很久之前就知道硬链接(hard link)和软连接(soft link)的存在,但是一直搞不清它们之间的区别,今天 Google 到一篇文章,通俗易懂地解决了我心头的疑惑。英文 ok 的童鞋可以直接看 原文 。
Linux 文件系统使用一个叫作 inode 的结构,存储一个文件中除了文件名和文件数据的所有信息,包括文件大小,所有者,读写权限等内容。同时 inode 存储了该文件数据存放的地址。
.---------------> ! data ! ! data ! etc
/ +------+ !------+
! permbits, etc ! data addresses !
+------------inode---------------+
inode 不存储文件名信息,则需要有另外一个数据结构存储文件名与其对应的 inode 。这个结构在 ext2 里称为目录实体(directory entry)。
.--------------> ! permbits, etc ! addresses !
/ +---------inode-------------+
! filename ! inode # !
+--------------------+
有了上面简单的预备知识后,我们可以开始解释软连接和硬链接了。
硬链接就是目录实体结构中,两个不同的文件名拥有同一个 inode。
! filename ! inode # !
+--------------------+
\
>--------------> ! permbits, etc ! addresses !
/ +---------inode-------------+
! othername ! inode # !
+---------------------+
这样意味着硬链接的两个文件拥有相同的 User ID, Group ID, 读写权限,同时文件数据的位置也是一样的。
软连接的概念相对抽象。软连接文件的 inode 与目标文件不一致,它有自己的 inode ,也有自己独有的数据,这个数据即是所指向的目标文件的路径。
! filename ! inode # !
+--------------------+
\
.-------> ! permbits, etc ! addresses !
+---------inode-------------+
/
/
/
.----------------------------------------------'
(
'--> !"/path/to/some/other/file"!
+---------data-------------+
/ }
.~ ~ ~ ~ ~ ~ ~ }-- (redirected at open() time)
( }
'~~> ! filename ! inode # !
+--------------------+
\
'------------> ! permbits, etc ! addresses !
+---------inode-------------+
/
/
.----------------------------------------------------'
(
'-> ! data ! ! data ! etc.
+------+ +------+
打开软链接文件时,会通过该文件的数据得知目标文件的地址,自动重定向到目标文件。
通过 mkdir
建立一个新目录 directory
,在 directory
的父目录下执行 ls -lia
指令:
1 | $ ls -lia 319519 drwxr-xr-x 24 onlyice onlyice 4096 Jan 4 22:26 . 262146 drwxr-xr-x 3 root root 4096 Jan 4 18:41 .. 319669 drwxr-xr-x 2 onlyice onlyice 4096 Jan 4 22:26 directory |
ls
指令表示列出当前目录的文件,开启 l
选项输出详细信息,i
输出 inode 信息(第一列),a
表示目录 .
, ..
的信息也一并输出。可以看到目录也分配有一个 inode。
1 | $ cd directory $ echo "This is a file" > basic.file $ ls -lia 319669 drwxr-xr-x 2 onlyice onlyice 4096 Jan 4 22:49 . 319519 drwxr-xr-x 24 onlyice onlyice 4096 Jan 4 22:26 .. 269019 -rw-r--r-- 1 onlyice onlyice 15 Jan 4 22:45 basic.file |
此时可以看到,新建的文件 basic.file
分配了 inode 269019。留意当前目录 .
的 inode,与上一个输出对比,发现了什么?接下来我们创建一个硬链接文件:
1 | $ ln basic.file hardlink.file $ ls -lia 319669 drwxr-xr-x 2 onlyice onlyice 4096 Jan 4 22:49 . 319519 drwxr-xr-x 24 onlyice onlyice 4096 Jan 4 22:26 .. 269019 -rw-r--r-- 2 onlyice onlyice 15 Jan 4 22:45 basic.file 269019 -rw-r--r-- 2 onlyice onlyice 15 Jan 4 22:45 hardlink.file |
可以发现新创建的 hardlink.file
文件与 basic.file
文件有着相同的 inode ,同时读写权限一致文件长度也相同(15 字节)。第三列的数字由 1 变成 2,表示的是该 inode 的引用次数。试着改变一下文件权限:
1 | $ chmod a+w basic.file $ ls -lia 319669 drwxr-xr-x 2 onlyice onlyice 4096 Jan 4 22:49 . 319519 drwxr-xr-x 24 onlyice onlyice 4096 Jan 4 22:26 .. 269019 -rw-rw-rw- 2 onlyice onlyice 15 Jan 4 22:45 basic.file 269019 -rw-rw-rw- 2 onlyice onlyice 15 Jan 4 22:45 hardlink.file |
hardlink.file
也随之改变。现在试试建立一个软连接:
1 | $ ln -s basic.file softlink.file $ ls -lia 319669 drwxr-xr-x 2 onlyice onlyice 4096 Jan 4 22:49 . 319519 drwxr-xr-x 24 onlyice onlyice 4096 Jan 4 22:26 .. 269019 -rw-rw-rw- 2 onlyice onlyice 15 Jan 4 22:45 basic.file 269019 -rw-rw-rw- 2 onlyice onlyice 15 Jan 4 22:45 hardlink.file 269011 lrwxrwxrwx 1 onlyice onlyice 10 Jan 4 22:49 softlink.file -> basic.file |
softlink.file
的 inode 与其他两个文件都不同,而且其文件大小为 10 字节。虽然不知道怎样查看它的数据内容,但是 10 字节的大小不难看出应该是什么,留给读者自行思考。
现在尝试删掉 basic.file
,看看 hardlink.file
和 softlink.file
的访问情况:
1 | $ cat hardlink.file This is a file $ cat softlink.file cat: softlink.file: No such file or directory |
softlink.file
需要 basic.file
的 inode 信息才可以完成对文件数据的读取,而 hardlink.file
不需要。此时 hardlink.file
的 inode 中的引用计数降为 1 ,当 inode 引用次数为 0 时,文件系统便可以回收该文件数据存储区域的空间。
另外,值得一提的是,使用系统调用 fopen()
时会增加该文件的引用计数。即使此时删掉该文件的目录实体,也可以通过文件描述符获得该文件信息。下面一段 C 代码展示了这个用途:
1 | FILE *fp; |
最后提个简单的问题,Windows 上的软连接是怎样的形式?