Linux的文件系统比较庞大,所以笔者从pwd这一命令入手,在实现的过程中加深对文件系统的了解。
输入:man pwd
从指导文档中可以看到,pwd命令的作用是显示出当前所处位置,以路径的形式打印出来。
举例如下:
笔者首先输入pwd命令,显示出/home/lularible,说明我当前就处在该位置。
当笔者进入其中的一个子目录"bin"时,再次输入pwd命令,显示出/home/lularible/bin,这是显而易见的。
为了能够实现pwd命令,就需要先了解Linux文件系统的内部结构
一般而言,文件是存储在硬盘上的,那么将磁盘这一物理实体,进行逻辑划分和组织,就是进行抽象的过程。目的就是为了便于管理。
最朴素的管理手段就是,给硬盘的区域编号,按照编号从低到高给文件分配存储空间。当然,访问效率就可想而知了(当文件数量一多,访问效率将会及其低下)。所以那些系统开发人员就发挥出自己的聪明才智,对文件系统进行了巧妙的设计。
一整块磁盘,能存储大量的数据,统一管理起来不太方便。若能将它分而治之,则更加灵活。比如说windows系统里面的磁盘分区:C盘,D盘,E盘等等。每个分区都可以看作是一个独立的磁盘。
一个磁盘由一些磁性盘片组成。每个盘片的表面都被划分为很多同心圆,这些同心圆称作磁道,每一个磁道又进一步被划分为扇区,每个扇区可以存储一定字节的数据(如512字节)。扇区是磁盘上的基本存储单元,每次空间分配或者访问都是以一个扇区为最小单位。
为了存储不同类型的数据(文件内容、文件属性、目录),将磁盘块分为3个部分:
文件有内容和属性,内核将文件内容存放在数据区,文件属性存放在i-节点,文件名存放在目录。下图所示为创建一个文件的例子:
其中的几个主要操作为:
目录被抽象为一个包含i-节点号和文件名的表。
输入ls -ia可以查看当前目录包含的文件以及对应的i-节点号:
如代表当前目录的"."的i-节点号为1048600,代表上一级目录的".."的i-节点号为936372。再看一下根目录的组成:
其中"."和".."的i-节点号都是2,说明根目录的上级目录就是自己。另外,还可以看到存在i-节点号一样的文件(目录),这就是硬链接,将在后续的软、硬链接区别一节中叙述。
既然知道了目录的结构,那么就可以理一遍文件读取的过程了。举例来说:
输入cat userlist,表示读取userlist这个文件并显示。
step1.在目录中寻找文件名
文件名存储在目录文件中,内核在目录文件中寻找包含字符串"userlist"的记录。userlist所在的记录包含编号为47的i-节点。
step2.定位i-节点并读取内容
内核在文件系统中的i-节点区域找到i-节点47。i-节点包含数据块编号的列表。
step3.访问存储文件内容的数据块
在step2之后,即知道了数据块的位置和在磁盘中的顺序,就可以通过不停的调用read函数,使内核不断将字节从磁盘复制到内核缓冲区。
ps:读取权限的控制:内核根据文件名找到i-节点号,再根据i-节点号找到i-节点。在i-节点中,找到文件的权限位和用户ID,从而判断该用户是否具有读取权限。
每个文件对应一个i-节点,而每个i-节点大小是固定的,所以当文件内容需要占用很多磁盘块时,i-节点中的磁盘分布区可能不够用。这个时候,就需要采用多级分配的方式。一图说明问题:
其中,级数越多,访问磁盘时就越慢。因为需要按照每一级的指引,多次读取磁盘。
重复上述步骤,直到树顶。到树顶的判断依据:一个目录的"."和".."的i-节点号相同。
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<dirent.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
ino_t get_inode(char*);
void printpathto(ino_t);
void inum_to_name(ino_t,char*,int);
int main()
void printpathto(ino_t this_inode)
}
//获得i-节点号对应的文件名
void inum_to_name(ino_t inode_to_find,char* namebuf,int buflen)
while((direntp = readdir(dir_ptr)) != NULL)
}
fprintf(stderr,"error looking for inum %ld
",inode_to_find);
exit(1);
}
//获得文件名对应的i-节点号
ino_t get_inode(char* fname)
return info.st_ino;
}
当pwd01命令运行在装载文件系统中时,可能会出现与原版pwd不同的结果。(装载文件系统是指将它嵌入到已有的系统以获得某些支持,子树的根目录被嵌入到根文件系统的一个目录中,子树所在的目录被称为第二个系统的装载点。)依据pwd01命令的实现逻辑,当遇到当前目录和上级目录i-节点号一样时,就停止上溯,实际上可能只是到达了一个被装载的文件系统的顶端,而非整个文件系统的顶端。
假设多个文件名通过硬链接的方式指向同一个文件,那么它们拥有同一个i-节点,系统会记录链接数。如果删除其中的一个文件,则会将链接数减一,直到链接数为0时,才会真正删除文件。
而建立原文件的软链接,则其i-节点号与原文件的不同,并且链接数、修改时间和文件大小都不同于原始文件。若原始文件被删除或者位置变动或者被改名,那么软链接将指向空。这种思想有点类似于window中的快捷方式。
《Understanding Unix/Linux Programming A Guide to Theory and Practice》
欢迎大家转载本人的博客(需注明出处),本人另外还有一个个人博客网站:lularible的个人博客,欢迎前去浏览。