linux 硬鏈接和軟連接(符號連接) 原理

linux 文件存儲原理

在linux系統中,文件存儲被分爲兩部分,用戶數據和元數據。
用戶數據,即文件數據塊,是記錄文件真實內容的地方。
元數據則是文件的附加屬性,如文件大小、創建時間、所有者等信息。
inode號(即索引節點號)是元數據的一部分,是文件的唯一標緻。
這裏要區分文件名和inode號的區別。文件名是爲了方便用戶記憶和使用,而系統是通過inode號尋找正確的文件數據塊。

在這裏插入圖片描述
我們可以改通過 stat 查看文件的inode號

[user_00@localhost ~/d1]$ ls
f1  f2  f3
[user_00@localhost ~/d1]$ stat f1
  File: ‘f1’
  Size: 18        	Blocks: 8          IO Block: 4096   regular file
Device: fd02h/64770d	Inode: 805903006   Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/ user_00)   Gid: (  100/   users)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2020-06-11 16:42:05.119863677 +0800
Modify: 2020-06-11 16:41:58.862863004 +0800
Change: 2020-06-12 16:48:12.425140189 +0800
 Birth: -
[user_00@localhost ~/d1]$

可以看到 f1 的 Inode 號是 805903006。
那按照上面的原理,我們重命名文件,或者移動文件的話,inode號和用戶數據是不會變的。

[user_00@localhost ~/d1]$ mv f1 ../f1.new
[user_00@localhost ~/d1]$ stat ../f1.new
  File: ‘../f1.new’
  Size: 18        	Blocks: 8          IO Block: 4096   regular file
Device: fd02h/64770d	Inode: 805903006   Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/ user_00)   Gid: (  100/   users)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2020-06-11 16:42:05.119863677 +0800
Modify: 2020-06-11 16:41:58.862863004 +0800
Change: 2020-06-12 16:53:45.688176047 +0800
 Birth: -

我們可以看到 Inode 沒有變,也就是說用戶數據的地址是沒變的。只有文件目錄地址和文件名發生了變化。

硬連接和軟連接

爲了解決文件共享的問題,linux引入了兩種連接方式,硬鏈接(hard link)和軟連接(symbolic link 又稱符號連接)。一個inode號對應多個文件的時候,這些文件就稱爲硬連接。或者說硬鏈接就是一個文件同時有多個文件名。

硬連接

[user_00@localhost ~/d1]$ ln f1 f1.hlink
[user_00@localhost ~/d1]$ ls
f1  f1.hlink  f2  f3  f4
[user_00@localhost ~/d1]$
[user_00@localhost ~/d1]$ stat f1.hlink
  File: ‘f1.hlink’
  Size: 18        	Blocks: 8          IO Block: 4096   regular file
Device: fd02h/64770d	Inode: 805903006   Links: 2
Access: (0644/-rw-r--r--)  Uid: ( 1000/ user_00)   Gid: (  100/   users)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2020-06-11 16:42:05.119863677 +0800
Modify: 2020-06-11 16:41:58.862863004 +0800
Change: 2020-06-12 17:35:38.830013074 +0800
 Birth: -

可以看到 f1.hlink 的 inode 和 f1的 inode 是一樣的,僅僅是文件名不一樣而已。
由於硬鏈接是兩個文件名對應同一個文件,所以會有一些特性:

  1. 文件有相同的inode和 data block
  2. 只能對已有的文件創建
  3. 刪除一個硬鏈接並不影響其他相同inode號的文件
  4. 硬鏈接只能針對文件創建,不能針對目錄
  5. 不能交叉文件系統創建
[user_00@localhost ~/d1]$ ls -li
total 8
805903006 -rw-r--r--. 2 user_00 users 18 Jun 11 16:41 f1
805903006 -rw-r--r--. 2 user_00 users 18 Jun 11 16:41 f1.hlink
805903007 -rw-r--r--. 1 user_00 users  0 Jun 11 16:30 f2
805878680 -rw-r--r--. 1 user_00 users  0 Jun 11 16:30 f3
805939943 -rw-r--r--. 1 user_00 users  0 Jun 12 17:22 f4

具有相同的inode號


[user_00@localhost ~/d1]$ ln f5 f5.hlink
ln: failed to access ‘f5’: No such file or directory

不能對不存在的文件創建


[user_00@localhost ~]$ ln d1 d1.hlonk
ln: ‘d1’: hard link not allowed for directory

可以看到是不予許爲目錄創建硬鏈接的。基於linux的文件存儲機制,如果我們給目錄創建硬鏈接,系統是檢測不出來的,如果形成目錄環那程序會陷入死循環。
比如 有目錄 d1/a , d2/b b指向d1,a指向d2,那當我們用 find 查找文件的時候,遍歷過程會是 d1/a/b/a/b…陷入無限循環
但是系統裏缺有兩個目錄的硬鏈接,便是 . 和 …

[user_00@localhost ~/d1]$ ls -ail
total 8
805903005 drwxr-xr-x. 2 user_00 users  62 Jun 12 17:35 .
134217792 drwxr-x---. 8 user_00 users 184 Jun 12 17:13 ..

