之前一直對Linux的文件類型中的 “l” 類型的瞭解不是很深入,最近經過“聖經”指點,略知一二,在此先記錄一下,以便以後查閱,之後會對文件和目錄、文件I/O這部分再擴充。
首先需明確,Unix在查閱文件類型時,首先調用的是stat函數,格式如下:
int stat(const char *restrict pathname , struct stat *restrictbuf)
成功則返回0(出錯返回-1),得到7種文件類型如下:
1.普通文件 (-)
2.目錄文件 (d)
3.塊特殊文件 (b)
4.字符特殊文件 (c)
5.FIFO (用於進程間通信,也叫命名管道 )
6.套接字 (socket)
7.符號鏈接 (l)
平時我們新手接觸最多的就是普通文件以及目錄文件,同時也會接觸到標誌爲“l”的文件,在此先介紹硬鏈接和軟鏈接。
硬鏈接實際上是一個指針,指向源文件的inode,系統並不爲它重新分配inode。任何一個文件可以有多個目錄項指向其inode,硬鏈接不會產生新的inode,硬連接不管有多少個,都指向的是同一個inode節點,只是新建一個hard link會把結點連接數增加,只要結點的連接數不是0,文件就一直存在,不管你刪除的是源文件還是連接的文件。只要有一個存在,文件就存在(其實就是引用計數的概念)。當你修改源文件或者連接文件任何一個的時候,其他的文件都會做同步的修改。(引自http://blog.csdn.net/yasaken/article/details/7292186)。此時,我們可以試一下,找一個佔用磁盤大一些的測試文件,,然後ln建立一個hard link,發現此時該文件的類型就是普通文件,如下圖,而且佔用同樣大的磁盤空間,當我隨便去試圖修改一個文件時,由於這些硬鏈接文件指向同一個inode,因此所有文件都做出同步的修改,該文件的鏈接計數爲2,當我們unlink隨便一個文件時,鏈接計數減一,則只刪去unlink路徑下的那個硬鏈接文件,實際的文件並沒有刪除。
通過以上的實驗,我個人認爲是否可以將硬鏈接看成是cp一個文件,因爲硬鏈接文件同樣佔用磁盤空間,但是這個cp文件與源文件指向同一個inode,因此相當於創建了一個會和源文件的數據塊時刻保持同步的文件。(注意:hard link只能指向自己文件系統的inode,無法跨越文件系統。如果要想實現支持創建指向一個目錄的硬鏈接,那麼也僅限於root,這其實是不被推薦的,容易在文件系統中形成循環。POSIX.1常量LINK_MAX指定了一個文件鏈接數的最大值爲8.)。link 函數以及linkat函數調用方式如下:
int link (const char *existingpath, const char *newpath);
int linkat (int efd, const char *exsitingpath, int nfd, const char *newpath, int flag);
軟鏈接最直觀的解釋:相當於Windows系統的快捷方式,是一個獨立文件(擁有獨立的inode,與源文件inode無關),該文件的內容是源文件的路徑指針,通過該鏈接可以訪問到源文件。所以刪除軟鏈接文件對源文件無影響,但是刪除源文件,軟鏈接文件就會找不到要指向的文件(可以類比Windows上快捷方式,你點擊快捷方式可以訪問某個文件,但是刪除快捷方式,對源文件無任何影響)。命令可以用:ln -s 源文件的絕對路徑 軟鏈接文件的絕對路徑
在此注意,指定路徑時,一定要指定絕對路徑,否則會出現找不到鏈接的源文件的情況。如下圖:軟鏈接已經建立,但是無法通過軟鏈接打開源文件。如果不使用絕對路徑的話,就要在腳本中調用linkat函數,通過設置文件描述符efd和nfd的標誌爲AT_FDCWD(強制通過相對於調用進程的當前目錄計算pathname),與相對路徑來計算文件的路徑(目前我還沒有涉及到)。
由於軟鏈接文件與源文件的inode無關,所以是可以跨越文件系統的。同時,軟鏈接的操作權限是777的,但是如果你要對此進行編輯,需要的權限是源文件的權限,而硬鏈接的操作權限與源文件保持一致。
下面說一下由此引發的對unlink的一點記錄。
爲了刪除一個現有的目錄項,可以調用unlink函數,如下:
int unlink (const char *pathname);
int unlinkat (int fd ,const char *pathname, int flag);
當我們要想刪除一個文件時,必須要具備兩個條件:
1.鏈接計數達到0,該文件纔可以被刪除。
2.只要有進程打開了文件,其內容也不能刪除。
如下面一段代碼:
int
main(void)
{
if (open("tempfile", O_RDWR|O_CREAT) < 0)
err_sys("open error");
if (unlink("tempfile") < 0)
err_sys("unlink error");
printf("file unlinked\n");
sleep(15);
printf("done\n");
exit(0);
}
當我們執行unlink後,雖然計數爲0,實際上並沒有將文件刪除,而是要經過15秒後的exit(0)使進程調用關閉後,才真正的刪除了該文件,正是那句printf讓我糾結了大半天。 具體的執行exit(0)做的東西以後再擴充。