文件共享

4.2.3 说无环图目录能支持共享,但没说这条”共享边”具体怎么造出来。这一节给出两种造法,它们的差别正是本节全部考点的来源。

先把共享的定义钉死:文件共享指多个用户共同使用同一个文件,系统中只保留该文件的一份副本。 “只有一份副本”是硬要求——若各存各的,一方修改后另一方看到的就是旧数据,那叫复制,不叫共享。

机制

基于索引节点的共享方式(硬链接)

这种方式只有在采用索引节点的系统中才可能,原理在 4.1.2 已经埋下:文件的物理地址等信息全在 inode 里,目录项中只有 ⟨文件名, inode 号⟩。

既然如此,让多个目录项填写同一个 inode 号,就自然实现了共享。 用户 A 的目录里有一项叫 data.txt、用户 B 的目录里有一项叫 报表,两项的 inode 号相同——它们是同一个文件的两个名字。

inode 中的链接计数 count 记录有多少个目录项指向自己。 每建立一个新链接 count 加一,每删除一个目录项 count 减一。

关键规则是:只有当 count 减到 0 时,才真正删除文件本体(回收 inode 与数据块)。 若不这样规定,文件主一删除,其他用户的目录项就成了悬空指针。

硬链接留下的一个遗留问题

王道特别指出一个不对称之处,它是本节最容易被忽略的考点:

文件主删除自己的那个目录项后,count 减一,但只要 count 仍大于 0,文件就不会被删除。 此时文件主已经不再拥有指向该文件的目录项,却仍然是 inode 中记录的所有者——在计费的系统中,他还要继续为这个文件的存储开销付费,直到最后一个共享者也删除了它。

这个问题的根源是:所有者信息记在 inode 里,而 inode 是被共享的。 删除一个名字不会改变 inode 中的所有者字段。

利用符号链接实现共享(软链接)

做法完全不同:为共享者新建一个文件,这个文件的类型标记为 LINK,它的内容就是被共享文件的路径名。

访问时,系统读到这是一个 LINK 类型的文件,就取出其中的路径,再重新走一遍完整的路径解析去找真正的目标。

符号链接文件自己有独立的 inode 和目录项,它是一个货真价实的文件,只不过内容是一个字符串。这一点是理解它全部特性的钥匙。

两种方式的能力差别从何而来

硬链接靠的是 inode 号,符号链接靠的是路径名。 两者所有的差别都能从这一句推出来:

① 能否跨文件系统。 inode 号只在本文件系统内唯一——A 文件系统的 5 号 inode 和 B 文件系统的 5 号 inode 毫无关系。因此硬链接不能跨文件系统。而路径名是全局的,所以符号链接可以跨文件系统,也可以指向网络上的文件。

② 能否指向目录。 硬链接一般不允许指向目录,因为多个目录项指向同一个目录会在命名空间里造出环,退化成 通用图目录,带来遍历死循环和引用计数失效的问题。符号链接可以指向目录——因为它只是一个存路径的文件,不会真的在目录树上加一条父子边,遍历时系统可以选择不跟随。

③ 目标被删除后会怎样。 硬链接下根本不会出现”目标被删除”——删的只是众多名字中的一个,count 减一而已,只要还有别的名字,文件就还在。符号链接下则会出现悬空链接:目标文件被真正删除后,符号链接依然存在,但其中的路径已经指向一个不存在的位置,访问时报错。

④ 访问开销。 硬链接没有任何额外开销,它和普通目录项完全一样。符号链接每次访问都要多读一个文件(读出路径),再从头解析这条路径,路径有几级就多几轮目录检索,开销明显更大。

边界

硬链接没有”原件”和”链接”之分

这是最反直觉的一点。用 ln 建立硬链接后,新旧两个目录项在系统看来完全平等——它们是同一个 inode 的两个名字,没有任何字段记录”谁是先建的”。

所以”删除原文件后硬链接还在吗”这个问题本身就问错了:系统里根本不存在”原文件”这个概念,只存在”这个 inode 现在有几个名字”。删掉任何一个名字,效果都一样:count 减一。

符号链接则完全相反:它明确区分”链接文件”和”目标文件”,两者是两个独立的文件,有各自的 inode。

链接计数与打开计数是两回事

这两个计数都控制着”文件什么时候能真正被删除”,但管的是不同的东西:

链接计数(在 inode 中)记录磁盘上有多少个目录项指向它,属于持久状态,关机后依然有效。

打开计数(在系统打开文件表中)记录当前有多少个进程打开了它,属于运行期状态,关机即消失。

类 UNIX 系统中,数据块真正被回收的条件是两者都为 0。 这解释了一个常见现象:删除一个正在被进程使用的文件,磁盘空间不会立刻释放——目录项确实没了(ls 看不到),但进程还开着它,要等进程退出后空间才回来。

符号链接为什么”更安全”

尽管符号链接会悬空,它在共享场景中反而更常用,原因是它不改变文件的所有权和责任归属。

硬链接会让文件主陷入上面那个”删了名字还要付费”的困境;而符号链接下,共享者手里只有一个存着路径的小文件,文件本体的生死完全由文件主决定。文件主删除文件后,共享者的链接失效——这在语义上是正确的,因为文件确实没了。

判据:硬链接让所有共享者对文件的存续拥有同等否决权;符号链接则把控制权完全留给文件主。

那些 @ --> 条目就是符号链接

Linux 根目录下常见的 bin -> usr/bin、lib -> usr/lib、sbin -> usr/sbin 全都是符号链接。

它们能存在,恰恰证明了符号链接的两条能力:这些目标都是目录(硬链接做不到),而且它们把访问重定向到了另一处,同时保持旧路径依然可用——这正是这类系统迁移(把 /bin 合并进 /usr/bin)能够不破坏任何已有脚本的原因。

工具显示时用 @ 标记它是符号链接、用 --> 显示它的内容(那个路径),但磁盘上它只是一个类型为 LINK、内容为 "usr/bin" 这九个字符的文件。

对照速查

硬链接(基于索引节点)符号链接(软链接)
本质多个目录项指向同一 inode一个独立文件,内容是目标路径
有无独立 inode没有,共用一个有,是另一个文件
靠什么定位inode 号路径名
跨文件系统不能(inode 号仅本文件系统内唯一)能
能否指向目录一般不允许(会成环)能
目标被删后不存在此情况,只是 count 减一悬空,访问报错
访问开销无额外开销多读一个文件 + 重新解析路径
是否区分原件不区分,完全平等区分,链接与目标是两个文件
存储开销只多一个目录项多一个文件(inode + 数据块)
两个计数在哪记什么性质
链接计数inode 中有几个目录项指向它持久,关机仍在
打开计数系统打开文件表中有几个进程打开了它运行期,关机即消失
回收条件两者都为 0

考点

  • 共享的硬要求是系统中只保留一份副本
  • 硬链接的原理是多个目录项填同一个 inode 号,靠 count 计数
  • count 为 0 才真正删除;文件主删名字后仍需为存储付费(高频细节)
  • 硬链接不能跨文件系统,原因是 inode 号只在本文件系统内唯一
  • 硬链接一般不能指向目录,原因是会成环
  • 符号链接可跨文件系统、可指向目录,但会悬空且访问开销大
  • 硬链接不区分原件与链接,两个目录项完全平等
  • 链接计数与打开计数都为 0,数据块才被回收

链接