我在教科书中读到,Unix / Linux不允许硬链接到目录,但允许软链接。是因为,当我们有周期并且如果我们创建硬链接,并且在一段时间后删除原始文件时,它会指向一些垃圾值吗?

如果周期是不允许使用的唯一原因硬链接,那么为什么允许到目录的软链接?

评论

应该指向哪里?特别是在删除指向该目录的硬链接之后,在..?指向的目录中。它需要指向某个地方。

..不需要实际存在于任何驱动器上。无论如何,跟踪当前工作目录是操作系统的工作,因此,保持与每个进程的cwd相关联的inode列表并在看到使用时引用它也应该相对简单。 ,这意味着需要牢记这一点来创建符号链接,但是您已经必须小心不要破坏符号链接,而且我不认为其他规则会使其失效。
我喜欢这个解释。简洁易读和/或浏览。

#1 楼

这只是一个坏主意,因为无法分辨硬链接和原始名称之间的区别。

允许硬链接到目录将破坏文件系统的有向无环图结构,可能创建目录循环和悬挂目录子树,这会使fsck和其他任何文件树walker容易出错。文件系统中的数据保存在磁盘上的块中,这些块由一个索引节点收集在一起。您可以将inode视为THE文件。
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


现在,您可以清楚地看到不存在硬链接之类的东西。硬链接与常规名称相同。在上面的示例中,testtest2是原始文件,并且是硬链接?最后,您无法真正分辨(甚至按时间戳记),因为两个名称都指向相同的内容,相同的索引节点:

% 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
在行的开头显示inode编号。请注意-ils如何具有相同的inode编号,
但是test具有不同的inode编号。

现在,如果允许您对目录执行此操作,则文件系统中不同点的两个不同目录可能指向同一对象。实际上,子目录可能指向其祖父母,从而创建了一个循环。

为什么要关注此循环?因为在遍历时,无法检测到是否在循环(遍历时不跟踪inode编号)。想象一下您正在编写test2命令,该命令需要通过子目录递归以了解磁盘使用情况。 test3何时会知道如何循环? 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    .


评论


允许硬链接到目录将破坏文件系统的有向无环图结构。您能否使用硬链接解释有关循环问题的更多信息?为什么用符号链接可以

–user3539
2011年10月12日,1:13

他们似乎在Mac上允许通过在link()系统调用中添加循环检测,并拒绝创建目录硬链接(如果会创建循环)来允许它。似乎是一个合理的解决方案。

–psusi
11-10-14在20:08

@psusi mkdir -p a / b; nocheckln c a; MV A / B; -nocheckln有一个理论上的ln,它不检查目录args,而只是传递给链接,并且由于没有循环,因此我们都擅长创建'c'。然后我们将'c'移到'a / b',然后从a / b / c创建一个循环-> a /-在link()中检查还不够好

–丹尼·杜莱
2011-10-15 2:05

周期非常糟糕。 Windows的“连接”是硬链接目录,存在此问题。如果您不小心将权限应用于整个配置文件,它将发现一系列创建无限循环的联结。在目录中递归,直到路径长度限制停止为止。

– Doug65536
2013年6月15日19:46



@WhiteWinterWolf,根据此链接,他们特别添加了对时间机器的支持,但只允许root用户使用:superuser.com/questions/360926/…

–psusi
16年1月23日在16:18

#2 楼

您可以使用绑定安装来模拟硬链接目录

sudo mount --bind /some/existing_real_contents /else/dummy_but_existing_directory
sudo umount /else/dummy_but_existing_directory


#3 楼

除了挂载点外,每个目录都有一个唯一的父目录:..。和“ ..”。如果它们相同,则您已到达文件系统的根目录。否则,在父目录中找到当前目录的名称,将其压入堆栈,然后开始比较“ ../。”。用“ ../ ..”,然后是“ ../../。”与'../../ ..'等。一旦打到根,开始弹出并从堆栈中打印名称。此算法基于以下事实:每个目录只有一个父目录。

如果允许对目录进行硬链接,则pwd应该指向多个父目录中的哪一个?这就是为什么不允许硬链接到目录的一个令人信服的原因。
目录的符号链接不会导致该问题。如果程序愿意,它可以在路径名的每个部分上执行..并检测何时遇到符号链接。 lstat()算法将返回目标目录的真实绝对路径名。在某处(符号链接)有一段文本指向目标目录这一事实几乎是无关紧要的。这样的符号链接的存在不会在图中创建循环。

评论


对此不太确定。如果我们认为..是到父级的一种虚拟硬链接,则从技术上讲,链接的目标只能有一个其他链接。 pwd只需使用其他算法来解析路径。

– Benubird
2014年5月5日在9:44

#4 楼

关于这个问题,我想补充一点。在Linux中允许使用硬链接进行目录,但是以一种受限方式。和“ ..”。据我们所知 ”。”指向同一目录,“ ..”指向父目录。

