Linux文件系統中的硬鏈接及常見面試題
如果能對inode的概念有所了解,對理解本文會有所幫助。如果對inode的概念不太清楚也沒有關系,我們會捎帶介紹一下。在文件系統的實現層面,我們可以認為包含兩個組件:一個是包含數據塊的池子,池子中的數據塊是等大小的,比如4KB,8KB等;另外一個是管理這些數據塊的數據庫。當普通用戶訪問文件數據時,正是通過前面所說的數據庫來找到文件對應的數據塊的。
什么是inode
inode是Linux(Unix)操作系統中文件系統的一個概念。inode的全稱為index node,也就是索引節點。那么inode是用來索引什么的呢?其實inode表示的是一個文件,它是用來索引文件數據的。以Ext3文件系統為例,其文件數據通過間接塊的方式來管理,inode通過一個間接塊樹來管理整個文件的數據。

圖1 Ext3間接塊數組組織形式
如圖所示,inode中包含索引信息,通過文件的邏輯地址和inode中的索引信息,可以很方面的找到文件特定位置的數據。關于inode與文件系統的更多知識,大家可以翻閱本號的其它文章,本文不再贅述。
需要注意的是,在inode中并沒有文件名稱相關的信息。文件名稱相關的信息是存儲在目錄當中,在目錄當中有文件名稱與inode ID之間的對應關系,具體如下所示。由于有兩者之間的對應關系,因此可以根據文件名輕松地獲取到inode ID,進而得到inode的信息。

圖2 目錄內數據格式
什么是硬鏈接
文件的硬鏈接是一個指向inode的目錄項。硬鏈接從表面上來說就是一個文件,但是該文件是基于原始文件創建的鏈接文件。硬鏈接與源文件指向相同的inode,因此其數據也是完全一樣的。
相對于硬鏈接,還有一個軟鏈接的概念。軟鏈接是指向一個具體的文件的,而非文件的inode,所以當文件重新命名時,軟鏈接就會失效。因為該軟鏈接原本指向的文件不存在了。而硬鏈接則不會存在這種情況。

假設如圖所示的目錄結構,在目錄Linux中有file1和file2兩個文件。目錄編程語言中有file2文件一個指向目錄linux中file1的硬鏈接。這是在用戶層面的形態,那么在文件系統層面是如何的呢?
在文件系統層面,我們知道文件系統通過一個inode來指示一個文件(包括目錄)的內容。目錄“電子書”的inode ID是15,其內容圖下圖所示,包含Linux,編程語言等子目錄,對應的inode ID分別如圖所示。
對于目錄“Linux”來說,其中包含文件file1和file2,inode ID分別是19和20。目錄“編程語言”的包含文件file2和硬鏈接file1_hlink,可以看出file1的inode ID和硬鏈接file1_hlink的inode ID是相同的,都指向19。inode 19 的內容如下所示。
通過上圖可以看出硬鏈接與源文件的對應關系。
如何在Linux創建一個硬鏈接
前面介紹了很多原理性的內容,那么如何在Linux中創建一個硬鏈接呢?很簡單,通過ln命令即可,如下是創建硬鏈接的命令格式。
- ln target_file link_name
上述命令將為文件target_file創建一個名為link_name的硬鏈接。通過對比你會發現兩者沒有任何差異,包括文件內容和屬性。
如果你通過ls -li命令可以看到,兩個文件的inode ID是相同的(第一列的內容),而文件的計數則是2(rwx權限后面的數字),說明有兩個文件名稱指向該inode。
- 134195 -rw-r--r-- 2 sunnyzhang sunnyzhang 0 Jul 17 19:49 target_file
- 134195 -rw-r--r-- 2 sunnyzhang sunnyzhang 0 Jul 17 19:49 link_name
下面這些知識點在面試中經常遇到
在后端程序員面試過程中經常會遇到鏈接相關的面試題,下面幾個面試題是硬鏈接相關的題目。
如果一個文件有硬鏈接,刪除源文件會怎樣?
如果存在硬鏈接,刪除源文件將不會刪除文件的數據。通過硬鏈接仍然能夠訪問文件的數據。
為什么會出現這種情況?這是因為當有目錄項指向inode的時候,inode會增加引用計數。通常情況下引用計數是1,當有一個硬鏈接時為2,再有一個硬鏈接的時候就變成了3。
當我們刪除普通文件(無硬鏈接)的時候,首先會刪除目錄項中的內容,然后將inode的引用計數減1,如果此時inode中引用計數為0,則刪除該inode,同時刪除相關聯的數據。如果非0,則只刪除目錄項,而不刪除相關內容。所以,如果存在硬鏈接則可以正常訪問文件內容。
為什么沒法為目錄創建硬鏈接?
我們可以為目錄創建一個軟鏈接,但是當我們為目錄創建硬鏈接的時候將會出現如下錯誤提示:
- ln: newdir/test_dir: hard link not allowed for directory
為什么不能為目錄創建硬鏈接呢?這是因為在目錄中除了文件相關內容外,還有一個指向父目錄的目錄項,具體如下圖所示的".."目錄。如果我們在其它目錄創建該目錄的硬鏈接,那么該內容就會被改寫,從而導致混亂。

除了導致目錄數據混亂外,還有一種問題就是會形成路徑環。至于如何形成路徑環本文不再贅述,大家可以自己思考一下。
能否區分源文件與硬鏈接?
實際上并沒有任何信息區分硬鏈接和源文件。如果我們在文件名命名規則上沒有限制,那么我們將無法區分兩者。也就是說,文件本身也是一個硬鏈接。
- 134195 -rw-r--r-- 2 sunnyzhang sunnyzhang 0 Jul 17 19:49 target_file
- 134195 -rw-r--r-- 2 sunnyzhang sunnyzhang 0 Jul 17 19:49 link_target_file
比如上面這個例子,我們可以通過文件名稱來知道哪個是硬鏈接。但是并沒有其它信息進行區分。
如何查找一個文件的硬鏈接?
如果你發現一個文件的引用計數大于1,那么該文件肯定是有硬鏈接的。那么如何找到這個文件的所有硬鏈接呢?其實很簡單,通過find命令就行。find命令有個-inum選項,用于查找指定inode ID的文件,具體如下。
- find . -inum inode_number
今天的內容先到這里。