0

I've been trying for a few days now to write a code which will inspect all subfolders from C:\Users, and print their files, for example:

C:\Users\Public

files

C:\Users\Somefolder

files

Here is my code:

main() {

  DIR *dr,*dirp;
  struct dirent *dr_ent,*sec; 
  char *buf,*baf; 
  char get[50],x[50];     
  char folder[] = "C:\\Users\\"; 

  dr = opendir(folder);
  if (dr != NULL) 
   goto next;
  else return -1;

  next:
       while ((dr_ent = readdir(dr))!=NULL) {
             buf=dr_ent->d_name;
             strcpy(get,buf);
             if (strstr(get,".")==NULL && strstr(get,"..")==NULL) { 
                strcpy(x,folder);
                strcat(x,get); 
                printf("%s\n",x);
                continue;
                goto read;
                Sleep(300);
             }
       }
  read: 
       dirp = opendir(get);
       while ((sec = readdir(dirp))!=NULL) {
             baf=sec->d_name;
             printf("%s\n",baf);
             Sleep(300);
       }       


  system("PAUSE");
  return EXIT_SUCCESS;
  }`enter code here`

And in this case, only one folder was read. So am I actually making mistake by taking a variable from loop before so only one line was taken? And why is second label completely ignored by program? By the way, I'm sort of beginner in C programming, so don't get surprised by potential errors.

shodanex
  • 14,975
  • 11
  • 57
  • 91
SaleNs991
  • 11
  • 5
  • 2
    this kind of processing is usually handled by a recursive function. I.E. open once to get ptr to top directory (C:\users\), then if read item. if item is a directory, then call self (the recursion) to read the sub directory. else if item is file then process file. then read next item in directory, else if end of directory, return; the above algorithm is very flawed, but should give you the basic idea – user3629249 Nov 07 '14 at 15:46
  • 1
    There is always a lively debate about [Goto](http://stackoverflow.com/q/24451/3897316), but I doubt you will find anyone who would defend the way you used it. Try using `break` to exit your first `while` loop. – Degustaf Nov 07 '14 at 17:09
  • Have you looked at FindFirstFile/FindNextFile instead? There are many [examples](http://msdn.microsoft.com/en-us/library/windows/desktop/aa364418(v=vs.85).aspx) using those functions. – AndersK Nov 07 '14 at 20:55

1 Answers1

1

The second label is completely ignored because before the goto read; you use continue; which takes you to the next iteration of the while loop ignoring everything else after it.

Also in your code you don't check if the directory's entry is a file or a directory to handle it appropriately. What I mean is you should descend into a directory but you should print a file's name when you encounter one (as you do).

You can use a recursive function to avoid the use of goto, as goto is a bad practice.

void list_dir(char const* dirName)
{
    DIR* dir;

    if ((dir = opendir(dirName)) == NULL) {
        fprintf(stderr, "Cannot open directory '%s': %s\n", dirName, strerror(errno));
        exit(EXIT_FAILURE);
    }

    struct dirent* entry;

    // For every entry in the directory
    while ((entry = readdir(dir)) != NULL) {
        char* path;                         // path =  dirName/entryName
        int pathLength;                     // length of the path in chars
        struct stat entryStats;             // info of the entry
        char* entryName = entry->d_name;    // entry filename

        pathLength = strlen(dirName) + 1 + strlen(entryName);
        path = malloc((pathLength + 1) * sizeof(char));
        strcpy(path, dirName);
        strcat(path, "/");
        strcat(path, entryName);

        if (stat(path, &entryStats) == 0) {                
            // If the entry is a directory
            if (entryStats.st_mode & S_IFDIR) {
                // If the directory is not "." or ".." get its entries
                if (strcmp(entryName, ".") != 0 &&
                        strcmp(entryName, "..") != 0) {
                    list_dir(path);
                }
            }
            // If the entry is a file
            else if (entryStats.st_mode & S_IFREG) {
                printf("%s\n",path);
            }
        }
        free(path);
    }
    closedir(dir);
}

The above code works on Unix but on Windows you may have to change stat and struct stat to _stat and struct _stat if you are using Visual Studio.

KostasT
  • 113
  • 7
  • 1
    You can avoid the use of the cast with `path = malloc(pathLength + 1);` or `path = malloc((pathLength + 1) * sizeof *path);` as the cast is not needed. – chux - Reinstate Monica Nov 07 '14 at 16:19
  • @chux yes you are right :) I was just reading this in a top voted question. Should I edit my answer? – KostasT Nov 07 '14 at 16:25
  • 1) With `list_dir(path, fileList);`, do you mean `list_dir(path);`? Otherwise code compiles fine on my Windows machine. Maybe "on Windows you have to change ..." depends upon the _compiler_ in use and not OS. – chux - Reinstate Monica Nov 07 '14 at 17:42
  • Yes, I mean `list_dir(path);` thanks :) I usually use this function with a list of strings and forgot to change this one... I haven't tested it on Windows but if you did it's fine. After all I based my answer about `_stat` on a google search. I am changing this to "...on Windows you **may** have to change...". – KostasT Nov 07 '14 at 19:42
  • 1
    Certain it is not a Windows issue, but a Visual Studio issue. Other compilers on Windows, such as gcc work as is. – chux - Reinstate Monica Nov 07 '14 at 19:47