尝试在 C 中创建代码,打印从传递的根目录开始的所有目录

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

示例

假设我有一个名为 Alpha 的目录,我想将其作为根目录。

  1. Alpha 包含:一些文件和其他两个目录 Beta 和 Gamma,
  2. Beta 包含:一些文件和另一个名为 Theta 的目录,
  3. Gamma 包含:一些文件,
  4. Theta 包含:一些文件。

INPUT/OUTPUT

使用输入为:./myfind Alpha

我想要输出:

Alpha
Beta
Gamma
Theta

(我不关心顺序)。

我的代码 我尝试使用此代码,但它不起作用。我想做一个递归函数来做它,我不能使用 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);
}

问题是递归到子目录时更改了当前目录,但从递归函数返回时没有更改回父目录。

您可以在 find 函数的末尾添加一个 chdir("..");,但它可能不适用于所有情况:

  • 如果一个目录有超过 2 个硬链接
  • 如果你遍历符号链接

最好通过连接 passed_dir_name/dir->d_name 来计算对 find() 的递归调用的目标目录路径,并避免更改当前目录。

这里是 find() 的修改版本,用于简化方法:

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("..");
}