使用 C 处理 POSIX 中的目录

Mon*_*bus 6 c unix directory posix

我会继续说这是 Linux 课程介绍的家庭作业。我不会在没有自己广泛尝试的情况下发布它,并且由于我本学期是远程学生,因此无法到校园进行辅导。我需要一些帮助来找出问题所在。

本质上,作业要求我们制作一个程序,该程序的基本功能与pwdPOSIX 中的命令相同,以显示当前目录的绝对路径。我们将与 main 一起使用三个函数。我们也不要使用该getcwd命令。我会列出他们和他们的目的

  • inum_to_filename: 接受三个参数(要转换的 inode 编号、指向写入名称的缓冲区的指针以及缓冲区的大小)。什么都不返回。它是为了:

    1. 打开当前目录,
    2. 读取第一个目录条目,
    3. 如果当前目录的 inode 与传入的 inode 匹配,则将 name 复制到缓冲区并返回。
    4. 否则读取下一个目录条目并重复上一步。
  • filename_to_inum: 接受一个参数(achar *表示文件名)。它返回相应的 inode 编号。它是为了:

    1. 将文件 inode 中的信息读取到内存中的结构中。
    2. 如果有任何问题,请显示相应的错误。
    3. 从结构中返回 inode 编号。
  • display_path: 接受一个参数(来自当前工作目录的 inode)。它什么都不返回。它是为了:

    1. 创建一个字符数组以用作目录名称的缓冲区。
    2. 使用 获取父目录的 inode filename_to_inode
    3. 如果父 inode 等于当前 inode,我们就达到了 root 并且可以返回。
    4. 否则,切换到父目录并使用它inum_to_filename来查找传递给函数的 inode 的名称。使用步骤 1 中的缓冲区来存储它。
    5. 递归调用display_path显示绝对路径。

这是代码:

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

void inum_to_filename (int inode_arg, char *pathBuffer, int size_arg) {
    DIR *dir_ptr = opendir(".");
    struct dirent *dirent_ptr = readdir(dir_ptr);
    int counter = 0;

    while (counter != 1) {
        if (inode_arg == dirent_ptr->d_ino) {

            strcat(pathBuffer, "/");
            strcat(pathBuffer, dirent_ptr->d_name);

            counter = counter + 1;
            return;

        } else {
            dirent_ptr = readdir(dir_ptr);
        }
    }

    closedir(dir_ptr);
}

int filename_to_inum (char *src) {
    int res = 0;
    struct stat info;
    int result = stat(src, &info);

    if (result != 0) {
        fprintf(stderr, "Cannot stat ");
        perror(src);
        exit(EXIT_FAILURE);
    } else {
        res = info.st_ino;
    }

    return res;
} 

void display_path (int ino_src) {
    int bufSize = 4096;
    char pathBuffer[bufSize];
    int ino_prnt = filename_to_inum("..");

    if (ino_src == ino_prnt) {
        //print for test
        inum_to_filename(ino_src, pathBuffer, bufSize);
        printf("%s", pathBuffer);
        return;
    } else {
        //print for test
        chdir("..");
        inum_to_filename(ino_src, pathBuffer, bufSize);
        display_path(ino_prnt);
        printf("%s", pathBuffer);
    }
}

int main (int argc, char *argv[]) {
    int c_ino = filename_to_inum(".");
    display_path(c_ino);
    printf("\n");
}
Run Code Online (Sandbox Code Playgroud)

截至目前,它显示“/./MyName”,其中 MyName 是我在服务器上的个人命名目录。这是我运行程序的目录。使用密码时,我返回“/home/MyName”。我不太确定我要获得正确绝对路径的下一步是什么。

Jon*_*ler 1

该代码主要设置为以正确的顺序一次打印一个名称,因此主要问题是使用strcat()而不是strcpy(). 此外,在开始时检测您何时位于根目录也很重要;如果不这样做,/.当当前目录是根目录时,您可能会得到类似的结果(具体取决于您协调打印的方式)。

\n\n

您的此版本的代码具有:

