为什么目录不支持硬链接?

引言

在大概去年十二月中旬的时候刘裕基学弟问了我这个问题,很遗憾当时并没有给出一个令人信服的解释,实在是愧疚不已。在鸟哥那本书上给出的原因说实话是有些让人迷惑的,因为书在实验室,我依稀记着书上给出的原因是如果目录要创建硬连接的话就需要在目录中的每一项上进行硬链接(可能记错了,等到学校再作修改)。说实话在我大一时看到这个书上的这个解释的时候非常疑惑,因为如果我们创建了一个指向目录的硬连接,事实上这个时候它们指向的文件控制块(FCB),也就是我们所说的inode(其实也就是盘块号)是相同的,意味着目录下的修改肯定是同步的,因为指向的磁盘都是一样的,为什么又要在目录中的每一项上进行硬链接呢?在搞懂这个问题以后进行记录,希望20届及以后的学弟学妹们可以在十二月就清楚这个问题。

硬链接与符号链接

在很多地方我们会知道一个inode的概念,其实它本质上就是一个盘块的逻辑号,也就是数据在磁盘中真正存储的地方。为了检索时的高效,把文件名和其他的文件信息进行区分,其他的文件信息存储在一个盘块中(当然这个盘块会对数据盘块进行索引)。
在这里插入图片描述
举个简单的例子,如果盘块大小1KB,文件目录有3200个文件目录项,也就是静态信息所占的盘块,在引入索引之前这些都是存储在盘块中的假设盘块大小1K,文件目录项64B,那么文件的所有目录信息需要3200*64/1K = 200个盘块,所以查找一个文件平均查询盘块数为(1+200)/2 = 100.5 个磁盘。

但是在我们引入索引节点以后呢?文件名最长14B,索引结点编号为2B,那么文件的目录项实际只需要 3200*16/1K = 50 个盘块,所以查找一个文件平均查询盘块数为(1+50)/2 = 25.5 + 1 个磁盘,加1是因为我们还需要拿到文件的控制信息,25.5只是得到了盘块信息。

所以在目录项中查找数据的时候是根据文件名来查询盘块号的。硬连接的原理就是把两个文件的索引结点编号设置成一样即可。所以硬链接文件看起来其实是非常正常的一个文件,除了链接数不一样以外它和一般文件没有任何区别。

 lizhaolong@lizhaolong-PC  ~/Desktop:  vi hello        
 lizhaolong@lizhaolong-PC  ~/Desktop:  ln hello link  
 lizhaolong@lizhaolong-PC  ~/Desktop:  l 
-rw-r--r--  2 lizhaolong lizhaolong   24 5月  27 11:57  hello
-rw-r--r--  2 lizhaolong lizhaolong   24 5月  27 11:57  link

然而我们知道符号链接是可以链接目录的,本质的原因就是符号链接是一个特殊的文件,其中存放着所连接地址的路径名。

 lizhaolong@lizhaolong-PC  ~/Desktop: ln -s hello slink                                     
 lizhaolong@lizhaolong-PC  ~/Desktop: l  
 lrwxrwxrwx  1 lizhaolong lizhaolong    5 5月  27 11:59  slink -> hello
 -rw-r--r--  2 lizhaolong lizhaolong   24 5月  27 11:57  hello

我们可以看到slink中文件大小为5,正好是hello的长度,hello中则是本身的内容长度。

为什么目录不支持硬链接

那么为什么目录不支持硬链接呢?原因就是允许目录的硬链接可能会打破文件系统目录的有向无环图结构,可能创建目录循环,这可能会导致fsck以及其他一些遍历文件树的软件出错。这可能会出现一种你的父目录是你的子目录这种及其奇怪的事情出现,其实就是硬链接以后的目录可能是你的父目录,这导致很多遍历系统的命令如果不跟踪inode的话就没办法用了,因为可能会导致无限循环,比如du,ls -r, pwd等。

对应的,为什么符号链接没有这样的限制呢?原因出现在lstat和stat这两个函数上,stat与lstat的区别就是lstat返回的是符号链接文件本身的信息,而不是它指向的文件的信息,stat返回指向文件的信息,这意味着在遍历的时候采用lstat就不会出现环路从而导致死循环。

当然你非要这样也可以,就是把一个目录挂载到另一个目录上,可以使用“ mount -o bind /dir1 /dir2 ” 将dir1挂载到dir2上,从而达到与对目录硬链接一样的效果,只不过这个命令要求dir1和dir2都必须存在。

总结

当然,个人认为如果能够在遍历的过程中记录inode,比如记录所有已遍历的inode,如果出现重复则证明出现了硬链接的目录,则跳过这个目录项,就是这个树上的环路只走一遍(当然有环就不是树了),这样也是可以的,没有出现的原因可能是目录支持硬链接的意义和遍历的开销之间的一个权衡吧。以上就是我对于这个问题的看法。

参考:

posted @ 2022-07-02 13:17  李兆龙的博客  阅读(198)  评论(0编辑  收藏  举报