Pwd命令实现

要实现pwd命令首先需要对linux基本文件系统有所了解才行。而文件系统的知识还是比较绕人的,所以一般理解起来会比较晦涩一些。另外,实现pwd命令还需要了解linux下基本的命令行操作。

首先明确的是pwd的功能,这个很简单,在命令行下输入pwd之后就会得到从根目录到当前目录的全路径。那么问题来了,在linux文件系统中什么是目录?我们又是通过什么方式对文件进行索引?通过什么方式在磁盘上村塾数据?怎么记录数据的基本信息?

首先是物理上来看,撇开固态硬盘不谈,我们现在只讨论基本的磁盘,每个磁盘有两个盘面,每个盘面上又有多个磁道,每个磁道上又可分为多个扇区。这里扇区一般就是我们对磁盘进行操作的基本单位,通常每个扇区的大小是512byte。所以通常我们的磁盘会拥有相当多个扇区,在这里我们给每个扇区进行编号(从0开始),这样我们就可以将磁盘的空间抽象成线性的空间,类似于数组一样的方式来索引。

linux中,将磁盘分成了三部分:

超级块:文件系统的第一块,该区域存放文件系统本身的结构和未使用的磁盘块的信息。

Inode存储区:这块区域存储的是inode,这里只需要知道inode相当于文件的存储位置索引表即可,除此之外,每个inode中还包含某些文件的基本信息。每一个文件无论大小都需要一个inode与之对应。

数据区:这里存放的是具体的数据,超过一个扇区大小的文件会分成多个扇区进行存储。另外尤其需要说明的是:目录也是一种文件,所以目录也是存储在数据区的。

到这里可能还是会比较乱,到底目录和inode是什么关系?ode和文件又是什么关系?

在计算机启动之前,所有文件的目录都在磁盘的数据区,为了能够快速定位到文件的位置,计算机将磁盘目录文件加载到内存中用以减少之后查找文件时的开销。目录文件有很多项组成,每项代表一个具体的文件,每项的内容是文件名到文件inode号的对应关系。也就是说我们打开文件时,首先在内存中检索目录,通过文件名定位目录项,然后取出文件的inode号。这时,我们就能够从磁盘中取出相应的inode结点,取出inode结点就可以得到文件数据具体在哪一个磁盘扇区了。

早期文件的目录和现在的inode结点是储存在一起的,但是当文件多了之后发现存储文件信息的结点也很大,没法放到内存,如果放到外存,每次查找文件都需要大量磁盘I/O,这样的时间开销是不可忍受的。于是现在将目录和inode结点分开。

当然,每个inode的大小也是有限的,尤其是小文件大文件共存的文件系统中,如果inode为每个扇区都分配扇区号直接索引的话,大文件的inode将会非常大,所以现在linuxinode都是通过多级索引的方式,比如有10个直接索引,1个一级索引,1个二级索引,1个三级索引。比如一级索引就是inode的第11个指针指向一个存有文件扇区号的文件,这个文件每个基本单位中都存有一个扇区号,这样就可以大大较少额外开销。

我们可以通过ls -ia命令还查看该目录下所有文件的inode号和文件名等基本信息。由于我们给ls的参数中包含a,所以可以看到文件名为‘.’‘..’的文件,他们分别表示当前目录和上一级目录。

说到上一级目录,就必须说说linux的树型目录结构,具体不再展开,但是我们如果从本级目录切换到上级目录的话可以直接通过命令行指令cd ..来完成。当我们在上一级目录下继续使用指令ls -ai查看的话,通过比较我们可以发现这时候看到的文件名为‘.’文件的inode号和之前查到的‘..’文件的inode号相同,这也就说明了二者是同一个文件。

我们知道,inode是唯一标识文件属性的单元,所以inode相同就表明二者是同一个文件。说到这里我们可以通过inode来探索硬链接和软链接的异同。首先说一下二者在linux下的指令:

硬链接:ln filename1 filename2

软链接(符号链接):ln -s filename1 filename2

当我们使用链接之后,无论是硬链接还是软链接,当对两个中任意一个文件进行操作时,打开另一个文件都会看到之前的操作痕迹。二者区别只有通过输出inode号才能看得出。当我们使用硬链接时,file1file2inode号相同,也就是可以理解成虽然在目录项里存在两项,但是两个文件虽然文件名不同,但都指向同一个inode结点。但是我们显示软链接两个文件的inode号时,发现二者的inode号并不相同。

在对链接文件进行过操作时,硬链接中两个文件,删除任意一个文件之后,另一个文件依旧会保存在计算机中,数据并不会受到损坏,只有所有链接文件都被删除之后才能彻底删除该文件。而软链接状态下,只要删除了其中被链接的原文件,再去打开链接文件时就会显示文件不存在。

经过学习了解到硬链接实质时两个不同文件名文件通向同一个inode,而软链接则是通过软链接存储下一条到原文件的全路径,这样当原文件被删除时,链接就失效了。不过软链接相比于硬链接还是有其优势的,硬链接必须是同一个文件系统下的文件,而软链接由于给出的是全路径,所以软链接可以链接到不相同的文件系统下的文件。

有了上述文件基本知识,我们先展示下pwd命令的代码实现:

#include <stdio.h>

#include <stdlib.h>

#include <dirent.h>

#include <sys/types.h>

#include <sys/stat.h>

 

ino_t get_inode(char *filename);

void printpathto(ino_t this_inode);

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

 

int main()

{

    printpathto(get_inode(“.”));

    printf(“\n”);

    return 0;

}

 

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;

}

 

void printpathto(ino_t this_inode)

{

    char its_name[BUFSIZ];

    if(this_inode != get_inode(“..”)){

       chdir(“..”);

       inum_to_name(this_inode, its_name, BUFSIZ);

       printf(“/%s”, its_name);

       printpathto(get_inode(“.”));

    }

}

 

void inum_to_name(ino_t inode_to_find, char *namebuf, int buflen)

{

    DIR *dir_ptr;

    struct dirent *direntp;

    if((dir_ptr = opendir(“.”)) == NULL){

       perror(“.”);

       exit(1);

    }

    while((direntp = readdir(dir_ptr)) != NULL){

       if(direntp->d_ino == inum_to_find){

           strcpy(namebuf, direntp->d_name, buflen);

           namebuf[buflen – 1] = ‘\0’;

           closedir(dir_ptr);

           return;

       }

    }

    fprintf(stderr, “error looking for the inum %d\n”, inum_to_find);

    exit(1);

}

Advertisements