如何编程实现Linux中的pwd命令?

版权声明:本文为博主原创文章,未经博主允许不得转载。有事联系:[email protected] https://blog.csdn.net/qq_17550379/article/details/89416521

0x00 pwd命令是什么?

pwd用来显示到达当前目录的路径。

0x01 pwd命令是如何工作的?

我们知道一个目录下包含了两个特殊的目录...分别表示当前目录和上一个目录。我们可以先找到.inode节点编号,然后回到上一级目录,通过inode节点编号获取该目录的名字。

什么时候递归结束呢?当然是到达目录树的顶端了。当到达树的顶端的时候,...inode编号相同。

0x02 使用函数介绍

我们这里的操作主要有

0x0201 目录打开

所需要的头文件

#include <sys/types.h>
#include <dirent.h>

函数的格式

DIR *opendir(const char *name);

name指向我们需要打开的目录,返回的是一个DIR结构体指针(可以理解为“目录描述符”)。

0x0202 目录的读操作

所需要的头文件

#include <dirent.h>

函数的格式

struct dirent *readdir(DIR *dirp);

dirp指向我们的目录描述符,返回的是一个dirent结构体。

struct dirent {
    ino_t          d_ino;       /* Inode number */
    off_t          d_off;       /* Not an offset; see below */
    unsigned short d_reclen;    /* Length of this record */
    unsigned char  d_type;      /* Type of file; not supported
                                              by all filesystem types */
    char           d_name[256]; /* Null-terminated filename */
};

我们可以通过d_name获取目录中的文件信息。

扫描二维码关注公众号,回复: 5955041 查看本文章

0x0203 目录的关闭操作

所需的头文件

#include <sys/types.h>
#include <dirent.h>

函数原型

int closedir(DIR *dirp);

dirp指向我们的目录描述符,关闭的过程中出现错误返回-1

0x0204 获取文件信息

所需的头文件

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

函数原型

int stat(const char *pathname, struct stat *statbuf);

pathname指向我们需要获取的文件,stat是一个结构体包含文件信息。

struct stat {
    dev_t     st_dev;         /* ID of device containing file */
    ino_t     st_ino;         /* Inode number */
    mode_t    st_mode;        /* File type and mode */
    nlink_t   st_nlink;       /* Number of hard links */
    uid_t     st_uid;         /* User ID of owner */
    gid_t     st_gid;         /* Group ID of owner */
    dev_t     st_rdev;        /* Device ID (if special file) */
    off_t     st_size;        /* Total size, in bytes */
    blksize_t st_blksize;     /* Block size for filesystem I/O */
    blkcnt_t  st_blocks;      /* Number of 512B blocks allocated */

    /* Since Linux 2.6, the kernel supports nanosecond
                  precision for the following timestamp fields.
                  For the details before Linux 2.6, see NOTES. */

    struct timespec st_atim;  /* Time of last access */
    struct timespec st_mtim;  /* Time of last modification */
    struct timespec st_ctim;  /* Time of last status change */

#define st_atime st_atim.tv_sec      /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};

获取信息出错的话返回-1

0x0205 改变目录位置

所需的头文件

#include <unistd.h>

函数原型

int chdir(const char *path);

path指向我们需要改变的目录位置。

0x03 编写一个pwd

0x0301 第一版

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

void printpathto(ino_t);
void inum_to_name(ino_t inode_to_find, char *namebuf, int buflen);
ino_t get_inode(char *filename);

void printpathto(ino_t this_inode)
{
    ino_t my_inode;
    char its_name[BUFSIZ];
    if (get_inode("..") != this_inode)
    {
        chdir("..");
        inum_to_name(this_inode, its_name, BUFSIZ);
        my_inode = get_inode(".");
        printpathto(my_inode);
        printf("/%s", its_name);
    }
}

void inum_to_name(ino_t inode_to_find, char *namebuf, int buflen)
{
    DIR *dir_ptr;
    struct dirent *direntp;
    dir_ptr = opendir(".");
    if (dir_ptr == NULL)
    {
        perror(".");
        exit(1);
    }

    while ((direntp = readdir(dir_ptr)) != NULL)
    {
        if (direntp->d_ino == inode_to_find)
        {
            strncpy(namebuf, direntp->d_name, buflen);
            namebuf[buflen - 1] = '\0';
            closedir(dir_ptr);
            return;
        }
    }    
    fprintf(stderr, "error looking for inum %ld\n", inode_to_find);
    exit(1);
}

ino_t get_inode(char *filename)
{
    struct stat info;
    if (stat(filename, &info) == -1)
    {
        fprintf(stderr, "Cannot stat");
        perror(filename);
        exit(1);
    }
    return info.st_ino;
}
int main()
{
    printpathto(get_inode("."));
    putchar('\n');
    return 0;
}

我们查看我们的版本和实际版本的区别

功能实现的还不错,但是我们没有递归到home目录。是代码问题吗?不是,因为unix允许一个磁盘的存储由多棵树构成,每个磁盘或磁盘上的每个分区都包含一颗目录树。

我将该问题的其他语言版本添加到了我的GitHub Linux

如有问题,希望大家指出!!!

猜你喜欢

转载自blog.csdn.net/qq_17550379/article/details/89416521