I am writing my own version of the ls command. I use a 2 pass approach, where the first pass reads the files and displays them and the second traverses the dir again and performs a recursive call if the entry is a directory. The problem is, on the second pass the program thinks every entry it comes across after the first true directory is also a directory, so it ends up entering standard files as if they were directories. Does anybody know why?
Code:
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include "listdir.h"
void listDir (char *thisDir, int level)
{
int pass; // Used to mark what pass we are on.
struct stat statBuff; // Made static so it doesn't have to be re-allocated every call.
DIR *dir;
struct dirent *dirSlot;
char path [100]; // Can get large.
strcpy (path, thisDir);
dir = opendir ("."); // Open this dir.
if (dir == NULL)
{
perror ("Could not open directory!");
return; // Fail.
}
// Pass 1:
while ((dirSlot = readdir (dir)) != NULL) // Keep reading until this directory ends
{
stat (dirSlot->d_name, &statBuff); // Get details.
spaces (level); // Print spaces according to recursion level (give a slight indentation effect).
printEntryDetails (&statBuff, dirSlot->d_name);
}
rewinddir (dir);
// Pass 2:
while ((dirSlot = readdir (dir)) != NULL) // Keep reading until this directory ends:
{
stat (dirSlot->d_name, &statBuff); // Get details.
if (S_ISDIR (statBuff.st_mode)) // Determine directory...
{
if ((strcmp ("..", dirSlot->d_name) != 0) && (strcmp (".", dirSlot->d_name) != 0)) // ... but not ".." or "." !!!
{
strcat (path, "/"); // Concatenate the path and new dir together, along with '/'.
strcat (path, dirSlot->d_name);
spaces (level);
printf ("Entering directory %s - level %d:\n",path, level + 1);
chdir (dirSlot->d_name);
listDir (path, level + 1);
printf ("Leaving directory %s.\n", path);
}
}
}
closedir (dir);
}
void spaces (int number)
{
int i;
for (i = 0; i <= number; i++)
printf (" ");
}
void printPermissions (unsigned int st_mode_word)
{
int i;
unsigned int permMask = 0x0100;
char permChar [4] = { 'r', 'w', 'x' };
for (i = 0; i < 9; i++)
{
if (st_mode_word & permMask)
printf ("%c", permChar [i % 3]);
else
printf ("_");
permMask >>= 1;
}
printf (" "); // Not a tab as all strings of the permissions will be 9 chars in length.
}
void printEntryDetails (struct stat *statBuff, char *name)
{
if (S_ISDIR (statBuff->st_mode))
printf ("d");
else
printf ("_");
printPermissions (statBuff->st_mode);
printUserName (statBuff->st_uid);
printf ("%s\t", name);
if (strlen (name) < 4 )
printf ("\t\t"); // Extra tab.
printf ("%d\t", statBuff->st_size);
printf ("%d\t", statBuff->st_uid);
printf ("\n");
}
void printUserName (uid_t uid)
{
struct passwd *userDetails = getpwuid (uid);
if (userDetails != NULL)
printf ("%s\t", userDetails->pw_name);
}
Sorry about pasting code, but the attatchments option is gone.