Insight into something.
////////////////////////////////////////////////////////////////////////////////
/**
* @file ls_01.c
* @brief Write a program in C that is similar to the ls command.
*
* @title ls 01
* @author Nicholas Guthrie
* @web http//nickguthrie.com
* @created February 4, 2013
*
* Compile with: gcc -g -Wall -o ./ls_01 ls_01.c
*/
////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------ :Libraries:
// _ _ _ _
// | | (_) |__ _ _ __ _ _ _(_)___ ___
// | |__| | '_ \ '_/ _` | '_| / -_|_-<
// |____|_|_.__/_| \__,_|_| |_\___/__/
//
// -----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <limits.h> /* limits.h defines "PATH_MAX". */
#include <sys/stat.h>
//----------------------------------------------------------------- :Prototypes:
// ___ _ _
// | _ \_ _ ___| |_ ___| |_ _ _ _ __ ___ ___
// | _/ '_/ _ \ _/ _ \ _| || | '_ \/ -_|_-<
// |_| |_| \___/\__\___/\__|\_, | .__/\___/__/
// |__/|_|
//
//-----------------------------------------------------------------------------
int o_dir(char * dir, int level, char * f_name);
void get_permissions (char *mode, unsigned int imode);
/**----------------------------------------------------------------------- :Main:
// __ __ _
// | \/ |__ _(_)_ _
// | |\/| / _` | | ' \
// |_| |_\__,_|_|_||_|
//
-----------------------------------------------------------------------------*/
int main( int argc, char *argv[] )
{
char d_name[3] = "."; /* initial directory */
//Debug - cleaner way of formatting pointers?
char * p_name = d_name;
char * pf_name = NULL;
//Obtain Argument
if ( argc == 2 ) /* argc should be 2 for correct execution */
{
//printf( "Argument is %s\n", argv[1] );
pf_name = argv[1];
//strcpy(f_name, argv[1]);
}
// Error Checking for > 1 Argument
if ( argc > 2 )
{
printf( "Usage: %s (optional)filename\nExiting.\n", argv[0] );
return -1;
}
o_dir(p_name, 0, pf_name);
return EXIT_SUCCESS;
}
//------------------------------------------------------------------ :Functions:
// ___ _ _
// | __| _ _ _ __| |_(_)___ _ _ ___
// | _| || | ' \/ _| _| / _ \ ' \(_-<
// |_| \_,_|_||_\__|\__|_\___/_||_/__/
//
//
//-----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/**
* @brief Recursively search for directories.
* @param[in] c_dir The name of the directory to search.
* @param[in] level Used to keep track of spacing for sub-directories.
* @return EXIT_SUCCESS if successful
*/
////////////////////////////////////////////////////////////////////////////////
int o_dir( char * c_dir, int level, char * f_name )
{
DIR * dir = opendir(c_dir);
struct dirent * file;
while ( ( file = readdir( dir ) ) != NULL )
{
// check for dir open failure
if ( dir == NULL )
{
perror( "opendir() failed\n" );
return EXIT_FAILURE;
}
// Read File Info
struct stat buf;
int rc = lstat( file->d_name, &buf );
// check for . or .. as first char in name
if ( (strcmp (file->d_name, "..") != 0 && strcmp (file->d_name, ".") != 0) &&
( S_ISDIR(buf.st_mode) || ( S_ISREG( buf.st_mode )
&& (f_name == NULL || strcmp(f_name, file->d_name) == 0))))
{
//Print Directory Level Spacing
int i;
for(i=0; i<level*4;i++)
printf(" ");
//@DEBUG - What is this used for?
if ( rc < 0 )
{
/* perror( "lstat() failed\n" ); */
/* return EXIT_FAILURE; */
}
else
{
printf( "%s ", file->d_name);
if ( S_ISDIR( buf.st_mode ) )
{
char rwx_perms[12];
get_permissions (rwx_perms, buf.st_mode);
printf( "(subdirectory) [%s]\n", rwx_perms);
// Recursive Section
int path_length;
char path[PATH_MAX];
path_length = snprintf (path, PATH_MAX,
"%s/%s", c_dir, file->d_name);
//Check Path Length
if (path_length >= PATH_MAX)
{
fprintf (stderr, "Path length has got too long.\n");
exit (EXIT_FAILURE);
}
//Recursively call with the new path.
chdir(file->d_name);
o_dir (".", level + 1, f_name);
chdir("..");
}
// Regular File
else if ( S_ISREG(buf.st_mode) )
{
//Determine rwx_perms
char rwx_perms[12];
get_permissions (rwx_perms, buf.st_mode);
printf( "(%d bytes) [%s]\n", (int) buf.st_size, rwx_perms);
}
// Sub-Directory
// System Link
/*else if ( S_ISLNK( buf.st_mode ) )
{
printf( "[symbolic link]\n" );
}*/
// Unknown File
/* else */
/* { */
/* //Do Nothing */
/* } */
}
}
}
closedir( dir );
return EXIT_SUCCESS;
}
////////////////////////////////////////////////////////////////////////////////
/**
* @brief Given the octal permission of a file, determine rwx human readable
* @param[out] mode Stores the string of rwx permissions.
* @param[in] imode
* @return void. Results stored in *mode.
*/
////////////////////////////////////////////////////////////////////////////////
void get_permissions (char *mode, unsigned int imode )
{
int i[16];
int count=0;
int rem;
memset( i,0,16 );
memset( mode,'\0',11 );
/*Convert to binary*/
while ( imode>0 )
{
rem=imode%2;
imode/=2;
i[count]=rem;
count++;
}
/*End Binary Coversion*/
count=0;
/*Start Processing bits*/
int j;
for ( j=15;j>=0;j-- )
{
switch ( j )
{
case 15 : if ( i[j]==1 )
{
mode[count]='-';
count++;
} else {
mode[count]='d';
count++;
}
break;
case 8 : if ( i[j]==0 )
{
mode[count]='-';
count++;
} else {
mode[count]='r';
count++;
}
break;
case 7 : if ( i[j]==0 )
{
mode[count]='-';
count++;
} else {
mode[count]='w';
count++;
}
break;
case 6 : if ( i[j]==0 )
{
mode[count]='-';
count++;
} else {
mode[count]='x';
count++;
}
break;
case 5 : if ( i[j]==0 )
{
mode[count]='-';
count++;
} else {
mode[count]='r';
count++;
}
break;
case 4 : if ( i[j]==0 )
{
mode[count]='-';
count++;
} else {
mode[count]='w';
count++;
}
break;
case 3 : if ( i[j]==0 )
{
mode[count]='-';
count++;
} else {
mode[count]='x';
count++;
}
break;
case 2 : if ( i[j]==0 )
{
mode[count]='-';
count++;
} else {
mode[count]='r';
count++;
}
break;
case 1 : if ( i[j]==0 )
{
mode[count]='-';
count++;
} else {
mode[count]='w';
count++;
}
break;
case 0 : if ( i[j]==0 )
{
mode[count]='-';
count++;
} else {
mode[count]='x';
count++;
}
break;
}
}
}