Naveen Mathew
Naveen Mathew

Reputation: 103

Weird bug with routine to list files recursively

Can anybody spot what I am missing here? This block of code is supposed to recursively access directories and store the directory path and the path of the files in it. It will fprintf() a true if the file is a directory and a false if the file is not a directory. Weird part is that the printf routine for fileName works fine but when its time to fprintf fileName to a file, it just prints a newline where its supposed to print fileName.

/* List the files in "dir_name". */
static void listDir(const char *dirName)
{
DIR *dir;

/* 
 * Open the directory specified by "dirName". 
 */

dir = opendir(dirName);

/* 
 * Check it was opened. 
 */
if (!dir) {
    fprintf(stderr, "Cannot open directory '%s': %s\n",
            dirName, strerror(errno));
    exit(EXIT_FAILURE);
}
while (1) {
    struct dirent *entry;
    const char *dir_name;

    /* 
     * "Readdir" gets subsequent entries from "d". 
     */
    entry = readdir(dir);
    if (!entry) {
        /* 
         * There are no more entries in this directory, so break out of the while loop. 
         */
        break;
    }
    dir_name = entry->d_name;
    char fileName[PATH_MAX];
            // Assign fileName to path if the file is not a directory
    if (entry->d_type != DT_DIR) {
        if (strcmp(dirName, "/") != 0) {
            snprintf(fileName, PATH_MAX,
                                   "%s/%s", dirName, dir_name);
        } else {
            snprintf(fileName, PATH_MAX,
                                   "%s%s", dirName, dir_name);
        }
    }
    /* Access directory and leave out /. and /.. in the process
     */

    if (entry->d_type == DT_DIR) {

        /* 
         * Check that the directory is not "d" or d's parent. 
         */

        if (strcmp(dir_name, "..") != 0 && strcmp(dir_name, ".") != 0) {
            int path_length;
            char path[PATH_MAX], indexPath[PATH_MAX];
            if (strcmp(dirName, "/") != 0) {
                path_length = snprintf(path, PATH_MAX,
                                       "%s/%s", dirName, dir_name);
            } else {
                path_length = snprintf(path, PATH_MAX,
                                       "%s%s", dirName, dir_name);
            }
            strcpy(indexPath, path);
            strcat(indexPath, "/masterIndex.db");
            FILE *fp;
            if ((fp = fopen(indexPath, "a")) == NULL) {
                printf("Cannot open file\n");
                return;
            }

            printf("File: %s\n      (TRUE)\n", path);
            printf("File: %s\n      (FALSE)\n", fileName); // This routine prints fileName correctly
            fprintf(fp, "%s\n", path);
            fprintf(fp, "%s\n", "true");
            fprintf(fp, "%s\n", fileName); // This routine prints a newline where fileName is supposed to be
            fprintf(fp, "%s\n", "false");
            fclose(fp);

            // Activate this for screw ups
            /*
            char command[PATH_MAX];
            strcpy(command, "cd ");
            strcat(command, path);
            strcat(command, " && rm abc *.finderDB .DS_Store");
            printf("%s\n", command);
            system(command);*/

            if (path_length >= PATH_MAX) {
                fprintf(stderr, "Path length has gotten too long.\n");
                exit(EXIT_FAILURE);
            }
            /* 
             * Recursively call "list_dir" with the new path. 
             */
            listDir(path);
        }
    }
}
/* 
 * After going through all the entries, close the directory. 
 */
if (closedir(dir)) {
    fprintf(stderr, "Could not close '%s': %s\n",
            dirName, strerror(errno));
    exit(EXIT_FAILURE);
}
}

Upvotes: 1

Views: 265

Answers (3)

Naveen Mathew
Naveen Mathew

Reputation: 103

Here's the working code I managed to fix. Still have no idea what the bug was but this should work on POSIX systems. Not sure about Windows. Thanks to alk for the initialization suggestion, xtof for chidir() (which i have still not implemented yet) and twalberg for explaining what chdir() does.

