標籤:永久連結與軟連結 符號連結 檔案的時間
引言:
執行如下命令時,
ls /usr/local/lib/libfreetype.so -l
顯示內容:
lrwxrwxrwx 1 root root 20 2014-04-06 22:57 /usr/local/lib/libfreetype.so -> libfreetype.so.6.9.0
表明這是一個連結檔案,通過連結可以實現對一個檔案從不同路徑對它進行引用。對於檔案的連結有永久連結和軟串連(即符號連結)之分。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中的最後一個分量,路徑中的其他部分應當已經存在。
#include <unistd.h>
int unlink(const char *pathname); // 過成功則返回0,若出錯則返回-1
此函數刪除目錄項,並將由pathname所引用檔案的連結數減1.如果還有指向該檔案的其他連結,則仍可通過其他連結訪問該檔案的資料。如果出錯,則不對該檔案做任何更改。
(三)
符號連結時指向一個檔案的間接指標,它與上面所說的永久連結有所不同,永久連結直接指向檔案的i節點。引入符號連結的原因是為了避開永久連結的一些限制:
1、永久連結通常要求連結和檔案位於同一檔案系統中。
2、只有超級使用者才能建立指向目錄的永久連結。
對符號連結以及它所指向何種對象並無任何檔案系統限制,任何使用者都可建立指向目錄的符號連結。符號連結一般用於將一個檔案或整個目錄結構移動到系統的另一個位置。
#include <unistd.h>
int symlink(const char *oldpath, const char *newpath);
#include <unistd.h>
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是一個null 指標,則訪問時間和修改時間兩者都設定為目前時間。為了執行此操作必須滿足下列兩條件之一:進程的有效使用者ID必須等於該檔案的所有者ID;或進程對該檔案必須具有寫入權限。
2、如果times是非null 指標,則訪問時間和修改時間被設定為times所指向結構中的值。此時進程的有效使用者ID必須等於該檔案的所有者ID,或者進程必須是一個超級使用者進程。對檔案只具有寫入權限是不夠的。