Linux 之 符号链接与硬链接
链接简单理解就是,添加一个对文件/文件夹的访问副本,更方便平时的一些操作。类比Windows的快捷方式。
简单先看一下符号链接与硬链接的生成与使用。
生成符号链接与硬链接
-
创建符号链接:ln -s target_file link_file
-
创建硬链接:ln target_file link_file
演示:
创建文件的符号链接
$ ln -s file1 file_symlink
创建文件的硬链接
$ ln file1 file_hardlink
创建文件夹的符号链接
$ ln -s link_test_dir dir_symlink
创建文件夹的硬链接:创建失败
$ ln -s link_test_dir dir_hardlink
ln: link_test_dir: hard link not allowed for directory
从上面的流程和截图的观察中,可以总结几点:
- 在表现形式上(ls -alh查看):
- 符号链接表现为指向被链接文件的形式,硬链接表现为单独的文件。
- 符号链接权限为
lrwxrwxrwx.
,硬链接权限与源文件一致 - 硬链接大小与源文件一致,符号链接大小为被链接文件的路径字符长度。
- 硬链接不允许创建给目录,符号链接可以。
- 访问文件:都是源文件的值
做一些操作,再观察现象:
-
修改权限
-
修改硬链接权限
-
修改软连接权限
-
-
修改属主
-
修改硬链接属主
-
修改软连接权限
-
-
删除源文件后,再访问符号链接和硬链接
总结以上情况,我们可以再补充一些符号链接跟硬链接的特点:
- 访问符号链接和硬链接实际都是访问被链接文件;
- 硬链接修改权限/属主时,源文件跟着一起变;符号链接修改权限/属主时,链接文件未变化,实际变化的是源文件,且硬链接文件的属性跟着一起变动;
- 源文件被删除时,硬链接文件仍然可以访问,且与源文件一致;访问符号链接文件时会找不到对象。
按上面的操作,基本可以运用符号链接和软连接。但是留有一些疑问:
- 为什么源文件删除了,硬链接还能正常访问,而符号链接却失效了?
- 为什么修改符号链接的属主/权限,符号链接的属主/权限却未变动,变动的是源文件?
- 为什么硬链接的所有文件属性都跟源文件保持一致?
- 为什么硬链接不能链接给目录?
要解答这些问题,可以先延伸看下Linux文件系统的管理模式。
Linux文件管理
当我们使用Linux文件系统时,文件系统通常会将文件的两部分数据分别放在不同的区块中:权限与属性放置在inode中,实际数据放置在data block中。另外,还有一个超级区块 (superblock) 会记录整个文件系统的整体信息,包括 inode 与 block 的总量、使用量、剩余量等。
每个 inode 与 block 都有编号,这三个数据:
- superblock:记录所在 filesystem 的整体信息,包括inode/block的总量、使用量、剩余量,以及文件系统的格式与相关信息等;
- inode:记录文件的属性,一个文件占用一个inode,同时记录此文件的数据所在的 block号码;
- block:实际记录文件的内容,若文件太大时,会占用多个 block 。
这种数据存取的方法我们称为索引式文件系统(indexed allocation)
当我们在 Linux 下的文件系统创建一个目录时,文件系统会分配一个 inode 与至少一块 block给该目录。其中,inode 记录该目录的相关权限与属性,并可记录分配到的那块 block 号码;而 block 则是记录在这个目录下的文件名与该文件名占用的 inode 号码数据。
文件寻址过程
整个文件系统的目录结构就如一个树状图,从根目录开始,从目录的inode获取它的block。从block中获取子目录的inode值,持续往下寻址直到找到对应文件。
以上一节的源文件/home/jingx/test_link_dir/file1
为例,文件系统访问这个文件的流程如下:
- 找到"/"挂载点,获取root inode。
PS:在往下搜寻的时候,如果有新的挂载点,会重新获取root inode。当前仅讨论简单情况。
-
通过root inode找到对应block,继续往下寻找下一个目录的inode。通过inode获取文件权限属性,check当前用户的操作是否有权限继续;如果有权限,则通过inode指向的block搜寻下一层,直到搜索到最终文件:home/jingx/test_link_dir/file1。
-
最终找到对应文件的inode,从inode中获取文件属性和block号;从block号获取文件内容。这就是一次完整的文件寻址过程。
硬链接实现
从上一节知道了文件的寻址过程。现在来看硬链接的具体实现方式:
- 硬链接某一个文件时,实际上是在对应父目录的block中,添加一条 inode:硬链接文件名 的记录。通过
ls -il
命令可以输出对应文件的inode号。可以看到源文件和硬链接文件,其实是同一个inode号
如果硬链接文件在其他目录,也是同样在对应目录的block中添加一条指向文件实际inode的记录。
同时观察输出的第三列属性,因为当前有3个对象指向这个inode,所以这个inode的引用为3。
PS:直到inode引用为0时,这个文件才从文件系统认定被删除。
所以建立文件的硬链接,实际上就是在对应目录的block中新建一条记录,并非新增一个文件。
符号链接
对比硬链接的实现,符号链接实际上是一个真实存在的文件。
- 它是一个跟普通文件一样,存在于硬盘中,有自己的inode编号和block。
-
inode中标明它的文件类型是符号链接(权限中的第一位
l
); -
显示权限为777,但实际权限是跟父目录及被链接对象有关:
-
如果是对符号链接本身的操作(删除或修改指向),则根据操作用户在父目录的权限来执行;
-
如果是对符号链接指向对象的操作(chmod、chown、cp等),则根据操作用户在被链接对象的权限来执行;
-
-
符号链接文件实体内容则只有被链接文件的路径。存储位置根据链接格式(local、extend)有关,在此不赘述;
遗留问题回答
根据上面描述的硬链接和符号链接的特点,可以回溯文章开始提出的一些问题:
-
为什么源文件删除了,硬链接还能正常访问,而符号链接却失效了?
因为删除源文件的操作,实际上是在它父目录的block中删掉类似对应的 文件名:inode 的指向。实际的文件内容(inode、block)并没有删掉。硬链接还可以根据本身的inode号进行文件寻址。而符号链接实际保存的是源文件的路径,所以访问符号链接时候,会根据路径去寻找文件。而源文件删除后,该路径的文件记录已经不存在了,所以会导致
No such file or directory
。 -
为什么修改符号链接的属主/权限,符号链接的属主/权限却未变动,变动的是源文件?
因为像chmod/chown等命令做操作的时候,会递归的去对最终文件进行操作。所以修改属主/权限的操作实际是针对源文件的。
因为这个原因,导致了符号链接的提权类问题。由于操作、符号链接所在目录、源文件三者的权限不一致,可能导致通过伪造符号链接等方式进行提权操作。如果添加"-h"参数,则会在操作的时候忽略符号链接文件。以此来防止
-
为什么硬链接的所有文件属性都跟源文件保持一致?
因为硬链接文件的inode和源文件的inode是同一个,而inode是存储文件属性的位置。
-
为什么硬链接不能链接给目录?
为了防止路径回环。回忆之前说的文件寻址模式,是通过树状来进行寻址。假设将/a/b/hardlink_dir链接到/a上,由于a和hardlink_dir都是同一个inode,在寻址逻辑上会变成hardlink_dir既是b的子目录又是b的父目录(a)。在内核的处理上复杂度变变的更高,所以从使用工具层面上禁止了目录的硬链接。
PS:在系统中实际是存在两个特殊的硬链接,即:
.
和..
。.
指向目录本身,..
指向父目录。因为系统对它们做了特殊处理,所以不会有路径回环的问题发生。 -
补充:硬链接也不能跨文件系统进行链接,因为寻址模式、inode存储方式以及superblock在不同的文件系统间是不一样的。而软链接可以跨文件系统链接,因为软链接只存储被链接文件的路径,根据路径进行寻址这个是文件系统的共性。
Reference