0

Working on a modified/simpler version of Unix 'find' utility and as I'm printing out the files, my format is off.

Running:

./a.out mydir -print

The output should be similar to find, the following:

mydir
mydir/innerDir
mydir/innerDir/innerFile
mydir/testFile

However, my output is the following:

mydir/innerDir
innerFile/testFile

This is the function that I have that traverses the directory contents:

void printdir(char *dir, int depth) {
   DIR *dp;
   struct dirent *entry;
   struct stat statbuf;
   int spaces = depth * 4;
   char *path;

   if((dp = opendir(dir)) == NULL) {
      fprintf(stderr, "Error! Unable to open: %s\n", dir);
      exit(EXIT_FAILURE);
   }

   chdir(dir);
   while((entry = readdir(dp)) != NULL) {
      lstat(entry->d_name, & statbuf);
      if(S_ISDIR(statbuf.st_mode)) {
         if(strcasecmp(".", entry->d_name) == 0 ||
            strcasecmp("..", entry->d_name) == 0)
            continue;
         path = malloc(strlen(dir) + strlen(entry->d_name) + 2);
         strcpy(path, dir);
         strcat(path, "/");
         strcat(path, entry->d_name);
   //         printf("%*s|-- %s/\n", spaces, "", entry->d_name);
        printf("%s\n", path);
        printdir(entry->d_name, depth + 1);
      }
      else
   //         printf("%*s|-- %s\n", spaces, "", entry->d_name);
         printf("%s/", entry->d_name);
   }
   chdir("..");
   closedir(dp);
}

The commented lines above prints out similar output to Unix 'tree' utility. Any help on how to modify my printing to obtain 'find' output I listed above. Thank you!

George Rey
  • 13
  • 1
  • 1
    no need to use `strcasecmp` with `.` - its representation doesn't change with case. – Antti Haapala -- Слава Україні Mar 04 '17 at 18:09
  • You're right, I'll change that. – George Rey Mar 04 '17 at 18:13
  • Unclear what you're asking. – MD XF Mar 04 '17 at 18:15
  • anyway, there are 2 things - the last print doesn't even add a newline (it should, now it is making the mistakes less obvious), and check the string that you're recursing with (shouldn't you recurse with the full path instead of just the last component); then you'd notice that you don't need `chdir` at all... – Antti Haapala -- Слава Україні Mar 04 '17 at 18:15
  • After I changing the string I recurse with from the last component to the full path, I print an error of unable to open the directory because the concatenated string path is not seen as the name of the directory. (i.e. myDir/innerDir is not the name of the the directory, it should just be innerDir that I traverse. – George Rey Mar 04 '17 at 18:56
  • when a system function, like `opendir()` returns an error indication, it is best to call `perror()` so the reason the OS thinks the function failed is also output to stderr – user3629249 Mar 05 '17 at 13:17
  • when calling any of the heap memory allocation functions (malloc, calloc, realloc), always check (!=NULL) the returned value to assure the operation was successful. in the posted code there is a memory leak, because the pointer to the malloc'd memory is never passed to `free()` – user3629249 Mar 05 '17 at 13:22
  • one of the major problems with the posted code is that it only processes directory names, never file names. – user3629249 Mar 05 '17 at 13:27
  • this line: `printf("%s/", entry->d_name);` should be outputting a file name, not a directory name and there are other entries types besides directorys and normal files, like sym links, fifos, character devices, block devices, etc So the code should not assume that a entry is a regular file but rather check the type to know just what kind of file it actually is. – user3629249 Mar 05 '17 at 13:30
  • why the calls to `chdir()`? Nothing in the posted code requires that change nor is that changed directory make use of within the posted code – user3629249 Mar 05 '17 at 13:31

1 Answers1

0

Just a bad parameter at the recursion call, send the full path:

printdir(path, depth + 1);

and then for non directory entries, also print the full path:

printf("%s/%s\n", dir, entry->d_name);

----EDIT----

Remove all the calls to chdir as you generated the full path.

----EDIT-2----

lstat not called on the correct path, modify to:

 while((entry = readdir(dp)) != NULL) {
     path = malloc(strlen(dir) + strlen(entry->d_name) + 2);
     strcpy(path, dir);
     strcat(path, "/");
     strcat(path, entry->d_name);
     lstat(path, & statbuf);
Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
  • After I do that, it prints mydir/innerDir and then prints the error at the top of the function. I removed both calls to chdir and then it prints up to where it encounters the file, then it (obviously) says unable to open. But shouldn't it skip to the next entry? – George Rey Mar 04 '17 at 19:14
  • Now it prints the error when it encounters the file. – George Rey Mar 04 '17 at 19:22
  • As a follow-up question, how would I sort this output in lexicographic order using strcasecmp? – George Rey Mar 05 '17 at 21:42
  • read all entries of a given dir, sort them and do your tricks (print/recurse). – Jean-Baptiste Yunès Mar 06 '17 at 06:12