在前面的兩篇,我們了解了IO操作的一些基本操作函數,包括open、read和write。
在本篇我們來學習一下文件系統的其他特性和一個文件的屬性,涉及的函數功能包括:
我們還會了解一些文件系統相關的數據結構和符號鏈接(symbolic link)。
1 函數stat、fstat、fstatat、lsat函數#include <sys/stat.h>int stat(const char *restrict pathname, struct stat *restrict buf );int fstat(int fd, struct stat *buf);int lstat(const char *restrict pathname, struct stat *restrict buf );int fstatat(int fd, const char *restrict pathname, struct stat *restrict buf, int flag);//All four return: 0 if OK, −1 on error
函數功能:
stat返回pathname指定文件的信息;
fstat獲取在文件描述符fd上打開的文件信息;
lstat的功能和stat函數類似,只是有一種情況有區別,當pathname指定的文件是一個符號鏈接的時候,lstat函數獲取的文件信息是該符號鏈接的信息,而不是符號鏈接所指向文件的信息,在后面我們會了解更多關于符號鏈接的相關內容;
fstatat:文件描述符fd表示一個父目錄,pathame指定父目錄下得一個子目錄,fstatat函數返回該子目錄下的文件統計數。flag用來設置是否查詢符號鏈接所指向的文件,如果flag設置為AT_SYMLINK_NOFOLLOW,則fstatat函數只返回該符號鏈接的相關信息,如果不設置該標志位,則返回該符號鏈接指向的文件的相關信息。
是一個關鍵的輸出參數,上面的參數將文件屬性填充值該結構體內。結構體如下圖所示:
結構體中得每個成員都代表文件的某一個屬性,我們會逐個了解屬性的具體含義。
2 文件類型(File Type)目前我們了解了兩種文件:常規文件(regular files)和文件夾(directory)。
常見的幾種文件類型包括:
stat結構體中得st_mode制定了文件的類型。
Example:
#include "apue.h"intmain(int argc, char *argv[]){ int i; struct stat buf; char *ptr; for (i = 1; i < argc; i++) { PRintf("%s: ", argv[i]); if (lstat(argv[i], &buf) < 0) { err_ret("lstat error"); continue; } if (S_ISREG(buf.st_mode)) ptr = "regular"; else if (S_ISDIR(buf.st_mode)) ptr = "directory"; else if (S_ISCHR(buf.st_mode)) ptr = "character special"; else if (S_ISBLK(buf.st_mode)) ptr = "block special"; else if (S_ISFIFO(buf.st_mode)) ptr = "fifo"; else if (S_ISLNK(buf.st_mode)) ptr = "symbolic link"; else if (S_ISSOCK(buf.st_mode)) ptr = "socket"; else ptr = "** unknown mode **"; printf("%s/n", ptr); } exit(0);}
運行截圖:
每個進程6個甚至更多的ID和它關聯。如下表所示:
簡要介紹ID的區別:
一般情況下,effective user ID = real user ID,effective group ID = real group ID.
每個文件都由一個所有者,和一個組所有者,分別對應stat數據結構中得字段:st_uid和st_gid。
如果執行程序時,希望effective user(group) ID != real user(group) ID,即希望改變進程的訪問資源的權限為文件所有者的訪問權限,而不是真實用戶的訪問權限,可以通過設置mode中兩個bit來實現將effective user(group) ID設置為文件所有者(組),這兩個bit叫做:set-user-ID位和set-group-ID位。這兩個位包含在stat數據結構中得st_mode字段中,可以通過函數S_ISUID和S_ISGID來測試。
4 文件訪問權限(File access Permissions)stat數據結構中的st_mode字段中同樣包含文件訪問權限位。
每個文件有9中權限位:
這些標志位的使用需要注意的事項總結如下:
文件訪問權限檢測流程:
簡單來說,如果進程是該文件的擁有者,則訪問是否允許取決于用戶訪問權限標志位,忽略組權限標志位;如果進程不是該文件的擁有者,但是該進程屬于某個有訪問權限的組,訪問是否允許取決于組權限標志位的設置,忽略other訪問權限標志位。
5 新文件和目錄的所有權(ownership)新文件的real user ID為創建該文件的進程的effective user ID。
新文件的real group ID的取值取決于:
access和faccessat函數用于測試當前用戶(real user,當前登錄用戶)對某一文件是否有某種操作權限。
函數聲明:
#include <unistd.h>int access(const char* pathname, int mode);int faccessat(int fd, const char* pathname, int mode, int flag);
mode的可取值,當為F_OK,測試文件是否存在。
faccessat函數的相關細節:
Example:
#include "apue.h"#include <fcntl.h>intmain(int argc, char *argv[]){ if (argc != 2) err_quit("usage: a.out <pathname>"); if (access(argv[1], R_OK) < 0) err_ret("access error for %s", argv[1]); else printf("read access OK/n"); if (open(argv[1], O_RDONLY) < 0) err_ret("open error for %s", argv[1]); else printf("open for reading OK/n"); exit(0);}
測試:
由于本地mac環境搞不定,所以直接截書上的例子吧。
該例中,當切換到root用戶,修改了該文件的所有者為root用戶,并且設置了set-user-ID,這樣當切換到別的用戶時,仍可以以RDONLY方式打開文件,但是由于access是測試當前real user的讀權限,當切換到其他用戶時,access測試不通過,顯示Permission denied。
好吧,直接忽略上面這個例子吧,我沒能在自己的機器上重現,只是直接隨便翻譯書上某一段話。如果有某位高手看懂了,請指點。
小結由于這一章內容比較多,所以打算用三篇來寫,這是第一篇,主要介紹了stat函數,access函數,文件類型和各種令人糊涂的ID。
參考資料:
《Advanced Programming in the UNIX Envinronment 3rd》
新聞熱點
疑難解答