使用C

时间:2015-10-04 16:31:45

标签: c unix directory posix

我将继续说这是Linux课程介绍的家庭作业。如果没有我自己的大量尝试,我不会发布它,并且看到我这个学期的远程学生,我无法进入校园进行辅导。我需要一些帮助来找出问题所在。

本质上,赋值要求我们创建一个与POSIX中的pwd命令具有相同基本功能的程序,以显示当前目录的绝对路径。我们将使用main和main三个函数。我们也不要使用getcwd命令。我将列出它们及其目的

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

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

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

    1. 创建一个字符数组,用作目录名称的缓冲区。
    2. 使用filename_to_inode获取父目录的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");
}

目前正在显示&#34; /./ MyName&#34; MyName是我在服务器上的个人命名目录。它是我运行程序的目录。当使用pwd时,我返回&#34; / home / MyName&#34;。我不确定下一步让绝对路径正确的是什么。

2 个答案:

答案 0 :(得分:1)

这是非常好的任务:)。 我阅读并尝试了您的代码,这几乎是正确的。有两个小问题导致了错误的行为。

第一期

display_path到达根文件夹时,您不需要调用inum_to_filename并打印文件夹的名称,因为您已经在上一次迭代中打印了路径的第一个文件夹。这可以防止您的代码显示&#34; ./"在路径的开头。 也就是说,if条件变为:

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

第二期

您没有在属性上初始化保存目录名称的缓冲区。这会导致显示随机值。要解决此问题,您只需使用memset将缓冲区的初始值设置为零。

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;

    memset(pathBuffer, 0, size_arg);

    while (counter != 1) {
     ...
    }

    closedir(dir_ptr);
}

完整代码工作:

#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;

    memset(pathBuffer, 0, size_arg);

    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;
} 

/*
  - Create an array of characters to use as a buffer for the name of the directory.
  - Get the inode for the parent directory using filename_to_inode.
  - If the parent inode is equal to the current inode, we have reached root and can return.
  - Otherwise, change to the parent directory and use inum_to_filename to find the name for 
    the inode that was passed into the function. Use the buffer from step 1 to store it.
  - Recursively call display_path to display the absolute path.
*/

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

    if (ino_src == ino_prnt) {
        return;
    } else {
        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");
}

输出:

ubuntu@ubuntu-VirtualBox:~/dev$ vi pwd.c 
ubuntu@ubuntu-VirtualBox:~/dev$ gcc pwd.c 
ubuntu@ubuntu-VirtualBox:~/dev$ ./a.out 
/home/ubuntu/dev
ubuntu@ubuntu-VirtualBox:~/dev$ pwd
/home/ubuntu/dev
ubuntu@ubuntu-VirtualBox:~/dev$ 

答案 1 :(得分:1)

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

此版本的代码包含:

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

  • 丢失变量count;它没有达到有用的目的。使用assign-and-test惯用法允许代码包含对readdir()的单个调用。

  • 使用strcpy()代替strcat()

  • 使用类型ino_t存储inode编号。使用size_t表示尺寸。

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

  • 请注意if (ino_src == ino_prnt)语句体中的代码用于根目录;在没有测试印刷品的情况下,它什么都不做。

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

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

  • main()

  • 中检测到root
  • 观察到此代码不直接适合重写函数,因为它在成功时将进程的当前目录更改为/

修订代码:

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

static void inum_to_filename(ino_t inode_arg, char *pathBuffer, size_t size_arg)
{
    assert(size_arg > 0);
    DIR *dir_ptr = opendir(".");
    if (dir_ptr == 0)
    {
        fprintf(stderr, "Failed to open directory '.' (%d: %s)\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }
    struct dirent *dirent_ptr;

    while ((dirent_ptr = readdir(dir_ptr)) != 0)
    {
        if (inode_arg == dirent_ptr->d_ino)
        {
            if (strlen(dirent_ptr->d_name) >= size_arg)
            {
                fprintf(stderr, "File name %s too long (%zu vs %zu max)\n",
                        dirent_ptr->d_name, strlen(dirent_ptr->d_name), size_arg);
                exit(EXIT_FAILURE);
            }
            strcpy(pathBuffer, dirent_ptr->d_name);
            break;
        }
    }

    closedir(dir_ptr);
}

static ino_t filename_to_inum(char *src)
{
    struct stat info;

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

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

    if (ino_src == ino_prnt)
    {
        // print for test
        inum_to_filename(ino_src, pathBuffer, bufSize);
        printf("%s", "(root): /\n");
    }
    else
    {
        // print for real
        if (chdir("..") != 0)
        {
            fprintf(stderr, "Failed to chdir to .. (%d: %s)\n",
                    errno, strerror(errno));
        }
        inum_to_filename(ino_src, pathBuffer, bufSize);
        display_path(ino_prnt);
        printf("/%s", pathBuffer);
    }
}

int main(void)
{
    ino_t c_ino = filename_to_inum(".");
    ino_t r_ino = filename_to_inum("/");
    if (r_ino == c_ino)
        putchar('/');
    else
        display_path(c_ino);
    printf("\n");
}

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

警告:在使用记忆棒的/Volumes/CRUZER/Sub-Directory工作时,这给了我一些悲伤。在扫描1时,它无法找到inode(/Volumes,这是令人惊讶的),而我没有找到原因。我的一个程序 - getpwd实现 - 工作正常;另一个是有一个不同的问题。我希望我能深究这一切。使用GCC 5.1.0在Mac OS X 10.10.5上进行测试。