Unix/Linux编程:目录、硬链接、软链接

目录

文件树

在开始之前,先来看看Unix是如何组织磁盘上的文件的。

磁盘上的文件和目录被组成一颗目录树,每个节点都是目录或者文件。如下:

  • 大方框表示目录
  • 小方框表示文件
  • 目录之间的连线表示目录间组织关系
    在这里插入图片描述
    在Unix系统中,每个文件都位于某个目录中,在逻辑上是没有驱动器或者卷的,当然在物理上一个系统可以有多个驱动器或者分区,位于不同驱动器和分区上的目录通过文件树无缝连接在一起,甚至软盘、光盘这些移动存储介质也被挂在文件树中的某一个子目录来处理

这些使操作目录极为简单,只需要考虑文件和目录两种情况,而无需考虑驱动器或者分区

那什么是目录呢?

目录

  • 目录是一种特殊的文件,它的内容是文件和目录的名字。里面包含很多记录,每个记录个格式由同一的标准定义。每条记录代表一个文件或目录。
  • 在文件系列内部,目录是一个包含文件名和i-节点对列表的文件

在这里插入图片描述
(1)“文件在目录中”的真正含义

一般都说文件存放在某个目录,但是现在已经知道目录中存放的只是文件在i-节点表的入口,而文件的内容则存储在数据区。文件在某个目录中是什么意思?比如,从用户角度来看,文件y在目录demodir中,而从系统角度来看,看到的是目录中有一个包含文件y和i-节点号为497的入口。

类似,“文件x在目录a中”意味着目录a中有一个执行i-节点402的链接,这个链接所附加的文件名为x。另外,上面d1目录下的xlink也指向402,也就是说它们两指向同一个文件。

(2)文件名

在Unix文件系统中,文件没有文件名,但是链接具有名字。文件仅仅拥有i-节点号。

(硬)链接

在文件系统中,目录的存储方式类似于普通文件。目录与普通文件的区别如下:

  • 在其i-node条目中,会将目录标记为一种不同的文件类型
  • 目录是经过特殊组织而成的文件。本质来说是一个表格,包含文件名和i-node编号
  • 目录文件永远不会为空,每个目录都至少包含两个特殊的项----.(当前目录)和..(父目录)

在大多数原生Linux文件系统上,文件名长度可以达到255个字符。

下表针对/ect/passwd所维护的文件系统i-node表以及相关目录文件的部分内容,展示了目录与i-node之间的关系。
在这里插入图片描述

  • 虽然一个进程能够打开一个目录,但却不能使用 read()去读取目录的内容。(在一些 UNIX 实现中,也可以对目录执行 read(),但这会给应用带来可移植性方面的问题。)
  • 进程同样也不能使用 write()来改变一个目录的内容,仅能借助于诸如 open()(创建一个新文件)、link()、mkdir()、symlink()、unlink()及 rmdir()之类的系统调用间接(向内核请求)改变其内容。
  • i-node 表的编号始于 1,而非 0,因为若目录条目的 i-node 字段值为 0,则表明该条目尚未使用。i-node 1 用来记录文件系统的坏块。文件系统根目录(/)总是存储在 i-node 条目 2中(如上图),所以内核在解析路径名时就知道该从哪里着手。

文件i-node中存储的信息列表并未包含文件名,而仅通过目录列表中的一个映射来定义文件名称。这样的好处在于,能够在相同或者不同目录中创建多个名称,每个均指向相同的i-node节点。也将这些名称称为链接,有时也叫做硬链接,以与符合链接有所区别

所有的原生 Linux 和 UNIX 文件系统均支持硬链接,然而,许多非 UNIX 文件系统(比如,微软的 VFAT)则不支持。(微软的 NTFS 文件系统支持硬链接。

可在 shell 中利用 ln 命令为一个业已存在的文件创建新的硬链接,正如下面 shell 会话日志所示
在这里插入图片描述
ls -li中:

  • 其第一列名称abc和xyz均指向相同的i-node条目,也就是说指向相同的文件。
  • 其第三列为对i-node链接的计数。执行 ln abc xyz 命令后,abc 所指向 i-node 的链接计数升至 2,因为现在指向该文件的由两个名字。

如果移除其中一个文件名,另一文件名以及文件本身将继续存在:
在这里插入图片描述
仅当i-node的链接计数降为0时,也就是移除了文件的所有名字时,才会删除(释放)文件的i-node记录和文件快。

同一文件的所有名字(链接)地位平等—没有一个名字(比如,第一个)会优于其他名字。如上所示,在移除与文件相关的第一个名称后,物理文件继续存在,但只能通过另一文件名来访问其内容。

在 Linux 系统上,借助于 readdir()对 Linux 特有/proc/PID/fd 目录内容(内含符号链接指向进程当前打开的每个文件描述符)的扫描,可以获知一个进程当前打开了哪些文件。此外,已经移植到多个 UNIX 系统中的 lsof(1)和 fuser(1)工具也精于此道

对硬链接的限制有二,均可用符号链接来加以规避:

  • 因为目录条目(硬链接)对文件的指代采用了i-node编号,而i-node编号的唯一性仅在一个文件系统之类才能得到保障,所以硬链接必须为其指代的文件驻留在同一文件系统中
  • 不能为目录创建硬链接,从而避免出现现令诸多系统程序陷于混乱的链接环路
  • 早期的 UNIX 实现一度曾允许超级用户为目录创建硬链接。这在当时是必要的,因为这些实现并未提供 mkdir()系统调用。相反,当时会使用 mknode()调用创建一个目录,然后为.和…创建链接。虽然这一特性已是昨日黄花,但一些现代 UNIX 实现出于向后兼容的目的仍对其加以保留。
  • 使用绑定挂载(bind mount)可以获得与为目录创建硬链接相似的效果。

符号(软)链接

符号链接,有时也叫做软链接,是一种特殊的文件类型,其数据是另一文件的名称。

下图展示的情况是:

  • 两个硬链接—/home/erena/this 和/home/allyn/that—指向同一个文件,
  • 符号链接/home/kiran/other,则指代文件名/home/erena/this。
    在这里插入图片描述
    在 shell 中,符号链接是由 ln–s 命令创建的。ls–F 命令的输出结果中会在符号链接的尾部标记@。

符号链接的内容既可以是绝对路径,也可以是相对路径。解释相对符号链接时以链接本身的位置作为参照点。

文件的链接计数不会将符号链接计算在内。

如果移除了符号链接所指向的文件名,符号链接本身还将继续存在,经过无法在对此进行解引用。也将此类链接叫做悬空链接。根由甚者,还可以为并不存在的文件名创建一个符号链接。

引入符号链接的是 4.2BSD。虽然未获 POSIX.1-1990 接纳,但 SUSv1 和 SUSv3 随后还是将其纳入规范。

因为符号链接指代一个文件名,而非i-node编号,所以可以用其来链接不同文件系统中的一个文件。对硬链接的那些制约也不会困扰到符号链接,可以为目录创建符号链接。

  • 诸如find或tar之类的工具命令有能力识别硬链接和符号链接之间的差异,要么会在默认情况下不对符号链接进行解引用,要么会避免因使用符号链接而陷入引用环路。

  • 符号链接之间可能会形成链路。

  • 当在各个文件相关的系统调用中指定了符号链接时,内核会对一系列链接层层解去引用,直抵最终文件

SUSv3 规定,针对路径名中的每个符号链接部件,系统实现应允许对其实施至少_POSIX_SYMLOOP_MAX 次解除引用操作。_POSIX_SYMLOOP_MAX 的规定值为 8。然而,在内核 2.6.18 之前,Linux 将解析符号链接链路时的解引用操作次数限制为 5 次。始于版本2.6.18,Linux 内核实现了 SUSv3 所规定的最小解引用次数:8 次。Linux 还将对一个完整路径名的解引用总数限制为 40 次。施加这些限制,意在应对超长符号链接链路以及符号链接环路,从而使内核代码在解析符号链接时免于引发堆栈溢出。

总是会对路径名中目录部分(即最后一个斜线字符前的所有组成部分)的符号链接进行解除引用操作。因此,在路径/somedir/somesubdir/file 中,若 somedir 和somesubdir 属于符号链接,则一定会解除对这两个目录的引用,而针对 file 是否进行解引用与否,则取决于路径名所传入的系统调用。

符号链接的文件权限和所有权

  • 大部分操作会无视符号链接的所有权和权限(创建符号链接时会为其赋予所有权限)。
  • 是否允许操作是由符号链接所指代文件的所有权和权限来决定。
  • 仅当在带有粘性权限位的目录中对符号链接进行移除或改名操作时,才会考虑符号链接自身的所有权
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值