天天看點

《apue》讀書筆記 第四章 檔案和目錄(2)第四章 檔案和目錄

第四章 檔案和目錄

7.umask函數

當我們登入系統之後建立一個檔案總是有一個預設權限的,那麼這個權限是怎麼來的呢?這就是umask幹的事情。umask設定了使用者建立檔案的預設權限,它與chmod的效果剛好相反,umask設定的是權限“補碼”,而chmod設定的是檔案權限碼。即,umask是從權限中“拿走”相應的位。

對于檔案來說,權限的最大值是666,因為系統不允許你在建立一個文本檔案時就賦予它執行權限,必須在建立後用chmod指令增加這一權限。目錄則允許設定執行權限,這樣針對目錄來說,權限值最大可以到7。

例如,umask值002 所對應的檔案和目錄建立預設權限分别為6 6 4和7 7 5。

由于umask指定的是需要忽略(屏蔽)的位,故稱為屏蔽碼。umask函數用來設定程序建立檔案的屏蔽碼(它也是少數幾個沒有錯誤傳回的函數之一),聲明如下:

#include <sys/stat.h>
 mode_t umask(mode_t cmask);
 傳回:之前的檔案建立模式屏蔽碼。
           

參數cmask是9個權限常量的若幹個按位“或”構成的。

例子:建立兩個檔案,第一個的umask為0,第二個的umask值禁止所有組和其他使用者的通路權限。

#include "apue.h"
#include <fcntl.h>

#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)

int
main(void)
{
    umask();
    if (creat("foo", RWRWRW) < )
        err_sys("creat error for foo");
    umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
    if (creat("bar", RWRWRW) < )
        err_sys("creat error for bar");
    exit();
}
           

測試:

$ umask

$ ./umask
$ ls -l foo bar
-rw-------  jiange jiange  月  : bar
-rw-rw-rw-  jiange jiange  月  : foo
$ umask

           

從上面也可以看出,我們在程序中更改檔案模式建立屏蔽字并不影響其父程序(bash)的屏蔽字。

常用的umask:

002:阻止其他使用者寫你的檔案;

022:阻止同組成員和其他使用者寫你的檔案;

027:阻止同組成員寫你的檔案,阻止其他使用者讀寫或執行你的檔案。

符号形式的檔案模式建立屏蔽字:

$ umask -S
           

8.chomod 和 fchmod 函數

這兩個函數使我們可以更改已有檔案的通路權限:

#include <sys/stat.h>
 int chmod(const char *pathname, mode_t mode);
 int fchmod(int filedes, mode_t mode);
 兩者傳回:如果成功,傳回,如果錯誤,傳回-
           

chmod對一個路徑指定的檔案進行操作,而fchmod對一個打開的檔案描述符号filedes對應的檔案進行操作。

為了改變一個檔案的權限位,程序的有效使用者ID必須等于檔案的所有者ID,或者該程序必須具有超級使用者權限。

chmod函數的mode常量:

《apue》讀書筆記 第四章 檔案和目錄(2)第四章 檔案和目錄

一般“ls -l”指令隻顯示檔案内容改變的時間,而chmod修改的是i-node的最近更改時間。更改之後,按系統預設方式, ls -l列出的也隻是最後修改檔案内容的時間,而不是chmod的時間。

另外,chmod函數在下列條件下自動清除兩個權限位:

a)如果我們試圖設定普通檔案的粘滞位 ( S_ISVTX ),而且又沒有超級使用者優先權,那麼mode中的粘滞位自動被關閉(下一節說明粘住位)。也就是隻有超級使用者才能設定普通檔案的粘住位。這樣可以防止不懷好意的使用者設定粘住位。

b)新建立檔案的組ID可能不是調用程序所屬的組。前面說過,新檔案的組ID可能是父目錄的組ID。特别地,如果新檔案的組ID不等于程序的有效組ID或者程序添加組ID中的一個,以及程序沒有超級使用者特權,那麼set-group-ID位自動被關閉。這就防止了使用者建立一個并非該使用者所屬的組擁有的set-group-ID檔案。

9.粘住位(sticky bit)

S_ISVTX bit,在尚未使用分頁技術的unix系統時,如果可執行檔案設定了這個位,那麼,第一次運作可執行檔案的時候,會在程序退出的時候将可執行檔案的text段(包含機器指令的部分)拷貝一份儲存到swap分區。因為swap分區連續存儲,這樣下次運作的時候會更快。由于現在有了虛拟記憶體和更快的檔案系統,是以這個位就不那麼需要了。

在目前的系統,對這個位進行了擴充,unix标準允許這個位設定目錄,如果目錄設定了這個位,那麼目錄中的檔案可以在如下的情況下被重新命名或者删除:

使用者具有目錄的寫權限,并且滿足下面的條件之一:

a)使用者擁有這個檔案

b)使用者擁有這個目錄

c)使用者是超級使用者

/tmp 和 /var/spool/uucppublic就是一個典型的應用,任何使用者可以在這個目錄裡面建立和删除檔案,但是隻能删除屬于自己的檔案。

10.chown,fchown和lchown函數

chown函數可用于更改檔案的使用者ID群組ID:

#include <unistd.h>
 int chown(const char *pathname, uid_t owner, gid_t group);
 int fchown(int filedes, uid_t owner, gid_t group);
 int lchown(const char *pathname, uid_t owner, gid_t group);
 三者傳回:如果成功傳回,如果錯誤傳回-
           

chown和lchown修改路徑指向檔案的屬主/組,而fchown修改被打開的檔案描述符号代表的檔案的屬主/組。在符号連接配接情況下, lchown更改符号連接配接本身的所有者,而不是該符号連接配接所指向的檔案。

如果參數是-1,則對應的ID不變。

11.檔案長度

stat結構的st_size成員表示以位元組為機關的檔案長度,這個成員僅對普通檔案,目錄,連結檔案有意義。對于普通檔案,如果大小為0,則表示我們讀取檔案的時候将會獲得一個檔案結束标記;對于目錄檔案,檔案大小一般是一個數的整數倍(例如16或者512),我們後面會讨論目錄讀取;對于符号連結,檔案大小表示連結所指向的檔案的檔案名稱的大小(如“usr/lib”大小為7)。

目前多數UNIX系統提供了st_blksize和st_blocks域。前者表示這個檔案進行I/O的時候的期望塊大小,後者表示實際配置設定的512位元組塊的數目。前面我們說過,讀取一個檔案,設定不同的緩存,消耗的時間有所不同。當我們設定其大小為st_blksize的時候,實際就是最優的大小,這時候讀取檔案消耗的時間最小。為提高效率,标準I/O庫也嘗試每次都用st_blksize位元組的大小進行讀寫。另外,我們需要注意,不同版本的UNIX系統使用的st_blocks的機關可能不全是512位元組塊。

12.檔案截斷

有時我們需要在檔案尾端處截去一些資料以縮短檔案。将一個檔案的長度截斷為0是一個特例,open時候用O_TRUNC标志可以做到這一點。

為了截斷檔案可以調用函數truncate和ftruncate。聲明如下:

#include <unistd.h>
 int truncate(const char *pathname, off_t length);
 int ftruncate(int filedes, off_t length);
 兩者傳回:如果成功傳回,如果錯誤傳回-
           

函數的作用是将指定的存在的檔案的長度截短為length。如果該檔案以前的長度大于length,則超過length以外的資料就不再能存取。如果以前的長度短于length,則其結果依賴系統實作。若某個實作的處理是擴充該檔案,則在以前的檔案尾端和新的檔案尾端之間的資料将讀作0 (也就是在檔案中建立了空洞)。

繼續閱讀