< 返回博客

文件系统笔记(《Linux&UNIX系统编程手册》)


文件系统笔记

inode

  1. 整个磁盘分为两个区域:元数(inode)的存放区域和实际数据存放区域;
  2. inode的大小固定,一般为128或256,实际数据存放的最小单位为“块“,大小一般为4KB;
  3. inode线性排列,线性顺序作为编号;
  4. 每个inode对应一个文件。inode内部首先存储了这个文件的元信息,比如文件类型、文件权限、文件属主、时间戳、文件大小、inode引用数等等,另外inode剩余的空间存储了许多个指针,这些指针指向存放文件实际数据的块(位于数据区域);
  5. 目录文件也占用一个inode,对应的数据区域存储有该目录下的子项及其对应的inode;
  6. inode内不存储文件名,文件名位于所在目录的目录文件的数据区内。

创建目录

创建一个目录时,实际做了3件事:在其“父目录文件”中增加一个条目;分配一个inode;再分配一个存储块,用来保存当前被创建目录包含的文件与子目录。被创建的“目录文件”中自动生成两个子目录的条目,名称分别是:“.”和“..”。前者与该目录具有相同的inode号码,因此是该目录的一个“硬链接”。后者的inode号码就是该目录的父目录的inode号码。所以,任何一个目录的”硬链接”总数,总是等于它的子目录总数(含隐藏目录)加2。即每个“子目录文件”中的“..”条目,加上它自身的“目录文件”中的“.”条目,再加上“父目录文件”中的对应该目录的条目。
—— 维基百科

目录不允许硬链接

不能手动对目录创建硬链接。

首先,硬链接是指两个文件名指向了同一个inode;同时,每个目录下都会存在...目录,分别指向目录自身和父目录;如果允许对目录创建硬链接,那么..目录应该指向哪里?比如/x/a/b//x/c/d/两个目录如果互为硬链接,那么该目录数据块中的..该指向/x/a/还是/x/b/?这就成了问题。

如果想要使目录达到类似硬链接的效果,可以使用“绑定挂载”功能,比如sudo mount dir1 dir2 --bind,这样dir2dir1的关系就类似硬链接,这样的关系甚至可以跨越文件系统。至于为什么这样不会出现上述问题,查看...的inode号就可以发现,绑定挂载之后,目录的...的指向并没有发生变化(因为挂载的目标目录必须已经存在,所以这两者已然存在),仍然和未挂载时的相同,也就不会出现指向不明确的问题。举个例子吧:如果已经存在目录a/b/c/,运行mount --bind a/ b/c/之后,目录c...仍然保持未挂载之前的样子。

文件空洞

在执行lseek的时候,如果seek的目标位于文件末尾之后,那么文件应该被加长,但是大多数文件系统的真实表现为:这些加长的空字节不占用实际空间,直到向此处填充数据时,才会为其分配空间。因此,可能会出现看到的文件大小比文件实际占用大小还要大的情况。这些占有文件大小但不占有磁盘的空间称作文件空洞。

许多下载软件在开始下载任务前,就向文件系统申请了目标大小的空间,这些空间利用了上述的文件空洞的原理,所以并不占用实际磁盘空间。

在Linux中,如果使用cp命令拷贝一个还有空洞的文件,得到的新文件也有相同的空洞;但是如果使用简单的read+write,比如cat a > b,得到的新文件是不含有空洞的,所有字节都实际占用空间。

可以使用du命令来查看一个文件或目录实际占有的磁盘区块数:

# 创建文件
echo test > holetest
# 查看文件大小
ls -l holetest
-rw-r--r-- 1 kai kai    5 May  4 01:59 holetest
# 查看占用区块大小,此处占用了一个块
du -h holetest
4.0K	holetest

# seek
dd if=/dev/urandom of=holetest seek=10 count=10 bs=2M
# 查看文件大小
ls -lh holetest
-rw-r--r-- 1 kai kai 40M May  4 02:00 holetest
# 查看占用区块大小
du -h holetest
21M	holetest

由上述测试可以看出,seek之后,文件大小比实际占有空间要大。

实际上,由于磁盘是按照块为单位使用的,所以只有在seek超过当前文件结尾所在的块时,才会产生文件空洞。

文件时间属性

存储在inode块中

  • atime(access time):上次访问时间
  • mtime(modification time):上次文件内容修改时间
  • ctime(change time):上次文件状态修改时间(inode内的信息)

目录权限控制

  • r,读权限:列出目录下的文件(读取文件系统中目录文件的数据块)。
  • w,写权限:创建和删除文件(修改文件系统中目录文件的数据块)。
  • x,可执行权限:访问目录中的文件(访问目录下的文件的inode)。

目录权限一些常见的情形

  1. 一般来说,删除文件时,无需拥有对文件自身的任何权限,只需要拥有对所在目录的w权限即可,但是例外情况为:如果该文件所在的目录设置了sticky位(chmod +t filename),那么只有当进程为该文件的属主的时候,才可以删除该文件;
  2. 创建文件时,需要同时拥有w和x权限,可以理解为创建文件时,需要创建一个文件的inode(对应x权限),同时要将其加入目录文件中(对应w权限);
  3. 拥有r权限,没有x权限,那么只能列出文件,但不能访问;
  4. 拥有x权限,没有r权限,那么可以通过文件名访问到目录下的文件,但不能列出目录下的文件。

特权进程的特例

特权进程默认拥有文件的所有权限(rwx),但是在Linux下,如果一个文件owner/group/other都没有x权限的话,即使是特权进程,也不能执行该文件。

关于文件的sticky位

sticky,中文意思为“粘”。在较老的Unix系统中,设置sticky位的可执行文件的文本段会被“粘”在交换区内,用以加快一些程序的运行速度。

但是在现代Unix系统中,内存管理要更加复杂和精确,该位没有了原有的功能,新的表现为:普通文件的sticky位会被忽略,而目录的sticky位则会使得目录下的项目只有owner或者root才可以删除和重命名。