use*_*539 137 filesystems directory hard-link symlink
我在教科书中读到 Unix/Linux 不允许硬链接到目录,但允许软链接。是不是因为,当我们有循环,如果我们创建硬链接,一段时间后我们删除原始文件,它会指向一些垃圾值?
如果循环是不允许硬链接的唯一原因,那么为什么允许软链接到目录?
Dan*_*lai 152
这只是一个坏主意,因为无法区分硬链接和原始名称之间的区别。
允许硬链接到目录会破坏文件系统的有向无环图结构,可能会创建目录循环和悬空目录子树,这会使fsck和任何其他文件树遍历器容易出错。
首先,为了理解这一点,让我们来谈谈 inode。文件系统中的数据保存在磁盘上的块中,这些块由 inode 收集在一起。您可以将 inode 视为文件。?但是,inode 缺少文件名。这就是链接的用武之地。
链接只是一个指向 inode 的指针。目录是保存链接的 inode。目录中的每个文件名只是一个指向 inode 的链接。在 Unix 中打开一个文件也会创建一个链接,但它是一种不同类型的链接(它不是一个命名链接)。
硬链接只是指向该 inode 的额外目录条目。当您ls -l,权限后的数字是命名链接数。大多数常规文件都有一个链接。创建一个文件的新硬链接将使两个文件名指向同一个 inode。笔记:
% ls -l test
ls: test: No such file or directory
% touch test
% ls -l test
-rw-r--r-- 1 danny staff 0 Oct 13 17:58 test
% ln test test2
% ls -l test*
-rw-r--r-- 2 danny staff 0 Oct 13 17:58 test
-rw-r--r-- 2 danny staff 0 Oct 13 17:58 test2
% touch test3
% ls -l test*
-rw-r--r-- 2 danny staff 0 Oct 13 17:58 test
-rw-r--r-- 2 danny staff 0 Oct 13 17:58 test2
-rw-r--r-- 1 danny staff 0 Oct 13 17:59 test3
^
^ this is the link count
Run Code Online (Sandbox Code Playgroud)
现在,您可以清楚地看到没有硬链接之类的东西。硬链接与常规名称相同。在上面的例子中,test或者test2,哪个是原始文件,哪个是硬链接?到最后,你真的无法分辨(甚至通过时间戳),因为两个名称都指向相同的内容,相同的 inode:
% ls -li test*
14445750 -rw-r--r-- 2 danny staff 0 Oct 13 17:58 test
14445750 -rw-r--r-- 2 danny staff 0 Oct 13 17:58 test2
14445892 -rw-r--r-- 1 danny staff 0 Oct 13 17:59 test3
Run Code Online (Sandbox Code Playgroud)
在-i以标记ls显示你在该行的开头索引节点号。请注意如何test和test2具有相同的 inode 编号,但test3具有不同的inode 编号。
现在,如果允许您对目录执行此操作,则文件系统中不同位置的两个不同目录可能指向同一事物。事实上,一个子目录可以指向它的祖父目录,从而创建一个循环。
为什么这个循环是一个问题?因为当您遍历时,无法检测到您正在循环(在遍历时不跟踪 inode 编号)。假设您正在编写du命令,该命令需要遍历子目录以了解磁盘使用情况。怎么du知道它什么时候循环?du为了完成这个简单的任务,它很容易出错,并且必须进行大量的簿记工作。
符号链接是一个完全不同的野兽,因为它们是一种特殊类型的“文件”,许多文件系统 API 往往会自动遵循。请注意,符号链接可以指向不存在的目标,因为它们按名称指向,而不是直接指向 inode。这个概念对于硬链接没有意义,因为仅仅存在“硬链接”就意味着文件存在。
那么为什么可以du轻松处理符号链接而不是硬链接呢?我们能够在上面看到硬链接与普通目录条目没有区别。然而,符号链接是特殊的、可检测的和可跳过的!
du注意到符号链接是一个符号链接,并完全跳过它!
% ls -l
total 4
drwxr-xr-x 3 danny staff 102 Oct 13 18:14 test1/
lrwxr-xr-x 1 danny staff 5 Oct 13 18:13 test2@ -> test1
% du -ah
242M ./test1/bigfile
242M ./test1
4.0K ./test2
242M .
Run Code Online (Sandbox Code Playgroud)
小智 18
您可以使用绑定挂载来模拟硬链接目录
sudo mount --bind /some/existing_real_contents /else/dummy_but_existing_directory
sudo umount /else/dummy_but_existing_directory
Run Code Online (Sandbox Code Playgroud)
小智 17
除挂载点外,每个目录都有一个且唯一的父目录:...
一种方法pwd是检查 device:inode for '.' 和 '..'。如果它们相同,则您已到达文件系统的根目录。否则,在父目录中找到当前目录的名称,将其压入堆栈,然后开始比较 '../.' 用“../..”,然后用“../../.” 使用 '../../..' 等。一旦你找到了根,就开始从堆栈中弹出和打印名称。该算法依赖于这样一个事实,即每个目录只有一个父目录。
如果允许硬链接到目录,应该..指向多个父级中的哪一个?这是不允许硬链接到目录的一个令人信服的原因。
指向目录的符号链接不会导致该问题。如果程序想要,它可以lstat()对路径名的每个部分执行一个操作并检测何时遇到符号链接。该pwd算法将返回目标目录的真实绝对路径名。某处有一段文本(符号链接)指向目标目录这一事实几乎无关紧要。这种符号链接的存在不会在图中创建循环。
关于这个问题,我想再补充几点。linux 中允许目录的硬链接,但以一种受限的方式。
我们可以测试这一点的一种方法是,当我们列出目录的内容时,我们会发现两个特殊目录“.”。和 ”..”。据我们所知 ”。” 指向同一个目录,“..”指向父目录。
因此,让我们创建一个目录树,其中“a”是父目录,其子目录“b”。
a
`-- b
Run Code Online (Sandbox Code Playgroud)
记下目录“a”的 inode。当我们ls -la从目录“a”执行 a 时,我们可以看到“。” 目录也指向同一个 inode。
797358 drwxr-xr-x 3 mkannan mkannan 4096 Sep 17 19:13 a
Run Code Online (Sandbox Code Playgroud)
在这里我们可以发现目录“a”有三个硬链接。这是因为 inode 797358 有三个以“.”为名的硬链接。在“a”目录中,名称为“..”,在目录“b”中,名称为“a”。
$ ls -ali a/
797358 drwxr-xr-x 3 mkannan mkannan 4096 Sep 17 19:13 .
$ ls -ali a/b/
797358 drwxr-xr-x 3 mkannan mkannan 4096 Sep 17 19:13 ..
Run Code Online (Sandbox Code Playgroud)
所以在这里我们可以理解硬链接只用于目录连接它们的父目录和子目录。因此没有子目录的目录将只有 2 个硬链接,因此目录“b”将只有两个硬链接。
阻止自由目录硬链接的原因之一是避免无限引用循环,这会混淆遍历文件系统的程序。
由于文件系统被组织为树,并且树不能具有循环引用,因此应该避免这种情况。
以下都不是禁止硬链接到目录的真正原因;每个问题都很容易解决:
的真正原因(如@托尔比约恩Ravn的安徒生暗示)来当你删除它有多个父目录,从指向的目录..:
..现在应该指向什么?
如果该目录从其父目录中删除,但其链接数仍然大于0那么一定有某些东西,某处仍然指向它。你不能..指指点点;许多程序依赖于..,因此系统将不得不遍历整个文件系统,直到找到指向已删除目录的第一件事,只是为了更新... 要么如此,要么文件系统必须维护指向硬链接目录的所有目录的列表。
无论哪种方式,这都会导致性能开销和文件系统元数据和/或代码的额外复杂性,因此设计人员决定不允许这样做。
在目录上创建硬链接将是不可恢复的。假设我们有:
/dir1
???this.txt
???directory
? ???subfiles
???etc
Run Code Online (Sandbox Code Playgroud)
我将它硬链接到/dir2.
所以/dir2现在还包含所有这些文件和目录
如果我改变主意怎么办?我不能只是rmdir /dir2(因为它不是空的)
如果我递归删除/dir2......它也会被删除/dir1!
恕我直言,这是避免这种情况的充分理由!
编辑 :
评论建议通过对目录进行操作来删除该目录rm。但是rm在非空目录上失败,无论目录是否硬链接,这种行为都必须保留。所以你不能只是rm取消链接。它需要一个新的参数rm,只是说“如果目录 inode 的引用计数 > 1,则只取消链接目录”。
这反过来又打破了另一个最不令人惊讶的原则:这意味着删除我刚刚创建的目录硬链接与删除普通文件硬链接不同......
我将改写我的句子:如果没有进一步的发展,硬链接的创建将是不可恢复的(因为当前的命令无法在不与当前行为不一致的情况下处理删除)
如果我们允许更多的开发来处理这种情况,如果您对系统的工作方式不够了解,那么陷阱的数量以及数据丢失的风险,这样的开发意味着,恕我直言,这是限制目录硬链接的充分理由。