硬链接与软链接是 Linux 文件系统中的一个重要概念,其涉及文件系统中的索引节点 (index node 又称 inode),而索引节点对象是 Linux 虚拟文件系统 (VFS) 的四个基本概念之一。
不过讨论链接之前,有必要复习一下Linux的文件系统和文件。提起文件,我们最先想到的就是文件名和文件内容。没错,这的确是我们(人类)最关心的两个属性,但是在计算机看来,除此之外还需要加入更多的属性才能实现有效的文件管理。这些属性从计算机的角度可以分为两大类:元数据和用户数据,计算机关心的是前者,因为元数据是实现管理的关键,而这个文件里面到底存了哪些内容却并不关心(准确的说是文件系统并不关心,但不代表其他组件不关心);用户数据是人类关心的焦点,但是人类并不关心元数据——那是计算机的事。有趣的是,文件名并不在元数据的范围之内,计算机并不关心文件名是什么,后面将会解释。
在这篇文章中我曾仔细的介绍过磁盘与文件系统,但是太罗嗦了,这里说一下重点:
+ 建立文件系统的时候,至少要有两个部分:inode table和data blocks,前者存放inode,后者就是文件内容存放区。当然还有其他重要部分。
+ 文件系统将一个文件的所有信息分成元数据和用户数据分别存放在不同的位置。存放元数据的是inode,而用户数据存放在data blocks中。inode中有很多重要数据,但是最重要的恐怕就是用户数据存放在哪个block。普通文件的用户数据不必多说,但是目录文件的data block到底都是些什么?就是这个目录下所有文件的名字以及对应的inode,类似于一个映射表。
+ 在操作一个文件的时候,至少会提供两个基本参数:路径名和文件名。路径名就是目录树,树根就是根目录“/”。文件系统首先会找到文件所在目录的inode(绝对路径我猜是从根目录开始递归查询的,相对路径可能有更快的方法),从而找到目录内容在的block,从中查找与文件名对应的inode,然后才能从这个inode中找到文件内容所在的block。可见,文件名并不是文件系统定位文件的唯一标识,inode才是。文件名是给人类看的。
然后什么才是链接呢?从面我们知道,文件内容的位置信息存放在它的inode中,且这个inode是唯一的。而要寻找这个inode,只能去其父目录的的data block中,这里记录了文件名和对应inode的映射。而映射可以是多对一的,于是存在这么一种情况,有两个不同的文件名指向同一个inode,当然这种映射不必存在于同一张映射表中,比如/etc下有一个文件叫test1,那么/etc的data block中必然记录了test1和其inode的映射;而在/user中有个文件叫test2,且在/user的data block中,与test2对应的是同一个inode,这种情况下,test1就是test2的硬链接,反过来也成立,反正它们指向同一个inode然后同样的data block。可见,创建一个硬链接其实就是在目录的data block的映射表中增加一项,且增加项的inode是已经存在的。硬链接只是增加了目录的data block的内容,没有增加inode的总使用量,也没有增加data block的总使用量,形象的说只是为原来的文件增加了一个新的入口。
那么软连接的原理又是什么呢?软连接是在当前目录下新建一个文件,拥有全新的inode和data block,然而文件的用户数据,也就是data block中的内容是另一个文件的文件名和路径等信息。
可以对比一下复制文件,复制一个文件到另一个目录,不仅要给新文件分配新的inode和data block,还要把源文件的内容copy到新文件中。
通过ls -l命令可以查看一个目录下所有文件的链接计数情况:
m@sys:~/program/C_codes/tools/calculators$ ll
总用量 20
drwxrwxr-x 2 m m 4096 5月 4 00:16 ./
drwxrwxr-x 3 m m 4096 4月 24 11:24 ../
-rw-rw-r-- 1 m m 340 4月 24 14:10 calculator.l
-rw-rw-r-- 1 m m 673 5月 4 00:16 calculator.y
-rw-rw-r-- 1 m m 367 4月 24 14:20 Makefile
我们看到,对于普通文件,其链接计数都是1(假如不存在其他硬链接),而有“.”表示的目录本身的链接计数却是2。实际上,在当前目录下每新建一个子目录,都会使当前目录的链接计数增加1。但是一个子目录也没有时为什么是2呢?首先看看1是怎么来的:显然,每个文件都有父目录(根目录似乎也有。。),那么父目录的data block中肯定有这个文件的一个映射,这就是1的来源;那为什么每个目录文件的链接计数至少是2?因为除了父目录中的映射,代表当前的“.”也是一次引用,从上面的结果中看以看出,这个“.”应该是记录在该目录的data block中,所以至少链接数是2。我们还看到,每个子目录中还添加了符号“..”,代表上层目录,所以每增加一个子目录,父目录的链接计数都会增加1。
使用ln命令可以创建链接,ln是最常用的命令,但不是唯一的,cp命令也可以创建链接,这个以后再说。
其使用格式为:ln 源文件名 链接名
要注意添加路径。不加选项时,创建的就是硬链接,像创建软连接的话,需要加上选项-s。这是ln最基本的用法,更多的请参考man ln。
软硬链接的一些注意事项:
1. 硬链接不可以对目录使用;
2. 硬链接只能对已经存在的文件使用;
3. 软连接可以对不存在的文件使用;
4. 源文件移动后,软连接失效;
5. 创建软连接可以使用相对路径,但链接文件本身移动后链接会失效。