Linux的初学者常常混淆Linux中的硬链接(hard link)与符号链接(symbol link)的概念,分不清楚它们的区别。因此,本文将向读者全面介绍硬链接与符号链接,给予读者以全面的认识。
1.Linux下的文件系统
1.1 Ext2文件系统结构
为了能够从本质上理解硬链接与符号链接,我们必须要对Linux下的文件系统有一定的认识。这一小节将向读者简要地介绍Linux下的文件系统(以Ext2文件系统为例)知识作为背景。
Ext文件系统是对minix文件系统的扩展,而Ext2文件系统是第二代扩展文件系统。磁盘分区大小可达4TB,磁盘布局采用了组块。
上图是Ext2文件系统结构示意图。其中:
Boot Block:每个硬盘分区开头的第一个块为分区的启动块。这个块不受Ext2文件系统管理,为分区的引导扇区所保留。
一个Ext2硬盘可以有许多个组块。每一个组块都可以看作一个分区。每一个分区由超级块、组描述符、数据块位图、inode位图、inode表以及数据块组成。
Super Block:超级块。Block Group 0中的Super Block被内核所使用,定义了诸如文件系统的静态结构,包括块的大小、总块数、每组内inode数、空闲块、索引结点数等全局信息。其他Block Group中的Super Block仅仅是Block Group 0中Super Block的一个拷贝。Linux启动时,Block Group 0中的Super Block的内容会被读入到内存中,如果某个Block Group损坏时,可以用其进行恢复。
Group Descriptors:组描述符。组描述符记录了块位图(Data Block Bitmap)所在块的块号,inode位图(inode Bitmap)所在块的块号,inode表(inode Table)所在块的起始块号,本组空闲块的个数等组内信息。文件系统根据这些信息来查找数据块位图,索引结点位图,索引结点表的位置。
Data Block Bitmap:Ext2文件系统的数据块位图。这是Ext2管理存储空间的方法,即位图法。Data Block Bitmap中每一位对应了一个数据块,某一位上位0时表示该位所对应的数据块空闲,反之为1时,表示该位所对应的数据块已经被分配。Data Block Bitmap占了1个块的空间,因此,一个组中的数据块的个数就已经决定了。如果每个块为b-byte,那么该Group Block就有8*b个块,可以存放(8*b)*b字节的数据。
inode Bitmap与inode Table:inode Bitmap的作用于Data Block Bitmap差不多,但Data Block Bitmap索引的是数据块。而inode Bitmap索引的则是inode Table中的inode结点。每一个inode都是一个数据结构,其大小为128字节。每一个inode对应一个文件(包括了目录),包含了有关该文件的除了文件名,文件类型之外的所有属性,例如访问权限,文件创建时间,访问时间,修改时间,文件所占的数据块的个数,指向数据块的指针,该inode被引用的个数(这个十分重要!)等等。
Data Block:数据块存放文件的实际内容。需要特别指出的是,在Linux下目录也是一种文件。目录中的文件及子目录都以目录项(directory entry)的形式存放在该目录的数据块中。目录项中主要记录了文件的inode号,文件名以及文件类型等内容。
1.2 一个简单的示例
在前面已经简单地介绍了必要的Ext2文件系统知识。可能有些读者还有一些困惑。下面我用一个具体的实例来看一下再Ext2文件系统下如何找到某一个文件,以便对前一小节所讲的内容有形象的认识。
以定位“/xjtu/chenny”文件为例。通过Super Block中的根目录inode号,我们可以在文件系统被挂载时就能得到其根目录结点。假设根目录“/”在inode 0中(实际上,在Ext2文件系统中,根目录的inode值为2,为了示例简单,假设其inode为0)。文件系统首先读取inode 0(“/”),获得它的数据块指针(指向数据块3),然后读取数据块3的内容。数据块3中存放的是3个目录项:
“.”当前目录,inode为0;
“..”父目录,inode为0;
“xjtu”子目录,inode为43。
按照前面指示的路径中的“xjtu”分量,读取inode 43的内容,然后获取它的数据块指针,为6,然后再访问数据块6,读取其内容。xjtu包含了3个文件:
“.”当前目录,inode为43;
“..”父目录,inode为0;
“chenny”子文件,inode为55;
接下来就访问inode 55,读取其inode内容,直接访问其数据块11,数据块11中包含了它的内容,为文本“Hello!”。
2.硬链接(hard link)
所谓的硬链接,为某个文件创建另外一个可供访问的“别名”。Linux中的link函数提供了这一功能。需要注意的是,如果是为目录创建硬链接,则需要具有superuser权限。这是因为,为目录创建硬链接会引起文件系统中的循环访问,在这种情况下,许多Linux组件无法正常工作。同时,在许多Linux操作系统中,硬链接都要求文件以及硬链接处于同一文件系统中。
2.1 硬链接的本质
为一个文件创建硬链接,这个文件也就有了一个“别名”,可以通过另外的路径来访问到这个文件,这个“别名”是货真价实的。
创建硬链接,首先是在“别名”所在的目录,新建一个目录项,用来标示这个别名。然后,这个目录项中,指向的inode就是原文件的inode,文件名即是设置的新的那个“别名”。例如,我们在为/xjtu/chenny创建一个硬链接/chenny1。依然依照上面的那个例子,新的布局为:
我们需要注意的是,在inode中,有一个域是用来记录该inode被引用的次数。创建一个硬链接就会使该文件所对应的inode结点的link number增加1。这个域的作用显而易见。当我们要删除某个文件时,实际上只是减少了它的link number。当link number为0时,操作系统才真正地删除该文件的内容。否则,如果无视link number,直接删除文件,则会造成想不到的问题。例如上例中,如果我们删除了/xjtu/chenny文件,那么/chenny1也就会访问错误。真实的情况是,当删除/xjtu/chenny文件时,inode 55的link number减1,此时我们通过/chenny1,仍然可以访问到该文件的内容。但是当我们再删除掉/chenny1时,由于inode 55的link number减1之后变成了0,此时,inode 55会被真正删除。
3.符号链接(symbol link)
Linux文件系统下的另外一种常用链接是符号链接(symbol link),它的使用以及本质都有别于硬链接。我们可以使用ln –s命令来为某一文件创建一个符号链接。有一点与硬链接不同的是,符号链接允许对目录进行链接。
3.1符号链接的本质
创建符号链接的操作是:首先创建一文件,文件的路径即是“别名”的路径。这个创建,是需要为“别名”分配一个inode结点,并为其分配相应的data block,而其data block内存放的内容是被链接文件的路径。之后,为“别名”所在的父目录创建一个目录项,该目录项指示了该别名的内容。我们同样以上面的例子做示例。为/xjtu/chenny创建一个符号链接/chenny2:
在我的博文http://www.cnblogs.com/XjChenny/archive/2012/12/10/2811995.html中,也提及了符号链接st_size大小的问题,从这里,我们就可以得到对于该问题的解答。符号链接并没有将“别名”的inode结点指向原文件,而是新创建了一个符号链接文件,这也就允许了我们可以使用符号链接,链接一个不存在的文件或者目录而没有任何问题。这样的情形,对于硬链接确实不行的,硬链接要求必须链接到已存在的文件,这也是可以理解的,因为硬链接的目录项指向的inode是原文件的inode,原文件必须存在(即已分配inode)才可以。
End。由于本博文是根据《UNIX环境高级编程》相关内容,并参考本人本科时所做的操作系统专题实验中“Ext2文件系统模拟实现”相关内容所写,关于Ext2文件系统的叙述,可能与真实的Ext2文件系统有所出入,但对于基本原理的阐述应该无误。并且对硬链接与符号链接的实现机制也是准确无误的。
硬链接与符号链接是独立于具体的文件系统的,在本文中,也只是方便,采用了Ext2文件系统的布局进行了示例,以便对硬链接与符号链接有形象的认识。如果需要准确详细地了解Ext2文件系统,请查阅其他文档。但如要了解硬链接与符号链接,本文值得一读。
写作仓促,可能存在错误,欢迎指出,并相互交流。
作者:Chenny Chen
出处:http://www.cnblogs.com/XjChenny/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。