文件和目錄之link、unlink、remove和rename函數


任何一個文件可以有多個目錄項指向其i節點。創建一個指向現有文件的鏈接的方法是使用link函數。

#include <unistd.h>
int link( const char *existingpath, const char *newpath );
返回值:若成功返回0,若出錯返回-1

此函數創建一個新目錄項newpath,它引用現有的文件existingpath。如若newpath已經存在,則返回出錯。只創建newpath中的最后一個分量,路徑中的其他部分應當已經存在。

創建新目錄項以及增加鏈接計數應當是個原子操作。雖然POSIX.1允許實現支持跨文件系統的鏈接,但是大多數實現要求這兩個路徑名在同一個文件系統中。如果實現支持創建指向一個目錄的硬鏈接,那么也僅限於超級用戶才可以這樣做。其理由是這樣做可能在文件系統中形成循環,大多數處理文件系統的實用程序都不能處理這種情況。因此很多文件系統實現不允許對目錄的硬鏈接。

為了刪除一個現有的目錄項,可以調用unlink函數。

#include <unistd.h>
int unlink( const char *pathname );
返回值:若成功則返回0,若出錯則返回-1

此函數刪除目錄項,並將由pathname所引用文件的鏈接計數減1。如果還有指向該文件的其他鏈接,則仍可通過其他鏈接訪問該文件的數據。如果出錯,則不對該文件做任何更改。

為了解除對文件的鏈接,必須對包含該目錄項的目錄具有寫和執行的權限。如果對該目錄設置了粘住位,則對該目錄必須具有寫權限,並且具備下面三個條件之一:

擁有該文件。

擁有該目錄。

具有超級用戶特權。

只有當鏈接計數達到0時,該文件的內容才可被刪除。另一個條件也會阻止刪除文件的內容——只要有進程打開了該文件,其內容也不能刪除。關閉一個文件時,內核首先檢查打開該文件的進程數。如果該數達到0,然后內核檢查其鏈接數,如果這個數也是0,那么就刪除該文件的內容。

程序清單4-5 打開一個文件,然后unlink它

[root@localhost apue]# cat prog4-5.c
#include "apue.h"
#include <fcntl.h>

int 
main(void)
{
        if(open("tempfile", O_RDWR) < 0)
                err_sys("open error");
        if(unlink("tempfile") < 0)
                err_sys("unlink error");
        printf("file unlinked\n");
        sleep(15);
        printf("done\n");
        exit(0);
}

運行該程序,其結果是:

[root@localhost apue]# ls -l tempfile
-rw-r--r-- 1 root root 38117937 01-02 18:18 tempfile
[root@localhost apue]# df /home
文件系統               1K-塊        已用     可用      已用% 掛載點
/dev/sda3         15289132   
209228
  14290712   2% /home
[root@localhost apue]# ./prog4-5 &
[1] 5152
[root@localhost apue]# file unlinked
[root@localhost apue]# ls -l tempfile
ls: tempfile: 沒有那個文件或目錄                                                                         此時,目錄項已刪除
[root@localhost apue]# df /home
文件系統               1K-塊        已用     可用      已用% 掛載點
/dev/sda3         15289132    209228  14290712   2% /home                                   從已用/可用空間可以看出該文件內容還沒有刪除
[root@localhost apue]# done
[root@localhost apue]# df /home
文件系統               1K-塊        已用     可用      已用% 掛載點
/dev/sda3         15289132    171956  14327984   2% /home                                   睡眠結束后,進程結束,此時才刪除了該文件內容

unlink的這種性質經常被程序用來確保即使是在該程序崩潰時,它所創建的臨時文件也不會遺留下來。進程用open或creat創建一個文件,然后立即調用unlink。因為該文件仍舊是打開的,所以不會將其內容刪除。只有當進程關閉該文件或終止時(在這種情況下,內核會關閉該進程打開的全部文件),該文件的內容才會被刪除。

如果pathname是符號鏈接,那么unlink刪除該符號鏈接,而不會刪除由該鏈接所引用的文件。給出符號鏈接名情況下,沒有一個函數能刪除由該鏈接所引用的文件。

超級用戶可以調用unlink,其參數pathname指定一個目錄,但是通常應當使用rmdir函數,而不是使用這種方式。

我們也可以用remove函數解除對一個文件或目錄的鏈接。對於文件,remove的功能與unlink相同。對於目錄,remove的功能與rmdir相同。

#include <stdio.h>
int remove( const char *pathname);
返回值:若成功則返回0,若出錯則返回-1

文件或目錄用rename函數更名。

#include <stdio.h>
int rename( const char *oldname, const char *newname );
返回值:若成功則返回0,若出錯則返回-1

根據oldname是指文件還是目錄,有幾種情況要加以說明。我們也應說明如果newname已經存在將會發生什么。

(1)如果oldname指的是一個文件而不是目錄,那么為該文件或符號鏈接更名。在這種情況下,如果newname已存在,則它不能引用一個目錄。如果newname已存在,而且不是一個目錄,則先將該目錄項刪除然后將oldname更名為newname。對包含oldname的目錄以及包含newname的目錄,調用進程必須具有寫權限,因為將更改這兩個目錄。

(2)如果oldname指的是一個目錄,那么為該目錄更名。如果newname已存在,則它必須引用一個目錄,而且該目錄應當是空目錄(空目錄指的是該目錄中只有.和..項)。如果newname存在(而且是一個空目錄),則先將其刪除,然后將oldname更名為newname。另外,當為一個目錄更名時,newname不能包含oldname作為其路徑前綴。例如,不能將/usr/foo更名為/usr/foo/testdir,因為舊名字(/usr/foo)是新名字的路徑前綴,因而不能將其刪除。

(3)如若oldname或newname引用符號鏈接,則處理的是符號鏈接本身,而不是它所引用的文件。

(4)作為一個特例,如果oldname和newname引用同一文件,則函數不做任何更改而成功返回。

如若newname已經存在,則調用進程對它需要有寫權限(如同刪除情況一樣)。另外,調用進程將刪除oldname目錄項,並可能要創建newname目錄項,所以它需要對包含oldname以及newname的目錄具有寫和執行權限。

本篇博文內容摘自《UNIX環境高級編程》(第二版),僅作個人學習記錄所用。關於本書可參考:http://www.apuebook.com/

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM