“..”真的是硬链接吗?

dr_*_*dr_ 22 filesystems hard-link inode

这是一个有点理论问题,但使用事物的专有名称很重要。

在 UNIX/Linux 文件系统中,..指向父目录。

但是,我们知道硬链接不能指向目录,因为这有可能破坏文件系统的非循环图结构并导致命令无限循环运行。

那么,..真的是硬链接(.)吗?这将使其成为一种特殊类型的硬链接,不受目录限制,但在所有用途上都表现得像硬链接。

或者这是一个特殊的 inode 映射,硬编码到文件系统中,不应该称为硬链接?

Gil*_*il' 38

这取决于文件系统。大多数文件系统遵循传统的 Unix 设计,其中...是硬链接,即它们是文件系统中的实际目录条目。目录的硬链接计数为 2 + n,其中 n 是子目录的数量:即目录父目录中的条目、目录自己的条目.以及每个子目录的..条目。每次创建、删除或移入或移出目录时,硬链接计数都会更新。请参阅为什么在添加任何内容之前新目录的硬链接计数为 2?以获得更详细的解释。

\n

一些文件系统偏离了这一传统,特别是btrfs

\n
\n

我们知道硬链接不能指向目录

\n
\n

这是不精确的措辞。更准确地说,您无法使用ln实用程序或link系统调用或类似方法创建到目录的硬链接,因为内核阻止您这样做。调用mkdir确实会创建到新目录的父目录的硬链接。这是创建到文件系统上的目录的新硬链接的唯一方法(相反,删除目录是删除到目录的硬链接的唯一方法)。

\n

另请注意,将硬链接视为指向主文件的 \xe2\x80\x9c 是一种误导。与符号链接不同,硬链接不是定向的。当一个文件有多个硬链接时,它们是等效的。执行以下顺序后:

\n
mkdir a b\ntouch a/file\nln a/file b/file\n
Run Code Online (Sandbox Code Playgroud)\n

文件系统中没有任何东西可以成为b/file次要的a/file。这两个目录条目都引用同一个文件。它们都是文件的硬链接。

\n

  • 硬链接是定向的,因为它们从目录条目(名称)指向索引节点。 (11认同)
  • @ikegami 符号链接指向路径,而不是目录条目。它独立于它指向的潜在文件而存在。例如,对于可移动驱动器,相同的符号链接可以在不同时间指向不同的文件(并且在未安装驱动器时或者如果安装的驱动器在该特定位置没有文件时悬空)。正确的硬链接:当碰巧有多个目录条目指向同一 inode 时,“硬链接”实际上是目录条目的一个奇特名称。 (5认同)

use*_*489 10

这是一个实现细节。

在符合 POSIX 的文件系统中,..其作用类似于硬链接。

但是,某些文件系统仅模拟这一点,并不实际将其存储在磁盘上。

出于功能目的,假设您没有文件系统损坏,则这种区别没有实际意义。(如果这样做,fsck 旨在解决此问题。)

完全模拟硬链接的非 posix 失败之一是硬链接计数无法指示目录内子目录的正确数量。findoption选项-noleaf禁用使用此链接计数的优化。

  • 硬链接不能跨越安装点。因此,操作系统必须专门处理这个问题,作为挂载点的一部分。 (2认同)

Phi*_*ing 8

作为吉尔斯答案的补充我认为值得关注这些词并对其进行扩展:

\n
\n

另请注意,将硬链接视为指向主文件的 \xe2\x80\x9c 是一种误导。

\n
\n

了解 Linux 中文件的概念模型非常重要,其中每个文件名称都是指向可能指向数据的“inode”的“链接”。

\n

这里令人困惑的是“硬链接”和“符号链接”的命名约定听起来像是同一事物的两种风格。他们不是!

\n

常规文件是:

\n
link -> x \n        | Inode -> Data\n
Run Code Online (Sandbox Code Playgroud)\n

“硬链接文件”没有什么不同:

\n
link_a -> x\n          | Inode -> Data\nlink_b -> x\n
Run Code Online (Sandbox Code Playgroud)\n

但符号链接是:

\n
original_file_name -> x\n                      | Inode -> Data\n\nsym_link_name      -> x\n                      | Inode -> File name "original_file_name"\n
Run Code Online (Sandbox Code Playgroud)\n

那么为什么不能硬链接目录呢?

\n

我得到的最好的解释就是源自于此。该..条目必须保留在目录中。如果您有多个单一名称指向目录本身,则您可能有多个父目录,而这是不可能的,因为..只能存在一次,就像目录中所有其他可能的名称只能存在一次一样。

\n

  • 即使忽略“..”,如果我们允许像创建文件一样轻松地创建指向目录的(新)硬链接,操作系统也需要注意禁止目录由于图中的循环而陷入困境。有了循环,从外部删除到循环的任何链接都会使循环目录陷入困境:不会被删除,因为它们具有非零链接计数,但也无法访问它们。并且不仅在创建链接时可能发生循环,而且在移动目录时也可能发生循环,因此首先禁止指向目录的链接会更容易。:) (3认同)

Cod*_*ome 6

...指向 inode 的特殊硬链接

\n

从纯粹务实的角度来说,.. 一个硬链接。在 Linux 上,当从已挂载卷的顶层调用时,它会被视为到挂载点的硬链接,而在 Linux 和 macOS 上,作为特殊情况,它会/硬链接.和到 inode 2。..

\n

更多详情

\n

正如其他人指出的那样,...都是支持 inode 的文件系统上 inode 的硬链接。有一些文件系统没有 inode,但这只是一个附带问题。出于实际目的,无论系统是否直接支持 inode,硬链接都仅指向给定文件系统上的相同元数据块。有时硬链接是文件系统上的真实链接,有时它是合成的,因为 POSIX 系统期望...由于历史原因而存在。无论哪种方式,它都会被视为目录的硬链接,并且某些文件系统(例如 HFS+)会这样做允许您硬链接不跨越文件系统边界的目录。

\n

目录的硬链接

\n

MacOS确实允许 HFS+ 文件系统上的硬链接指向目录,因为这在历史上是 Time Machine 优化磁盘使用的方式。然而,较新版本的 Time Machine 使用 APFS 文件系统和文件系统快照,因此除了向后兼容性之外,实际上不需要此例外,并且它不适用于 APFS。不要依赖它。

\n

因此,通常是文件系统本身决定目录是否可以硬链接。在 Ubuntu 22.04 上,lnman 1 ln如果系统允许,

\n
       -d, -F, --directory\n              allow  the  superuser to attempt to hard link directories (note:\n              will probably fail due to system restrictions, even for the  su\xe2\x80\x90\n              peruser)\n\n
Run Code Online (Sandbox Code Playgroud)\n

可能让大多数人感到困惑的部分是挂载点。如果您将磁盘挂载为/mnt/foo,则cd /mnt/foo; ls -ld ..指向挂载点的 inode,在本例中为 的 inode /mnt。挂载目录的硬链接..要么不会真正跨越文件系统边界,因为它只是查看 /mnt/foo 的硬链接(无论当前是否挂载卷,该链接都存在),要么它得到由内核专门处理以支持已安装的卷。这很可能是一个实现细节,我无法指向与之相关的任何内核源代码,但从功能上来说,它在技术上仍然是一个硬链接,因为它..指向一个 inode而不是指向文件名的软链接。

\n

您可以通过以下方式自行测试:

\n
       -d, -F, --directory\n              allow  the  superuser to attempt to hard link directories (note:\n              will probably fail due to system restrictions, even for the  su\xe2\x80\x90\n              peruser)\n\n
Run Code Online (Sandbox Code Playgroud)\n

在 Linux 和 macOS 上,当使用该-x标志调用时,您将看到...始终指向 inode 2。许多文件系统为坏块保留 inode 1

\n

由于您可以创建指向某些文件系统上的目录的硬链接(包括带有debugfs的 EXT3/4 ),因此您不能硬链接目录并不是真的。为了确保目录图是非循环的,通常不支持它,并且像fsck这样的工具会抱怨除.当前..工作目录之外的任何内容的目录硬链接的文件系统上的硬链接目录( .) 和父目录 (.. ) 作为特殊的遗留情况。

\n