/* List the files in "dir_name". */
static void listDir(const char *dirName)
{
DIR *dir;

/* 
 * Open the directory specified by "dirName". 
 */

dir = opendir(dirName);

/* 
 * Check it was opened. 
 */
if (!dir) {
    fprintf(stderr, "Cannot open directory '%s': %s\n",
            dirName, strerror(errno));
    exit(EXIT_FAILURE);
}
while (1) {
    struct dirent *entry;
    const char *dir_name;

    /* 
     * "Readdir" gets subsequent entries from "d". 
     */
    entry = readdir(dir);
    if (!entry) {
        /* 
         * There are no more entries in this directory, so break out of the while loop. 
         */
        break;
    }
    dir_name = entry->d_name;

    if (entry->d_type != DT_DIR) {
        char fileName[PATH_MAX] = "", indexPath[PATH_MAX] = "";
        if (strcmp(dirName, "/") != 0) {
            sprintf(fileName, "%s/%s", dirName, dir_name);
        } else {
            sprintf(fileName, "%s%s", dirName, dir_name);
        }

        strcpy(indexPath, dirName);
        strcat(indexPath, "/masterIndex.db");

        // We don't want to include masterIndex.db in the index list right?
        if (strcmp(indexPath, fileName) != 0) {

            FILE *fp;
            fp = fopen(indexPath, "a");
            if (fp == NULL) {
                printf("Cannot open file\n");
            }

            printf("File: %s\n      (FALSE)\n", fileName);
            fprintf(fp, "%s\n", fileName);
            fprintf(fp, "%s\n", "false");
            fclose(fp);
        }
    }
    /* 
     * See if "entry" is a subdirectory of "dir". 
     */

    if (entry->d_type == DT_DIR) {

        /* 
         * Check that the directory is not "d" or d's parent. 
         */

        if (strcmp(dir_name, "..") != 0 && strcmp(dir_name, ".") != 0
            && strcmp(dir_name, "tmp") != 0
            && strcmp(dir_name, "Jarvis") != 0) {
            int path_length;
            char path[PATH_MAX] = "", indexPath[PATH_MAX] = "";

            if (strcmp(dirName, "/") != 0) {
                path_length = sprintf(path,
                                      "%s/%s", dirName, dir_name);
            } else {
                path_length = sprintf(path, "%s%s", dirName, dir_name);
            }
            strcpy(indexPath, path);
            strcat(indexPath, "/masterIndex.db");
            FILE *fp;
            fp = fopen(indexPath, "a");
            if (fp == NULL) {
                printf("Cannot open file\n");
            }

            printf("File: %s\n      (TRUE)\n", path);
            fprintf(fp, "%s\n", path);
            fprintf(fp, "%s\n", "true");
            fclose(fp);

            // Activate this for screw ups
            /*
               char command[PATH_MAX];
               strcpy(command, "cd ");
               strcat(command, path);
               strcat(command, " && rm abc *.finderDB .DS_Store");
               printf("%s\n", command);
               system(command); */

            if (path_length >= PATH_MAX) {
                fprintf(stderr, "Path length has gotten too long.\n");
                exit(EXIT_FAILURE);
            }
            /* 
             * Recursively call "list_dir" with the new path. 
             */
            listDir(path);
        }
    }
}
/* 
 * After going through all the entries, close the directory. 
 */
if (closedir(dir)) {
    fprintf(stderr, "Could not close '%s': %s\n",
            dirName, strerror(errno));
    exit(EXIT_FAILURE);
}
}

Upvotes: 0

alk
alk

Reputation: 70971

Your are missing to initialise fileName here:

 char fileName[PATH_MAX];

Mod the line like this:

 char fileName[PATH_MAX] = "";

Not doing so could lead to access the unintialised variable, which is Undefined Behaviour and could lead to anything more or less rational or irrational.

Upvotes: 1

xtof pernod
xtof pernod

Reputation: 883

system("cd any_path") won't have any effect on the calling process; use chdir() instead..

Upvotes: 1

Related Questions