王繼敏
【摘 要】Linux在其文件系統(tǒng)中引入了鏈接文件用于方便用戶使用和系統(tǒng)管理。本文對(duì)Linux下的鏈接文件的實(shí)質(zhì)、分類、用途進(jìn)行了分析和綜述。
【關(guān)鍵詞】Linux;鏈接文件
0 引言
鏈接文件在Linux的文件系統(tǒng)中扮演重要角色,而其背后又涉及到索引節(jié)點(diǎn)(index node,又稱inode)這一概念。索引節(jié)點(diǎn)是Linux虛擬文件系統(tǒng)(VFS)的基本概念之一。通過剖析鏈接文件的實(shí)質(zhì),理解鏈接文件的分類與區(qū)別,可以讓Linux的普通用戶和管理員正確而有效的使用鏈接文件。
1 幾個(gè)基本概念
要理解Linux下鏈接文件的實(shí)質(zhì),需要先理解索引節(jié)點(diǎn)(inode)和目錄項(xiàng)(dentry)這兩個(gè)基本概念。
在Linux文件系統(tǒng)中,一個(gè)文件除了純數(shù)據(jù)本身之外,還必須包含有對(duì)這些純數(shù)據(jù)的管理信息,如訪問權(quán)限、文件的屬主以及該文件的數(shù)據(jù)所對(duì)應(yīng)的磁盤塊等等,這些管理信息稱之為元數(shù)據(jù)(mata data),保存在文件的inode節(jié)點(diǎn)之中。[1]
每個(gè)inode都有一個(gè)全文件系統(tǒng)唯一的inode號(hào),操作系統(tǒng)內(nèi)核正是通過inode號(hào)而非文件名來識(shí)別不同的文件。文件名僅僅是為了方便用戶使用而已,內(nèi)核是通過文件名找到inode,然后通過inode訪問實(shí)際文件數(shù)據(jù)的。
雖然每個(gè)文件對(duì)應(yīng)了唯一的inode號(hào),但inode號(hào)是雜亂而毫無意義的,不方面用戶記憶和使用,用戶希望對(duì)每個(gè)文件取一個(gè)有意義的文件名。現(xiàn)代文件系統(tǒng)提供的一個(gè)基本功能是按名存取,所以還需要建立文件名到inode號(hào)的對(duì)應(yīng),這就引出了目錄項(xiàng)(directory entry即dentry)的概念。在Linux文件系統(tǒng)中有一類特殊的文件稱為“目錄”,目錄就保存了該目錄下所有文件的文件名到inode號(hào)的對(duì)應(yīng)關(guān)系,這里的每個(gè)對(duì)應(yīng)關(guān)系就稱為一個(gè)dentry。而Linux把所有的文件和目錄構(gòu)建成了一個(gè)倒立的樹狀結(jié)構(gòu),這樣,只要確定了根目錄的inode號(hào),就可以對(duì)整個(gè)文件系統(tǒng)進(jìn)行按名存取了。
2 鏈接文件的分類
Linux下的鏈接文件可以分為硬鏈接和軟鏈接。
硬鏈接的實(shí)質(zhì)是現(xiàn)有文件在目錄樹中的另一個(gè)入口。也就是說,硬鏈接與原文件是分居于不同或相同目錄下的的dentry而已,它們指向同一個(gè)inode,對(duì)應(yīng)于相同的磁盤數(shù)據(jù)塊(data block),具有相同的訪問權(quán)限、屬性等。[2]簡(jiǎn)而言之,硬鏈接其實(shí)就是給現(xiàn)有的文件起了一個(gè)別名。如果把文件系統(tǒng)比喻成一本書的話,硬鏈接就是在書本的目錄中,有兩個(gè)目錄項(xiàng)指向了同一頁(yè)碼的同一章節(jié)。
硬鏈接的優(yōu)點(diǎn)是幾乎不占磁盤空間(因?yàn)閮H僅是增加了一個(gè)目錄項(xiàng)而已),但是這一優(yōu)點(diǎn)相對(duì)于軟鏈接其實(shí)并不明顯(因?yàn)檐涙溄诱加玫拇疟P空間也很少)。另外,硬鏈接有以下一些局限:1)不能跨文件系統(tǒng)創(chuàng)建硬鏈接。原因很簡(jiǎn)單,inode號(hào)只有在一個(gè)文件系統(tǒng)內(nèi)才能保證是唯一的,如果跨越文件系統(tǒng)則inode號(hào)就可能重復(fù)。2)不能對(duì)目錄創(chuàng)建硬鏈接。原因我在稍后解釋。正因?yàn)橛叉溄拥倪@些局限,加之軟鏈接更加易于管理,所以軟鏈接更加常用。
軟鏈接又稱為符號(hào)鏈接(symbolic link),簡(jiǎn)寫為“symlink”。與硬鏈接僅僅是一個(gè)目錄項(xiàng)不同,軟連接實(shí)質(zhì)上本身也是個(gè)文件,不過這個(gè)文件的內(nèi)容是另一個(gè)文件名的指針。當(dāng)Linux訪問軟鏈接時(shí),它會(huì)循著指針找出含有實(shí)際數(shù)據(jù)的目標(biāo)文件。同樣用書本來打個(gè)比方,軟鏈接是書本里的某一章節(jié),不過這一章節(jié)什么內(nèi)容都沒有,只有一行字“轉(zhuǎn)某某章某某頁(yè)”。
3 兩種鏈接文件的區(qū)別
軟鏈接可以跨越文件系統(tǒng)指向另一個(gè)分區(qū)的文件,甚至可以跨越主機(jī)指向遠(yuǎn)程主機(jī)的一個(gè)文件,也可以指向目錄。當(dāng)創(chuàng)建了一個(gè)軟鏈接文件后,它的權(quán)限為777,即所有權(quán)限都是開放的,實(shí)際上你也無法使用chmod命令修改其權(quán)限,但是實(shí)際文件的保護(hù)權(quán)限仍然起作用。
軟鏈接還可以指向不存在的文件(可能是原來指向的文件被刪除了,或者指向的文件系統(tǒng)尚未掛載,或者最初建立該符號(hào)鏈接的時(shí)候就指向了一個(gè)不存在的文件等等),此時(shí)稱這種狀態(tài)為“斷裂”(broken)。與之相對(duì)的是,硬鏈接是不能指向一個(gè)不存在的文件的。
另外,在Linux上創(chuàng)建一個(gè)指向目錄的軟鏈接是允許的,但是卻不能創(chuàng)建一個(gè)指向目錄的硬鏈接。其實(shí)在UNIX操作系統(tǒng)的歷史上,對(duì)目錄創(chuàng)建硬鏈接曾經(jīng)是允許的。但人們發(fā)現(xiàn),這樣做會(huì)出現(xiàn)很多問題,尤其是一些對(duì)目錄樹進(jìn)行遍歷操作的如fsck、find等命令無法正確執(zhí)行。在《Unix高級(jí)環(huán)境編程》中提到作者Steven在自己的系統(tǒng)上做過實(shí)驗(yàn),結(jié)果是:創(chuàng)建目錄硬鏈接后,文件系統(tǒng)變得錯(cuò)誤百出。因?yàn)檫@樣做會(huì)破壞文件系統(tǒng)的樹形結(jié)構(gòu),可能會(huì)使目錄之間出現(xiàn)環(huán)。
為什么軟鏈接可以指向目錄而硬鏈接不行呢?根本原因在于軟鏈接實(shí)質(zhì)上是一個(gè)文件,而硬鏈接實(shí)質(zhì)上是一個(gè)目錄項(xiàng)(dentry)。在linux系統(tǒng)中,每個(gè)文件(目錄也是文件,軟鏈接也是文件)都對(duì)應(yīng)著一個(gè)inode結(jié)構(gòu),其中inode數(shù)據(jù)結(jié)構(gòu)中包含了文件類型(目錄,普通文件,符號(hào)連接文件等等)的信息,也就是說操作系統(tǒng)在遍歷目錄時(shí)可以判斷出符號(hào)連接。既然可以判斷出符號(hào)連接當(dāng)然就可以采取一些措施來防范進(jìn)入死循環(huán)了,系統(tǒng)在連續(xù)遇到8個(gè)符號(hào)連接后就停止遍歷,這就是為什么對(duì)目錄符號(hào)連接不會(huì)進(jìn)入死循環(huán)的原因了。而“硬鏈接”本質(zhì)上是“目錄項(xiàng)”的同義詞。當(dāng)一個(gè)目標(biāo)第一次被創(chuàng)建,就會(huì)為它創(chuàng)建一個(gè)目錄項(xiàng),這其實(shí)就是硬鏈接。大多數(shù)人常常把“硬鏈接”聯(lián)想成為一個(gè)已有的對(duì)象創(chuàng)建一個(gè)額外的目錄項(xiàng),但其實(shí)是原來的目錄項(xiàng)沒有任何特殊,所有的硬鏈接都是平等的,所以Linux內(nèi)核沒有方法能識(shí)別出哪個(gè)是“原文件”哪個(gè)是“硬鏈接”。這樣對(duì)于由于目錄硬鏈接而形成的環(huán)就無法進(jìn)行合適的處理。
4 鏈接文件的用途
合理的使用鏈接文件,會(huì)對(duì)日常使用和系統(tǒng)管理帶來一些便利,主要包括以下幾方面。
1)保持軟件的兼容性
例如,在很多Linux發(fā)行版中,/bin/sh文件其實(shí)是一個(gè)指向/bin/bash的符號(hào)鏈接。為什么要這樣設(shè)計(jì)?因?yàn)閹缀跛械膕hell script的第一行都是“#!/bin/sh”,“#!”符號(hào)表示該行指定該腳本所用的解釋器。#!/bin/sh表示使用Bourne Shell作為解釋器,這是一個(gè)早期的Shell。在現(xiàn)代的Linux發(fā)行版中通常采用Bourne Again Shell即bash,bash是對(duì)sh的改進(jìn)和增強(qiáng),而早期的Bourne Shell在系統(tǒng)的中根本不存在。為了能夠順利的運(yùn)行腳本而不必修改shell script,只需要?jiǎng)?chuàng)建一個(gè)軟鏈接/bin/sh讓其指向/bin/bash。如此一來,就可以讓bash來解釋原本針對(duì)Bourne Shell編寫的腳本了。
2)方便軟件的使用
比如安裝了一個(gè)大型軟件Matlab,它可能默認(rèn)安裝在/usr/opt/Matlab目錄下,它的可執(zhí)行文件位置在/usr/opt/Matlab/bin目錄下,除非你在這個(gè)路徑加入到PATH環(huán)境變量里,否則每次運(yùn)行這個(gè)軟件你都需要輸入一長(zhǎng)串的路徑很不方便。此時(shí)可以通過在“~/bin”下創(chuàng)建一個(gè)符號(hào)鏈接,今后在命令行下無需輸入完整路徑,只需輸入matlab即可。
3)維持舊的操作習(xí)慣
比如在SuSE中,啟動(dòng)腳本的位置是放在/etc/init.d目錄下,而在RedHat的發(fā)行版中,是放在/etc/init.d/rc.d目錄下。為了避免因?yàn)閺腟uSE轉(zhuǎn)換到RedHat系統(tǒng)而導(dǎo)致管理員找不到位置的情況,可以創(chuàng)建一個(gè)符號(hào)鏈接/etc/init.d使其指向/etc/init.d/rc.d即可。[3]事實(shí)上,RedHat發(fā)行版也正是這樣做的。
4)方便系統(tǒng)管理
在/etc/rc.d/rcX.d目錄下的符號(hào)鏈接(X為0~7數(shù)字)是一個(gè)非常典型的例子。在init.d/目錄下有許多用于啟動(dòng)、停止系統(tǒng)服務(wù)的腳本,如sshd、crond等。這些腳本可以接受一個(gè)參數(shù),代表要啟動(dòng)(start)或停止(stop)服務(wù)。為了決定在某個(gè)運(yùn)行級(jí)別運(yùn)行哪些腳本及傳遞給這些腳本哪些參數(shù),RedHat設(shè)計(jì)了一個(gè)額外的目錄機(jī)制,即rc0.d到rc6.d的7個(gè)目錄,每個(gè)目錄對(duì)應(yīng)一個(gè)運(yùn)行級(jí)別。如果在某運(yùn)行級(jí)別下需要啟動(dòng)某服務(wù)或者需要停止某服務(wù),就在對(duì)應(yīng)的rcX.d目錄下建立一個(gè)符號(hào)鏈接,指向init.d/目錄下的腳本。
5 結(jié)束語
通過闡述鏈接文件背后的索引節(jié)點(diǎn)、目錄項(xiàng)等與文件系統(tǒng)設(shè)計(jì)相關(guān)基本概念,分析了硬鏈接及軟鏈接文件的實(shí)質(zhì),并對(duì)使用鏈接文件的作用進(jìn)行了綜述。
【參考文獻(xiàn)】
[1]鳥哥.鳥哥的Linux私房菜基礎(chǔ)學(xué)習(xí)篇[M].3版.北京:人民郵電出版社,2010: 199-203.
[2]王紅.Linux文件系統(tǒng)結(jié)構(gòu)分析[J].濰坊學(xué)院學(xué)報(bào),2011(2):29-31.
[3]Jeffrey Dean.LPI Linux認(rèn)證權(quán)威指南[M].2版.南京:東南大學(xué)出版社,2007:209-210.
[責(zé)任編輯:田吉捷]