unlink与close关系
UNIX文件系統包括引導塊、超級塊、i節點區、文件存儲區、進程對換區等幾部分。
引導塊占用第0號物理塊,不屬于文件系統管轄,如果系統中有多個文件系統,只有根文件系統才有引導程序放在引導塊中,其余文件系統都不使用引導塊。
超級塊占用第1號物理塊,是文件系統的控制塊,超級塊包括:文件系統的大小、空閑塊數目、空閑塊索引表、空閑i節點數目、空閑i節點索引表、封鎖標記等。超級塊是文件系統為文件分配存儲空間、回收存儲空間的依據。
i節點區存放i節點,i節點是對文件進行控制和管理的一種數據結構。
文件存儲區是存放文件內容的區域,文件存儲區中各數據塊的使用情況在超級中有記錄,系統利用超級塊中的記錄完成對數據塊的分配和回收。
unix文件系統中很重要的概念之一就是i節點,下面就開始說說這個重要的概念。
每一個文件都由自己的i節點,每個i節點都有唯一的i節點號。
i節點的結構如下(參考/usr/include/sys/ino.h)
struct dinode
{
ushort??di_mode;//文件類型與權限
short???di_nlink;
ushort di_uid;
ushort di_gid;
off_t??di_size;
char di_addr[40];
time_t di_atime;
time_t di_mtime;
time_t di_ctime;
}
從上面的結構中可以看出:
1、i節點保存了文件的屬性和類型、存放文件內容的物理塊地址、最近一次的存取時間、最后一次修改時間、創建此文件的時間。
2、i節點中沒有記錄文件名字,那么文件的名字是怎么關聯到i節點的呢?這么設計又有什么好處呢?
?????在linux系統中,文件的查找不是通過文件名稱來查找的。實際上是通過i節點來實現文件的查找定位的。我們可以形象的將i節點看作是一個指針。當文件存儲到磁盤上去的時候,文件肯定會存放到一個磁盤位置上,可以這樣想象,既然文件數據是存放在磁盤上的,如果我們知道這個文件數據的地址,當我們想讀寫文件的時候,我們是不是直接使用這個地址去找到文件就可以了呢?
?????是的,在linux下,i節點其實就是可以這么認為,把i節點看作是一個指向磁盤上該文件存儲區的地址。只不過這個地址我們一般沒辦法直接使用,而是通過文件名來間接使用的。事實上,i節點不僅包含了文件數據存儲區的地址,上面也提到過,它還包含了很多其他信息(文件的屬性和類型,存放文件內容的物理塊地址,最近一次的存取時間,最近一次的修改時間,創建文件的時間)。但是i節點是不保存文件名的。文件名保存在一個目錄項中。每個目錄項中都包含了文件名和i節點。回到正題,i節點中沒有記錄文件愛你名字,那么文件按名是怎么關聯到i節點的呢。這里就關系到了硬鏈接與符號鏈接的區別。
如下圖:
???????對于硬鏈接來說,如果刪掉源文件helloA.c,那么磁盤上數據文件按是不會被刪除的。因為i節點上記錄了該文件的硬鏈接數。只有硬鏈接數為0的時候,刪除文件名的時候,該數據在磁盤上才會刪除。
???????所謂的符號鏈接,其實是指文件索引的索引。當源文件helloB.c刪除之后,其實磁盤數據文件還在,helloC.c也無法使用。符號鏈接包含了一個文件名的路徑,如果這個文件名被刪除,這個符號鏈接自然就不能正常工作了。
3、di_mode這個是怎么保存文件類型+用戶權限的呢?
比如:
drwxr-xr-x?????????7?????????root????????????sys??????????????512??????dec??15???2012???var
?-rw-r--r---?????????1?????????root????????????sys??????????????4003?????Ju1 4 23 : 37??????1
紅色字體部分說明是文件類型標記和文件權限,這個字符串跟ushort di_mode怎么關聯的?
ushort di_mode是16位2進制數,保存的就是文件類型及用戶權限信息,具體結構如下:
4??????????????????8????????????????????12????????????????????16
第1-4位:文件類型
第5位:suid位
第6位:sgid位
第7位:sticky位
第8-10位:文件屬主權限位
第11-13位:文件屬組權限位
第14-16位:其他用戶權限位
1)文件類型分類:
d--目錄文件、f--普通文件、b--塊設備文件、c--字符設備文件、l--鏈接文件
2)文件類型位算法
從系統的頭文件/usr/include/sys/stat.h中可以知道:
a、#define???S_IFMT???0170000 -- 文件類型掩碼宏,0170000以0開頭,表示這是一個8進制數,轉換成2進制,正好是 1 111 000 000 000 000 ,高4位全置1;
b、#define???S_IFREG 0100000 -- 普通文件類型掩碼,0100000,轉換成2進制,1 000 000 000 000 000,最高位置1;
c、#define S_ISREG(m)???(((m) & S_IFMT) == S_IFREG) --???判斷文件是否普通文件的宏函數
舉例說明:m值即為我們取到ushort di_mode,假設其2進制值為 0 011 000 000 000 000,對應的8進制為 060000???。S_ISREG(0060000) 即 (((0060000) & 0170000 ) == 0100000) ,該值返回False,則代表該文件不是普通文件。
說明:stat結構中的大多數信息都取自i節點。只有兩項數據存放在目錄項中:文件名和i節點編號。i節點編號的數據類型是ino_t。
注意:每個文件系統各自對它們的i節點進行編號,因此目錄項中的i節點編號數指向同一文件系統中相應的i節點,不能使一個目錄項指向另一個文件系統的i節點。
討論linux中link,unlink,close,fclose函數對st_nlink的影響
?????linux中每一個文件,都可以通過一個struct stat的結構體來獲得文件信息,其中一個成員st_nlink代表文件的鏈接數。
???????當通過shell的touch命令或者在程序中open一個帶有O_CREAT的不存在的文件時,文件的鏈接數為1。
???????通常open一個已存在的文件不會影響文件的鏈接數。open的作用只是使調用進程與文件之間建立一種訪問關系,即open之后返回fd,調用進程可以通過fd來read 、write 、 ftruncate等等一系列對文件的操作。
???????close()就是消除這種調用進程與文件之間的訪問關系。自然,不會影響文件的鏈接數。在調用close時,內核會檢查打開該文件的進程數,如果此數為0,進一步檢查文件的鏈接數,如果這個數也為0,那么就刪除文件內容。
???????link函數創建一個新目錄項,并且增加一個鏈接數。
???????unlink函數刪除目錄項,并且減少一個鏈接數。如果鏈接數達到0并且沒有任何進程打開該文件,該文件內容才被真正刪除。如果在unlilnk之前沒有close,那么依舊可以訪問文件內容。
???????綜上所訴,真正影響鏈接數的操作是link、unlink以及open的創建。
???????刪除文件內容的真正含義是文件的鏈接數為0,而這個操作的本質完成者是unlink。close能夠實施刪除文件內容的操作,必定是因為在close之前有一個unlink操作。
???????舉個例子簡單說明:通過shell???touch test.txt
??1 #include <stdio.h>
??2 #include <unistd.h>
??3 #include <sys/stat.h>
??4 #include <sys/types.h>
??5 #include <fcntl.h>
??6
??7 int main(int argc,char *argv[])
??8 {
??9?????struct stat buf;
?10?????stat("test.txt",&buf);
?11?????printf("1.link=%d\n",buf.st_nlink);
?12
?13 int fd;
?14 fd = open("test.txt",O_RDONLY);
?15 stat("test.txt",&buf);
?16 printf("2.link=%d\n",buf.st_nlink);
?17
?18?????close(fd);
?19?????stat("test.txt",&buf);
?20?????printf("3.link=%d\n",buf.st_nlink);
?21 link("test.txt","test2.txt");
?22 stat("test.txt",&buf);
?23 printf("4.link=%d\n",buf.st_nlink);
?24?????unlink("test2.txt");
?25?????stat("test.txt",&buf);
?26?????printf("5.link=%d\n",buf.st_nlink);
?27 fd = open("test.txt",O_RDONLY);
?28 stat("test.txt",&buf);
?29 printf("6.link=%d\n",buf.st_nlink);
?30?????unlink("test.txt");
?31?????fstat(fd,&buf);
?32?????printf("7.link=%d\n",buf.st_nlink);
?33
?34?????return 0;
?35
?36 }
順次執行以上8個步驟,結果如下:
1.link=1
2.link=1????//open不影響鏈接數
3.link=1????//close不影響鏈接數
4.link=2????//link之后鏈接數加1
5.link=1????//unlink后鏈接數減1
6.link=1????//重新打開??鏈接數不變
7.link=0????//unlink之后再減1,此處我們改用fstat函數而非stat,因為unlilnk已經刪除文件名,所以不可以通過???文件名訪問,但是fd仍然是打開著的,文件內容還沒有被真正刪除,依舊可以使用fd獲得文件信息。
執行步驟8,文件內容被刪除....
注意:在第步驟6中,文件test.txt此時已經打開并沒有將其關閉,而步驟七中直接將其釋放,此時,文件的內容沒有真正的被刪除。進程任然可以繼續讀文件中的內容。直到關閉該文件或進程結束自動關閉后,內核首先會先檢查打開文件的進程數,如果為0,然后內核檢查其鏈接數,由于在第七步中已經釋放了最后一個,所以其鏈接數為0,那么就刪除該文件的內容。
下圖是抄之apue的精典例子:
????unlink的這種性質經常被程序用來確保即使是在該程序崩潰時,它所創建的臨時文件也不會被遺留下來。進程用open或creat創建一個文件,然后立即調用unlink。因為該文件仍舊是打開的,所以不會將其內容刪除。只有當進程關閉該文件或終止時(這種情況下,內核會關閉該進程打開的全部文件),該文件的內容才會被刪除。
????unlink刪除該符號鏈接,而不是刪除由該鏈接所引用的文件。給出符號鏈接名的情況下,沒有一個函數能刪除由該鏈接所引用的文件。
總結
以上是生活随笔為你收集整理的unlink与close关系的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 音频、摄像机操作
- 下一篇: 二进制除法\模2除法