. 和 … 的 inode 號,就是當前目錄和上層目錄的 inode 號


至於爲什麼不能交叉文件系統創建就很容易理解了。inode 在同一個文件系統裏是唯一的,如果誇文件系統,則會出現相同的inode號對應不同 data block 的情況。這肯定是不對的。

軟連接

軟連接和硬連接是完全不同的。
軟連接是一個新的文件,文件的用戶數據塊存放的是原文件的路徑名。
like this
在這裏插入圖片描述
因此軟連接沒有硬連接那麼多限制:

  1. 軟連接有自己的文件權限和屬性
  2. 可對不存在的文件或目錄創建軟鏈接
  3. 軟鏈接可交叉文件系統
  4. 軟鏈接可對文件或目錄創建
  5. 創建軟鏈接時,鏈接計數 i_nlink 不會增加
  6. 刪除軟鏈接並不影響被指向的文件,但若被指向的原文件被刪除,則相關軟連接被稱爲死鏈接(即 dangling link,若被指向路徑文件被重新創建,死鏈接可恢復爲正常的軟鏈接)
[user_00@localhost ~/d1]$ ln -s f1 f1.slink
[user_00@localhost ~/d1]$ ls -l
total 8
-rwxrwxrwx. 2 user_00 users 18 Jun 11 16:41 f1
-rwxrwxrwx. 2 user_00 users 18 Jun 11 16:41 f1.hlink
lrwxrwxrwx. 1 user_00 users  2 Jun 15 11:17 f1.slink -> f1
-rw-r--r--. 1 user_00 users  0 Jun 11 16:30 f2
-rw-r--r--. 1 user_00 users  0 Jun 11 16:30 f3
-rw-r--r--. 1 user_00 users  0 Jun 12 17:22 f4

可以看到 ls 命令下,軟連接是會明確標識出來的。
我們試着修改下軟連接的文件權限

[user_00@localhost ~/d1]$ chmod 600 f1.slink
[user_00@localhost ~/d1]$ ls -l
total 8
-rw-------. 2 user_00 users 18 Jun 11 16:41 f1
-rw-------. 2 user_00 users 18 Jun 11 16:41 f1.hlink
lrwxrwxrwx. 1 user_00 users  2 Jun 15 11:17 f1.slink -> f1
-rw-r--r--. 1 user_00 users  0 Jun 11 16:30 f2
-rw-r--r--. 1 user_00 users  0 Jun 11 16:30 f3
-rw-r--r--. 1 user_00 users  0 Jun 12 17:22 f4

f1 以及自身的硬鏈接 f1.hlink 文件權限都發生了更改,但是身爲軟連接的 f1.slink 依然堅挺,並未改變。


那如果我給一個不存在的文件創建軟連接呢?

[user_00@localhost ~/d1]$ ln -s f5 f5.slink
[user_00@localhost ~/d1]$ ls -l
total 8
-rw-------. 2 user_00 users 18 Jun 11 16:41 f1
-rw-------. 2 user_00 users 18 Jun 11 16:41 f1.hlink
lrwxrwxrwx. 1 user_00 users  2 Jun 15 11:17 f1.slink -> f1
-rw-r--r--. 1 user_00 users  0 Jun 11 16:30 f2
-rw-r--r--. 1 user_00 users  0 Jun 11 16:30 f3
-rw-r--r--. 1 user_00 users  0 Jun 12 17:22 f4
lrwxrwxrwx. 1 user_00 users  2 Jun 15 11:27 f5.slink -> f5
[user_00@localhost ~/d1]$
[user_00@localhost ~/d1]$ cd f5.slink
-bash: cd: f5.slink: No such file or directory
[user_00@localhost ~/d1]$
[user_00@localhost ~/d1]$ cat f5.slink
cat: f5.slink: No such file or directory
[user_00@localhost ~/d1]$

事實上,可以給一個不存在的目錄或者文件創建軟連,但是創建的軟連是死鏈接。但是如果軟連接的指向被重新創建,那它就復活了,恢復爲正常的軟連接。神奇吧。

[user_00@localhost ~/d1]$ ls -l
total 12
-rw-------. 2 user_00 users 18 Jun 11 16:41 f1
-rw-------. 2 user_00 users 18 Jun 11 16:41 f1.hlink
lrwxrwxrwx. 1 user_00 users  2 Jun 15 11:17 f1.slink -> f1
-rw-r--r--. 1 user_00 users  0 Jun 11 16:30 f2
-rw-r--r--. 1 user_00 users  0 Jun 11 16:30 f3
-rw-r--r--. 1 user_00 users  0 Jun 12 17:22 f4
-rw-r--r--. 1 user_00 users 11 Jun 15 11:30 f5
lrwxrwxrwx. 1 user_00 users  2 Jun 15 11:27 f5.slink -> f5
[user_00@localhost ~/d1]$
[user_00@localhost ~/d1]$ cat f5.slink
I am live;

我們重新創建了 f5 ,通過軟連接也可以順利找到 f5。


還有一個問題是,軟連接是否會導致 links 數增加呢。
有興趣的朋友自己思考下吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章