To your study:
Code:
// test.c
// FIXME: For MSVC we need to use _findfirst/_findnext, instead of opendir/readdir/closedir.
// This code works on Cygwin, MSYS, Linux, but not on MSVC.
#define _GNU_SOURCE /* using glibc (asprintf) */
// if you don't have asprintf on your libc, it is easy to make one with vsnprintf/snprintf.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#ifdef _MSC_VER
#define realpath(P,RP) _fullpath((R),(RP),_MAX_PATH)
#endif
// opendir(), readdir() & closedir() not available on MSVC!
#include <dirent.h>
// Sizes for an arr with files and dirs:
#define ASIZE 4096
static void pout ( char **array )
{
while ( *array )
printf ( "\t%s\n", *array++ );
}
static void freelist ( char **array )
{
while ( *array )
free ( *array++ );
}
int filemapper ( char *directory )
{
static char *files[ASIZE];
static char *dirs[ASIZE];
// Dinamically allocated because we'll change it below.
char *path = strdup ( directory );
if ( ! path )
return 1;
DIR *dir = opendir ( path );
if ( ! dir )
return 1;
unsigned int fidx = 0, didx = 0;
struct dirent *entity;
// NOTE: entity points to a statically allocated buffer (must not free!).
entity = readdir ( dir );
while ( entity )
{
switch ( entity->d_type )
{
case DT_DIR:
// Discards "." and ".." references.
if ( ! strcmp ( entity->d_name, "." ) || ! strcmp ( entity->d_name, ".." ) )
break;
if ( didx < ASIZE )
{
char *tmpp;
if ( asprintf ( &tmpp, "%s/%s", path, entity->d_name ) >= 0 )
{
free ( path );
path = strdup ( tmpp );
dirs[didx++] = tmpp;
}
}
else
fputs ( "ERROR: Number of directory entries exausted.\n", stderr );
break;
// FIXED:
case DT_REG:
case DT_LNK:
if ( fidx < ASIZE )
{
if ( asprintf ( &files[fidx], "%s/%s", path, entity->d_name ) >= 0 )
{
printf ( "[%s] FILE : %s\n",
entity->d_type == DT_REG ? "\033[1;32mregular\033[m" : "\033[1;33msymlink\033[m",
files[fidx] );
fidx++;
}
}
else
fputs ( "ERROR: Number of file entries exausted.\n", stderr );
break;
// Ignores everything else.
default:
fprintf ( stderr, "Weird d_type (%hhu) at %s/%s\n",
entity->d_type, path, entity->d_name );
}
entity = readdir ( dir );
}
free ( path );
closedir ( dir );
printf ( "\nFILES:\n" );
pout ( files );
freelist ( files );
printf ( "\nDIRS:\n" );
pout ( dirs );
freelist ( dirs );
return 0;
}
int main ( int argc, char *argv[] )
{
struct stat st;
char path[PATH_MAX];
if ( argc != 2 )
{
fprintf( stderr, "Usage: %s <dir>\n", argv[0] );
return EXIT_FAILURE;
}
if ( stat( argv[1], &st ) )
{
fprintf( stderr, "Cannot stat '%s'.\n", argv[1] );
return EXIT_FAILURE;
}
if ( ! S_ISDIR( st.st_mode ) )
{
fprintf( stderr, "'%s' isn't a directory.\n", argv[1] );
return EXIT_FAILURE;
}
// Gets realpath only once (realpath is a glibc function!).
if ( ! realpath( argv[1], path ) )
{
fputs( "ERROR: Cannot get realpath.\n", stderr );
return EXIT_FAILURE;
}
printf( "Scanning '%s'\n", path );
if ( filemapper ( path ) )
{
fputs ( "ERRO!\n", stderr );
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}