\n\n
    \n
  • 压缩了 中的循环inum_to_filename(),但还添加了错误报告。请记住,进程可以在它没有权限访问的目录中运行(它需要 setuid 程序,通常为 \xe2\x80\x94,尽管在程序启动后可以更改权限)。在这种情况下,可能无法打开..(或.)。

  • \n
  • 丢失变量count;它没有起到任何有用的作用。使用分配和测试习惯用法允许代码包含对readdir().

  • \n
  • 使用strcpy()而不是strcat().

  • \n
  • 使用 typeino_t来存储 inode 编号。用于size_t尺寸。

  • \n
  • 减少 中中间变量的数量filename_to_inum()

  • \n
  • 注意语句体中的代码if (ino_src == ino_prnt)是针对根目录的;如果没有测试打印,它什么也做不了。

  • \n
  • 请注意,零件中的打印else是操作的主要部分,而不仅仅是测试打印。

  • \n
  • 错误检查chdir("..");

  • \n
  • 检测 中的根main()

  • \n
  • 请注意,此代码不适合直接重写为函数,因为它会将进程的当前目录更改为/成功时的目录。

  • \n
\n\n

修改后的代码:

\n\n
#include <assert.h>\n#include <dirent.h>\n#include <errno.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/stat.h>\n#include <unistd.h>\n\nstatic void inum_to_filename(ino_t inode_arg, char *pathBuffer, size_t size_arg)\n{\n    assert(size_arg > 0);\n    DIR *dir_ptr = opendir(".");\n    if (dir_ptr == 0)\n    {\n        fprintf(stderr, "Failed to open directory \'.\' (%d: %s)\\n", errno, strerror(errno));\n        exit(EXIT_FAILURE);\n    }\n    struct dirent *dirent_ptr;\n\n    while ((dirent_ptr = readdir(dir_ptr)) != 0)\n    {\n        if (inode_arg == dirent_ptr->d_ino)\n        {\n            if (strlen(dirent_ptr->d_name) >= size_arg)\n            {\n                fprintf(stderr, "File name %s too long (%zu vs %zu max)\\n",\n                        dirent_ptr->d_name, strlen(dirent_ptr->d_name), size_arg);\n                exit(EXIT_FAILURE);\n            }\n            strcpy(pathBuffer, dirent_ptr->d_name);\n            break;\n        }\n    }\n\n    closedir(dir_ptr);\n}\n\nstatic ino_t filename_to_inum(char *src)\n{\n    struct stat info;\n\n    if (stat(src, &info) != 0)\n    {\n        fprintf(stderr, "Cannot stat ");\n        perror(src);\n        exit(EXIT_FAILURE);\n    }\n    return info.st_ino;\n}\n\nstatic void display_path(ino_t ino_src)\n{\n    size_t bufSize = 4096;\n    char pathBuffer[bufSize];\n    ino_t ino_prnt = filename_to_inum("..");\n\n    if (ino_src == ino_prnt)\n    {\n        // print for test\n        inum_to_filename(ino_src, pathBuffer, bufSize);\n        printf("%s", "(root): /\\n");\n    }\n    else\n    {\n        // print for real\n        if (chdir("..") != 0)\n        {\n            fprintf(stderr, "Failed to chdir to .. (%d: %s)\\n",\n                    errno, strerror(errno));\n        }\n        inum_to_filename(ino_src, pathBuffer, bufSize);\n        display_path(ino_prnt);\n        printf("/%s", pathBuffer);\n    }\n}\n\nint main(void)\n{\n    ino_t c_ino = filename_to_inum(".");\n    ino_t r_ino = filename_to_inum("/");\n    if (r_ino == c_ino)\n        putchar(\'/\');\n    else\n        display_path(c_ino);\n    printf("\\n");\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

毫无疑问还有其他方法可以解决这个问题。

\n\n

警告:这让我在使用/Volumes/CRUZER/Sub-Directory记忆棒工作时感到有些悲伤。扫描时它找不到索引节点(1令人惊讶)/Volumes,我还没有弄清楚原因。我的程序之一 \xe2\x80\x94 的getpwd实现 \xe2\x80\x94 工作正常;另一个有不同的问题。我希望我能查出这一切的真相。在 Mac OS X 10.10.5 上使用 GCC 5.1.0 进行测试。

\n