引言:
執行如下指令時,
顯示内容:
表明這是一個連結檔案,通過連結可以實作對一個檔案從不同路徑對它進行引用。對于檔案的連結有硬連結和軟連接配接(即符号連結)之分。shell中的ln指令可以建立一個檔案的硬連結,加上-s選項可以建立一個檔案的軟連結。要想深入的了解檔案連結的概念,必須先明白檔案系統的基本結構以及i節點和指向i節點的目錄項之間的差別。是以,先要對檔案系統的基本結構做下了解,然後分别深入了解檔案的硬連結與軟連接配接。最後,了解一下檔案的修改時間。
(一):檔案系統的基本結構
每個磁盤可以分成一個或多個分區,每個分區可以包含一個檔案系統。檔案系統的基本結構如下圖:

其中i結點是固定長度的記錄項,它包含有關檔案的大部分資訊。
比較詳細的柱面組的i結點和資料塊部分如下圖:
首先,目錄、目錄項、索引節點的關系是:
一個目錄檔案包含了一組目錄項,目錄項放在資料塊中。一個目錄項主要包括檔案名和索引節點号,索引節點号是指向索引節點表中對應的索引節點的。也可這樣了解目錄項:因為目錄可以包含子目錄,目錄是可以層層嵌套的,是以形成檔案路徑,而檔案路徑中的每一部分就是所謂的目錄項。索引節點是檔案系統處理檔案所需要的所有資訊都存放在稱為索引節點的資料結構中。主要就是檔案的屬性,包括連結數、檔案所有者、檔案建立和修改時間,檔案在磁盤的位置,檔案大小,使用權限等。
對于上面的兩圖,應注意以下幾點:
1、在圖中有兩個目錄項指向同一i節點。每個i節點中都有一個連結計數,其值是指向該i節點的目錄項數。隻有當連結計數減小至0時,才可删除該檔案(即釋放該檔案占用的磁盤塊)。這就是為什麼“解除一個檔案的連結”操作并不總是意味着“釋放該檔案占用的磁盤塊”的原因。這也是為什麼删除一個目錄項的函數被稱為unlink而不是delete的原因。在stat結構中,連結計數包含在st_nlik成員中,這種連結類型稱為硬連結。
2、另外一種連結類型稱為符号連結。對于這種連結,該檔案的實際内容(在資料塊中)包含了該符号連結所指向的檔案的名字。
3、i節點包含了大多數與檔案有關的資訊:檔案類型、檔案通路權限位、檔案長度和指向該檔案所占用的資料塊的指針等等。stat結構中的大多數資訊都取自i節點。隻有兩項資料存放在目錄項中:檔案名和i節點編号。
4、每個檔案系統各自對它們的i節點進行編号,是以目錄項中的i節點編号數指向同一檔案系統中的相應i節點,不能使一個目錄項指向另一個檔案系統的i節點。這就是為什麼ln指令不能跨越檔案系統的原因。
5、當在不更換檔案系統情況下為一個檔案更名時,該檔案的實際内容并未移動,隻需要構造一個指向現有i節點的新目錄項,并解除與舊目錄項的連結。
(二)link、unlink、remove、rename函數
上面的函數都是針對硬連結進行操作的。關于硬連結,應該注意一下幾點:
1、建立硬連結時,一定要在同一檔案系統内執行。
2、對于目錄,通常的檔案系統實作不允許建立硬連結,即使能夠建立,也僅限于超級使用者才能這樣做。
3、删除目錄項時pathname時,會使的pathname所引用檔案的連結計數減1。如果還有指向該檔案的其他連結,則仍可通過其他連結通路該檔案的資料。
4、為了解除對檔案的連結,必須對包含該目錄項的目錄具有寫權限和執行權限。
5、隻有當連結計數達到0時,該檔案的内容才可能被删除。另一個阻止删除檔案的條件是有程序打開該檔案,其内容也不能被删除。關閉一個檔案時,核心首先檢視打開該檔案的程序數,如果該數達到0,然後核心檢查其連結數,如果這個數也是0,那麼就删除該檔案的内容。
#include <unistd.h>
int link(const char *oldpath, const char *newpath); // 若成功則傳回0, 若出錯則傳回-1。
此函數建立一個新目錄項newpath,它引用現有的檔案existingpath。如果newpath已經存在,則傳回出錯。隻建立newpath中的最後一個分量,路徑中的其他部分應當已經存在。
int unlink(const char *pathname); // 過成功則傳回0,若出錯則傳回-1
此函數删除目錄項,并将由pathname所引用檔案的連結數減1.如果還有指向該檔案的其他連結,則仍可通過其他連結通路該檔案的資料。如果出錯,則不對該檔案做任何更改。
(三)
符号連結時指向一個檔案的間接指針,它與上面所說的硬連結有所不同,硬連結直接指向檔案的i節點。引入符号連結的原因是為了避開硬連結的一些限制:
1、硬連結通常要求連結和檔案位于同一檔案系統中。
2、隻有超級使用者才能建立指向目錄的硬連結。
對符号連結以及它所指向何種對象并無任何檔案系統限制,任何使用者都可建立指向目錄的符号連結。符号連結一般用于将一個檔案或整個目錄結構移動到系統的另一個位置。
int symlink(const char *oldpath, const char *newpath);
ssize_t readlink(const char *path, char *buf, size_t bufsiz);
(四)
對每個檔案都有3個時間字段。如下表:
字段
說明
例子
ls選項
st_atime
st_mtime
st_ctime
檔案資料的最後通路時間
檔案資料的最後修改時間
i節點狀态的最後更改時間
read
write
chmod/chown
-u
預設
-c
注意修改時間和更改狀态的時間之間的差別。修改時間是檔案内容最後一次被修改的時間。更改狀态時間是該檔案的i節點最後一個被修改的時間,例如更改檔案的通路權限、使用者ID、連結數等。但它們都沒有修改檔案的内容。因為i節點中的所有資訊都是與檔案的時間内容分開存放的,是以,除了檔案資料修改時間外,還需要更改狀态時間。
#include <sys/types.h>
#include <utime.h>
int utime(const char *filename, const struct utimbuf *times);
struct utimebuf{
time_t actime;
time_t modtime;
}
此函數的操作以及執行它所需要的特權取決于time參數是否為NULL
1、如果times是一個空指針,則通路時間和修改時間兩者都設定為目前時間。為了執行此操作必須滿足下列兩條件之一:程序的有效使用者ID必須等于該檔案的所有者ID;或程序對該檔案必須具有寫權限。
2、如果times是非空指針,則通路時間和修改時間被設定為times所指向結構中的值。此時程序的有效使用者ID必須等于該檔案的所有者ID,或者程序必須是一個超級使用者程序。對檔案隻具有寫權限是不夠的。