ClaudioDeLise
ClaudioDeLise

Reputation: 247

Trying to create code in C that print all directories starting from a root directory passed

EXAMPLE

Imagine I have a directory called Alpha and I want it as root.

  1. Alpha contains: some files and other two directories Beta and Gamma,
  2. Beta contains: some files and another directory called Theta,
  3. Gamma contains: some files,
  4. Theta contains: some files.

INPUT/OUTPUT

Using input as: ./myfind Alpha

I'll want as output:

Alpha
Beta
Gamma
Theta

(I don't care about the order).

MY CODE I tried with this code but it doesn't work. I'll want to do a recursive function to do it and i can't use POSIX.

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>

#if !defined(NAME_MAX)
#define NAME_MAX 256
#endif

int find(const char *passed_dir_name) {
    if (chdir(passed_dir_name) == -1) {
        perror("FATAL ERROR CHANGING DIRECTORY");
        return -1;
    }
    DIR *current_directory;
    if ((current_directory = opendir(".")) == NULL) {
        perror("FATAL ERROR OPENING CURRENT WORKING DIRECTORY");
        return -1;
    }
    struct dirent *dir;
    while ((dir = readdir(current_directory)) != NULL) {
        struct stat statbuf;
        stat(dir->d_name, &statbuf);
        if (S_ISDIR(statbuf.st_mode)) {
            fprintf(stdout, "%s\n", dir->d_name);
            find(dir->d_name);
        }
    }
    if (closedir(current_directory) == -1) {
        perror("FATAL ERROR CLOSING CURRENT WORKING DIRECTORY");
        exit(EXIT_FAILURE);
    }  
}

int main(int argc, char **argv) {
    if (argc != 2) {
        fprintf(stderr, "ERROR: Run as ./myfind directory\n");
        exit(EXIT_FAILURE);
    }
    const char *dir = argv[1];
    struct stat statbuf;
    stat(dir, &statbuf);
    if (!S_ISDIR(statbuf.st_mode)) {
        fprintf(stderr, "FATAL ERROR: %s IS NOT A DIRECTORY\n", dir);
        exit(EXIT_FAILURE);
    }
    find(dir);
    exit(EXIT_SUCCESS);
}

Upvotes: 1

Views: 64

Answers (1)

chqrlie
chqrlie

Reputation: 145277

The problem is you change the current directory when you recurse into a subdirectory but you do not change back to the parent directory when returning from the recursive function.

You could add a chdir(".."); at the end of the find function, but it might not work in all cases:

  • if a directory has more than 2 hard links
  • if you traverse symbolic links

It is preferable to compute the path of the destination directory for the recursive call to find() by concatenating the passed_dir_name, a / and dir->d_name and avoid changing the current directory.

Here is a modified version of find() for the simplistic approach:

int find(const char *passed_dir_name) {
    if (chdir(passed_dir_name) == -1) {
        perror("FATAL ERROR CHANGING DIRECTORY");
        return -1;
    }
    DIR *current_directory;
    if ((current_directory = opendir(".")) == NULL) {
        perror("FATAL ERROR OPENING CURRENT WORKING DIRECTORY");
        chdir("..");
        return -1;
    }
    struct dirent *dir;
    while ((dir = readdir(current_directory)) != NULL) {
        struct stat statbuf;
        stat(dir->d_name, &statbuf);
        if (S_ISDIR(statbuf.st_mode)) {
            fprintf(stdout, "%s\n", dir->d_name);
            find(dir->d_name);
        }
    }
    if (closedir(current_directory) == -1) {
        perror("FATAL ERROR CLOSING CURRENT WORKING DIRECTORY");
        exit(EXIT_FAILURE);
    }
    chdir("..");
}

Upvotes: 1

Related Questions