因此创建目录树,其中“ a”是父目录,其子目录为“ b”。

 a
 `-- b


记下目录“ a”的索引节点。当我们从目录“ a”执行ls -la时,我们可以看到“”。目录还指向相同的inode。

797358 drwxr-xr-x 3 mkannan mkannan 4096 Sep 17 19:13 a


在这里我们可以发现目录“ 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 ..


阻止自由自由进行目录硬链接的一个原因是避免无限引用循环

由于文件系统被组织为树,并且由于树不能具有循环引用,因此应避免这种情况。

评论


好的例子。这消除了我的怀疑。因此,以特殊方式处理这些情况以避免无限循环。对?

– G Gill
2014年10月7日,下午1:42

由于我们使用有限方式允许硬链接访问目录,即“ ..”和“。”我们不会达到无限循环,因此我们将不需要任何特殊方法来避免这些情况,因为它们不会发生:)

–坎南·莫汉(Kannan Mohan)
2014年10月8日,3:20

#5 楼

以下都不是不允许硬链接到目录的真正原因;每个问题都相当容易解决:


树结构中的循环会导致遍历困难
多个父级,所以这是“真正的”一个?
文件系统垃圾集合

真正的原因(由@ThorbjørnRavn Andersen暗示)
是从..指向的目录中删除具有多个父目录的目录时出现的:

..现在应该指向什么?指向它。您不能让0指向什么;
很多程序都依赖..,因此系统将不得不遍历整个
文件系统,直到找到指向已删除的第一件事
目录,仅用于更新..。要么这样做,要么文件系统必须维护指向硬链接目录的所有目录的列表。文件系统元数据和/或代码,因此
设计者决定不允许这样做。

评论


这也很容易解决:保留子目录的父目录,在添加或删除子目录的链接时更新。删除规范的父级(孩子的..的目标)时,请更新..以指向列表中其他父级之一。

– Jathd
15年1月23日在19:29

我同意。没有火箭科学来解决。但是,这仍然会增加性能,并且会占用文件系统元数据中的一些额外空间并增加复杂性。因此,设计人员采用了一种简单,快速的方法-不允许链接到硬目录。

– Lqueryvg
15年1月24日在12:54

符号链接到目录“违反确定的语义和行为”,但仍然允许它们。因此,某些命令需要一些选项来控制是否遵循符号链接(例如,find和cp中的-L)。当程序后跟“ ..”时,还会造成混乱,因此遍历符号链接后pwd和/ bin / pwd的输出差异。没有“ Unix答案”。只是设计决定。正如我在回答中所说,这一点围绕“ ..”的含义展开。不幸的是,答案中甚至没有提到“ ..”,其他所有人都这么讨厌地投票。

– Lqueryvg
16年5月11日在21:18

顺便说一句,我并不是说我赞成与Dirs建立硬链接。一点也不。我不希望自己的日常工作变得比现在更辛苦。

– Lqueryvg
16年5月11日在21:19

这不是POSIX所说的,但IMO'..'绝不应该是文件系统的概念,而应在路径上通过语法解决,因此a / ..始终表示.. URL的工作方式,顺便说一句。是浏览器在甚至未到达服务器之前就解决了“ ..”。而且效果很好。

– ybungalobill
17/12/26在4:31

#6 楼

在目录上创建硬链接将是不可恢复的。假设我们有:

/dir1
├──this.txt
├──directory
│  └──subfiles
└──etc


我将其硬链接到/dir2

所以/dir2现在还包含所有这些文件和目录br />如果我改变主意该怎么办?我不能只是rmdir /dir2(因为它不是空的)

如果我递归地删除/dir2 ...它也会从/dir1中删除!

编辑:

评论建议通过对rm进行删除来删除目录。但是,非空目录上的rm失败,并且无论目录是否为硬链接,都必须保留此行为。因此,您不能仅通过rm取消链接。这将需要给rm一个新的参数,只是说“如果目录inode的引用计数大于1,则仅取消链接目录”。 :这意味着删除我刚刚创建的目录硬链接与删除普通文件硬链接不一样...

我将改写我的句子:
没有进一步的开发,创建硬链接将是不可恢复的(因为没有当前命令可以在不与当前行为不一致的情况下处理删除操作)

如果我们允许更多开发来处理这种情况,那么陷阱的数量和数据丢失的风险“这种发展意味着,还不够了解系统的工作方式,恕我直言,这是限制目录上硬链接的充分理由。

评论


那应该不成问题。对于您的情况,当我们创建到dir2的硬链接时,我们必须建立到dir1中所有内容的硬链接,因此,如果我们重命名或删除dir2,则只会删除指向inode的额外链接。而且这不会影响dir1及其内容,因为到inode的链接至少为一个(dir1)。

–坎南·莫汉(Kannan Mohan)
2014年9月17日下午13:20

您的说法不正确。您只需取消链接即可,而不需要rm -rf。如果链接计数达到0,则系统将知道它也可以删除所有内容。

– LtWorf
17年6月12日在12:55

无论如何,这几乎是所有rm所要做的(取消链接)。请参阅:unix.stackexchange.com/questions/151951/…这确实不是问题,与硬链接文件相比,这不成问题。取消链接只会删除命名的引用,并减少链接数。 rmdir不会删除非空目录的事实无关紧要-dir1也不会这样做。硬链接不是数据的副本,它们是相同的实际文件,因此实际上“删除” dir2文件将删除dir1的目录列表。您将始终需要取消链接。

– BryKKan
19年7月11日在0:49

您不能像普通文件一样直接取消链接,因为如果目录中的rm不为空,则不会取消链接。请参阅编辑。

– Pierre-Olivier Vares
19年7月12日在7:16

#7 楼

这是一个很好的解释。关于“多名父母中的哪一位应该..指向?”一种解决方案是使进程维护其完整的wd路径,无论是inode还是字符串。因为可以更改名称,所以inode会更健壮。至少在过去,每个打开的文件都有一个内核内索引节点,每当打开文件时该索引节点就增加,而在关闭时减少。当它达到零时,它和它指向的存储将被释放。当该文件不再由任何人打开时,它将被丢弃(核心副本)。如果子目录位于另一个进程的路径中时,如果某个其他进程将目录移动到另一个目录,则这将使路径保持有效。与删除打开文件的方式类似,但是只是从目录中删除了该文件,但是对于打开该文件的任何进程仍然是打开的。 ,至少是V6和V7,不了解Berkeley或更高版本。不需要标志。你能做循环吗?是的,不要那样做。很明显,如果进行循环,您在做什么。如果您的另一端方便地挂在舱壁的钩子上,那么当您等待跳下飞机时,也不要在脖子上打结。

我希望的是今天要做的是将lhome硬链接到home,这样无论是否用home的automout覆盖了/ home,我都可以使用/ home / administ,该automount具有一个名为administ的符号链接到/ lhome / administ。这使我拥有一个无论我的主home文件系统处于何种状态都可以运行的管理帐户。这是针对Linux的实验,但是我认为一次学习基于UCB的SunOS的自动挂载是在ascii字符串级别完成的。很难看到如何将它们作为其他任意FS之上的一层来完成。

我在其他地方读过。和..也不再是目录中的文件。我确信所有这些都是有充分理由的,并且由于这些原因,我们喜欢的很多东西(例如能够挂载NTFS)都是可能的,但是UNIX的某些优雅之处在于实现。这种优雅所提供的正是诸如通用性和可延展性之类的好处,使它如此坚固并且可以承受四十年。当我们放弃优雅的实现时,它最终将变得像Windows(我希望我错了!)。然后有人会基于优雅的原则创建一个新的操作系统。需要考虑的事情。也许我错了,我(显然)不熟悉当前的实现。令人惊奇的是,大多数情况下,对Linux已有30年的了解了...

评论


我认为,尽管我可能错了,但是。和..在现代文件系统中不是文件系统中的硬链接。但是,文件系统驱动程序会伪造它们。这些文件系统停止了硬链接目录。对于旧文件系统,这是可能的(但很危险)。要执行您要尝试的操作,请查看mount --bind,另请参阅mount --make…,也许还有容器。

–ctrl-alt-delor
16-2-23在23:03

#8 楼

据我所知,主要原因是能够更改目录名称而不弄乱正在运行的程序的过程,这些程序使用其工作目录来引用其他文件,这很有用。假设您使用Wine运行~/.newwineprefix/drive_c/Program Files/Firefox/Firefox.exe,而您想将整个前缀移到~/.wine。如果Firefox由于某种奇怪的原因通过引用drive_c/windows访问../../windows,则重命名~/.newwineprefix会破坏..的实现,该实现会将父目录作为文本字符串而不是inode进行跟踪。父目录必须比试图跟踪每个路径(包括文本字符串和一系列inode)要简单。

另一个原因是行为不当的应用程序可能能够创建循环。行为正常的应用程序应该能够检查要移动的目录的inode是否与要移动到的任何嵌套目录的inode相同,就像您不能将目录移动到它本身一样,但这可能不强制执行在文件系统级别。

但是,另一个原因可能是,如果您可以硬链接目录,那么您将希望防止硬链接无法修改的目录。 find具有安全方面的考虑,因为它用于从临时目录中清除其他用户创建的文件,如果在find调用另一个命令时用户为符号链接切换了真实目录,这可能会引起问题。能够硬链接重要目录将迫使管理员向find添加额外的测试,以免影响它们。 (好的,您已经不能对文件执行此操作,因此此原因无效。)

另一个原因是,在文件系统损坏或损坏的情况下,存储父目录的inode可能会提供额外的冗余。如果您想让..列出所有与此目录硬链接的父目录,那么如果当前目录被取消链接,则可以轻松找到一个不同的任意父目录,不仅违反了硬链接相等的想法,还必须更改方式文件系统存储并使用inode。让程序将路径视为一系列目录索引节点(每个硬链接唯一)可以避免这种情况,但是如果文件系统损坏,您将不会获得冗余。