鏈接簡單理解就是,添加一個對文件/文件夾的訪問副本,更方便平時的一些操作。類比Windows的快捷方式。
簡單先看一下符號鏈接與硬鏈接的生成與使用。
生成符號鏈接與硬鏈接
-
創建符號鏈接:ln -s target_file link_file
-
創建硬鏈接:ln target_file link_file
演示:
創建文件的符號鏈接
$ ln -s file1 file_symlink
創建文件的硬鏈接
$ ln file1 file_hardlink
創建文件夾的符號鏈接
$ ln -s link_test_dir dir_symlink
創建文件夾的硬鏈接:創建失敗
$ ln -s link_test_dir dir_hardlink
ln: link_test_dir: hard link not allowed for directory
從上面的流程和截圖的觀察中,可以總結幾點:
- 在表現形式上(ls -alh查看):
- 符號鏈接表現為指向被鏈接文件的形式,硬鏈接表現為單獨的文件。
- 符號鏈接權限為
lrwxrwxrwx.
,硬鏈接權限與源文件一致 - 硬鏈接大小與源文件一致,符號鏈接大小為被鏈接文件的路徑字符長度。
- 硬鏈接不允許創建給目錄,符號鏈接可以。
- 訪問文件:都是源文件的值
做一些操作,再觀察現象:
-
修改權限
-
修改硬鏈接權限
-
修改軟連接權限
-
-
修改屬主
-
修改硬鏈接屬主
-
修改軟連接權限
-
-
刪除源文件后,再訪問符號鏈接和硬鏈接
總結以上情況,我們可以再補充一些符號鏈接跟硬鏈接的特點:
- 訪問符號鏈接和硬鏈接實際都是訪問被鏈接文件;
- 硬鏈接修改權限/屬主時,源文件跟着一起變;符號鏈接修改權限/屬主時,鏈接文件未變化,實際變化的是源文件,且硬鏈接文件的屬性跟着一起變動;
- 源文件被刪除時,硬鏈接文件仍然可以訪問,且與源文件一致;訪問符號鏈接文件時會找不到對象。
按上面的操作,基本可以運用符號鏈接和軟連接。但是留有一些疑問:
- 為什么源文件刪除了,硬鏈接還能正常訪問,而符號鏈接卻失效了?
- 為什么修改符號鏈接的屬主/權限,符號鏈接的屬主/權限卻未變動,變動的是源文件?
- 為什么硬鏈接的所有文件屬性都跟源文件保持一致?
- 為什么硬鏈接不能鏈接給目錄?
要解答這些問題,可以先延伸看下Linux文件系統的管理模式。
Linux文件管理
當我們使用Linux文件系統時,文件系統通常會將文件的兩部分數據分別放在不同的區塊中:權限與屬性放置在inode中,實際數據放置在data block中。另外,還有一個超級區塊 (superblock) 會記錄整個文件系統的整體信息,包括 inode 與 block 的總量、使用量、剩余量等。
每個 inode 與 block 都有編號,這三個數據:
- superblock:記錄所在 filesystem 的整體信息,包括inode/block的總量、使用量、剩余量,以及文件系統的格式與相關信息等;
- inode:記錄文件的屬性,一個文件占用一個inode,同時記錄此文件的數據所在的 block號碼;
- block:實際記錄文件的內容,若文件太大時,會占用多個 block 。
這種數據存取的方法我們稱為索引式文件系統(indexed allocation)
當我們在 Linux 下的文件系統創建一個目錄時,文件系統會分配一個 inode 與至少一塊 block給該目錄。其中,inode 記錄該目錄的相關權限與屬性,並可記錄分配到的那塊 block 號碼;而 block 則是記錄在這個目錄下的文件名與該文件名占用的 inode 號碼數據。
文件尋址過程
整個文件系統的目錄結構就如一個樹狀圖,從根目錄開始,從目錄的inode獲取它的block。從block中獲取子目錄的inode值,持續往下尋址直到找到對應文件。
以上一節的源文件/home/jingx/test_link_dir/file1
為例,文件系統訪問這個文件的流程如下:
- 找到"/"掛載點,獲取root inode。
PS:在往下搜尋的時候,如果有新的掛載點,會重新獲取root inode。當前僅討論簡單情況。
-
通過root inode找到對應block,繼續往下尋找下一個目錄的inode。通過inode獲取文件權限屬性,check當前用戶的操作是否有權限繼續;如果有權限,則通過inode指向的block搜尋下一層,直到搜索到最終文件:home/jingx/test_link_dir/file1。
-
最終找到對應文件的inode,從inode中獲取文件屬性和block號;從block號獲取文件內容。這就是一次完整的文件尋址過程。
硬鏈接實現
從上一節知道了文件的尋址過程。現在來看硬鏈接的具體實現方式:
- 硬鏈接某一個文件時,實際上是在對應父目錄的block中,添加一條 inode:硬鏈接文件名 的記錄。通過
ls -il
命令可以輸出對應文件的inode號。可以看到源文件和硬鏈接文件,其實是同一個inode號
如果硬鏈接文件在其他目錄,也是同樣在對應目錄的block中添加一條指向文件實際inode的記錄。
同時觀察輸出的第三列屬性,因為當前有3個對象指向這個inode,所以這個inode的引用為3。
PS:直到inode引用為0時,這個文件才從文件系統認定被刪除。
所以建立文件的硬鏈接,實際上就是在對應目錄的block中新建一條記錄,並非新增一個文件。
符號鏈接
對比硬鏈接的實現,符號鏈接實際上是一個真實存在的文件。
- 它是一個跟普通文件一樣,存在於硬盤中,有自己的inode編號和block。
-
inode中標明它的文件類型是符號鏈接(權限中的第一位
l
); -
顯示權限為777,但實際權限是跟父目錄及被鏈接對象有關:
-
如果是對符號鏈接本身的操作(刪除或修改指向),則根據操作用戶在父目錄的權限來執行;
-
如果是對符號鏈接指向對象的操作(chmod、chown、cp等),則根據操作用戶在被鏈接對象的權限來執行;
-
-
符號鏈接文件實體內容則只有被鏈接文件的路徑。存儲位置根據鏈接格式(local、extend)有關,在此不贅述;
遺留問題回答
根據上面描述的硬鏈接和符號鏈接的特點,可以回溯文章開始提出的一些問題:
-
為什么源文件刪除了,硬鏈接還能正常訪問,而符號鏈接卻失效了?
因為刪除源文件的操作,實際上是在它父目錄的block中刪掉類似對應的 文件名:inode 的指向。實際的文件內容(inode、block)並沒有刪掉。硬鏈接還可以根據本身的inode號進行文件尋址。而符號鏈接實際保存的是源文件的路徑,所以訪問符號鏈接時候,會根據路徑去尋找文件。而源文件刪除后,該路徑的文件記錄已經不存在了,所以會導致
No such file or directory
。 -
為什么修改符號鏈接的屬主/權限,符號鏈接的屬主/權限卻未變動,變動的是源文件?
因為像chmod/chown等命令做操作的時候,會遞歸的去對最終文件進行操作。所以修改屬主/權限的操作實際是針對源文件的。
因為這個原因,導致了符號鏈接的提權類問題。由於操作、符號鏈接所在目錄、源文件三者的權限不一致,可能導致通過偽造符號鏈接等方式進行提權操作。如果添加"-h"參數,則會在操作的時候忽略符號鏈接文件。以此來防止
-
為什么硬鏈接的所有文件屬性都跟源文件保持一致?
因為硬鏈接文件的inode和源文件的inode是同一個,而inode是存儲文件屬性的位置。
-
為什么硬鏈接不能鏈接給目錄?
為了防止路徑回環。回憶之前說的文件尋址模式,是通過樹狀來進行尋址。假設將/a/b/hardlink_dir鏈接到/a上,由於a和hardlink_dir都是同一個inode,在尋址邏輯上會變成hardlink_dir既是b的子目錄又是b的父目錄(a)。在內核的處理上復雜度變變的更高,所以從使用工具層面上禁止了目錄的硬鏈接。
PS:在系統中實際是存在兩個特殊的硬鏈接,即:
.
和..
。.
指向目錄本身,..
指向父目錄。因為系統對它們做了特殊處理,所以不會有路徑回環的問題發生。 -
補充:硬鏈接也不能跨文件系統進行鏈接,因為尋址模式、inode存儲方式以及superblock在不同的文件系統間是不一樣的。而軟鏈接可以跨文件系統鏈接,因為軟鏈接只存儲被鏈接文件的路徑,根據路徑進行尋址這個是文件系統的共性。
Reference