1. 程式人生 > >[UNIX環境高階程式設計] 檔案和目錄

[UNIX環境高階程式設計] 檔案和目錄

1 引言

上文圍繞了普通檔案I/O進行了討論——開啟檔案、讀檔案或寫檔案。本文將描述檔案系統的其他特徵和檔案的性質。將從stat函式開始,stat結構中的大多數成員都是基本系統資料型別,逐個分解stat結構的每一個成員以瞭解檔案的所有屬性。
使用stat函式最多的地方可能就是[ls -ls]命令,可以獲得一個檔案的全部資訊。
本文主要討論4個stat函式以及它們的返回資訊。

struct stat
{
    dev_t     st_dev;         /* ID of device containing file */
    ino_t     st_ino;         /* inode number */
mode_t st_mode; /* file type and mode */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device ID (if special file) */ off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */ blkcnt_t st_blocks; /* number of 512B blocks allocated */ /* Since Linux 2.6, the kernel supports nanosecond * precision for the following timestamp fields. * For the details before Linux 2.6, see NOTES. */ struct
timespec st_atim; /* time of last access */ struct timespec st_mtim; /* time of last modification */ struct timespec st_ctim; /* time of last status change */ #define st_atime st_atim.tv_sec /* Backward compatibility */ #define st_mtime st_mtim.tv_sec #define st_ctime st_ctim.tv_sec }; #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> // return 0 or -1 if an error occurred. int stat(const char* pathname, struct stat* buf); int fstat(int fd, struct stat* buf); int lstat(const char* pathname, struct stat* buf); #include <fcntl.h> #include <sys/stat.h> // return 0 or -1 if an error occurred. int fstatat(int dirfd, const char* pathname, struct stat* buf, int flags);

一旦給出pathname,stat函式將返回與此檔案有關的資訊結構fstat函式獲得已在描述符fd上開啟檔案的有關資訊lstat函式類似於stat但是當命名的檔案是一個符號連結時,lstat返回該符號連結的有關資訊,而不是由該符號連結引用的檔案的資訊
fstatat函式為一個相對於當前開啟目錄(由fd引數指定)的路徑名返回檔案統計資訊。flag引數控制著是否跟隨著一個符號連結。當AT_SYMLINK_NOFOLLOW標誌被設定時,fstatat不會跟隨符號連結,而是返回符號連結本身的資訊。如果fd引數的值是AT_FDCWD,並且pathname引數是一個相對路徑名,fstatat會計算相對於當前目錄的pathname引數;如果pathname引數是一個絕對路徑,fd引數就會被忽略。這兩種情況下,fstatat的作用就跟stat或lstat一樣。

2 檔案型別

檔案型別包含如下幾種:
[1] 普通檔案
[2] 目錄檔案
[3] 塊特殊檔案:提供對裝置帶緩衝的訪問,每次訪問以固定長度為單位進行
[4] 字元特殊檔案:提供對裝置不帶緩衝的訪問,每次訪問長度可變。系統中的所有裝置要麼是字元特殊檔案,要麼是塊特殊檔案
[5] FIFO:這種型別的檔案用於程序間通訊,有時也成為命名管道
[6] 套接字:這種型別的檔案用於程序間的網路通訊,也可用於在一臺宿主機上程序之間的非網路通訊
[7] 符號連結:這種型別的檔案指向另一個檔案

檔案型別資訊儲存在stat結構的st_mode成員中,下表中的巨集引數都是stat結構中st_mode成員的可取值。

巨集 檔案型別
S_ISREG() 普通檔案
S_ISDIR() 目錄檔案
S_ISCHR() 字元特殊檔案
S_ISBLK() 塊特殊檔案
S_ISFIFO() 管道或FIFO
S_ISLNK() 符號連結
S_ISSOCK() 套接字

3 檔案ID和組ID

3.1 設定使用者ID和設定組ID

與一個程序相關聯的ID有6個或更多,包括:
實際使用者ID實際組ID:標識我們究竟是誰;
有效使用者ID有效組ID附屬組ID:決定了我們的檔案訪問許可權;
儲存的設定使用者ID儲存的設定組ID:在執行一個程式時包含了有效使用者ID和有效組ID的副本。
通常:有效使用者ID等於實際使用者ID,有效組ID等於實際組ID。

每個檔案有一個所有者和組所有者,所有者由stat結構中的st_uid指定,組所有者由st_gid指定。
設定使用者ID位以及設定組ID位都包含在檔案的st_mode值中,這兩位可分別用常量S_ISUID和S_ISGID測試。

3.2 更改檔案的使用者ID和組ID

下面幾個chown函式可用於更改檔案的使用者ID和組ID。

#include <unistd.h>
// return 0 or -1 if an error occurred.
int chown(const char* path, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int lchown(const char* path, uid_t owner, gid_t group);

#include <fcntl.h>
#include <unistd.h>
// return 0 or -1 if an error occurred.
int fchownat(int dirfd, const char* pathname, uid_t owner, gid_t group, int flags);

除了所引用檔案為符號連結外,這4個函式的操作類似。在符號連結情況下,lchown和fchownat(設定了AT_SYMLINK_NOFOLLOW標誌)更改符號連結本身的所有者,而不是符號連結所指向的檔案的所有者。
fchown函式改變fd引數指向的開啟檔案的所有者,既然它在一個已開啟的檔案上操作,就不能用於改變符號連結的所有者。

4 檔案訪問許可權

st_mode值也包含了對檔案的訪問許可權位。當提及檔案時,指的是前面所提到的任何型別的檔案。所有檔案型別都有訪問許可權。
每個檔案有9個訪問許可權位,可分為三類。

st_mode遮蔽 含義
S_IRUSR 使用者讀
S_IWUSR 使用者寫
S_IXUSR 使用者執行
S_IRGRP 組讀
S_IWGRP 組寫
S_IXGRP 組執行
S_IROTH 其他讀
S_IWOTH 其他寫
S_IXOTH 其他執行

chmod命令可以修改這9個許可權位,用u表示使用者,用g表示組,用o表示其他。

4.1 訪問許可權測試

當用open函式開啟一個檔案時,核心以程序的有效使用者ID和有效組ID為基礎執行其訪問許可權測試。有時,程序也希望按其實際使用者ID和實際組ID來測試其訪問能力。
access和fassessat函式是按實際使用者ID和實際組ID進行訪問許可權測試的。

#include <unistd.h>
// return 0 or -1 if an error occurred.
int access(const char* pathname, int mode);

#include <fcntl.h>
#include <unistd.h>
// return 0 or -1 if an error occurred.
int faccessat(int dirfd, const char* pathname, int mode, int flags);

測試檔案是否存在,mode位F_OK;否則是下表所列常量的按位或

mode 說明
R_OK 測試讀許可權
W_OK 測試寫許可權
X_OK 測試執行許可權

flag引數可以用於改變faccessat的行為,如果flag設定位AT_EACCESS,訪問檢查用的時呼叫程序的有效使用者ID和有效組ID,而不是實際使用者ID和實際組ID。

4.2 為程序設定檔案模式建立遮蔽字

#include <sys/types.h>
#include <sys/stat.h>
// Always succeeds and return previous value of the mask.
mode_t umask(mode_t mask);

4.3 更改現有檔案的訪問許可權

#include <sys/stat.h>
// return 0 or -1 if an error occurred.
int chmod(const char* path, mode_t mode);
int fchmod(int fd, mode_t mode);

#include <fcntl.h>
#include <sys/stat.h>
// return 0 or -1 if an error occurred.
int fchmodat(int dirfd, const char* pathname, mode_t mode, int flags);

chmod函式在指定的檔案上進行操作。
fchmod函式對已開啟的檔案進行操作。

4.4 檔案訪問許可權小結

常量 說明 對普通檔案的影響 對目錄的影響
S_ISUID 設定ID 執行時設定有效使用者ID 未使用
S_ISGID 設定組ID 若組執行位設定則執行設定有效組ID,否則使強制性鎖起作用(若支援) 將在目錄中建立的新檔案的組ID設定為目錄的組ID
S_ISVTX 黏著位 在交換區快取程式正文(若支援) 限止在目錄中刪除和重新命名檔案
S_IRUSR 使用者讀 許可使用者讀檔案 許可使用者讀目錄項
S_IWUSR 使用者寫 許可使用者讀檔案 許可使用者在目錄中刪除和建立檔案
S_IXUSR 使用者執行 許可使用者讀檔案 許可使用者在目錄中搜索給定路徑名
S_IRGRP 組讀 許可組讀檔案 許可組讀目錄項
S_IWGRP 組寫 許可組讀檔案 許可組在目錄中刪除和建立檔案
S_IXGRP 組執行 許可組讀檔案 許可組在目錄中搜索給定路徑名
S_IROTH 其他讀 許可其他讀檔案 許可其他讀目錄項
S_IWOTH 其他寫 許可其他讀檔案 許可其他在目錄中刪除和建立檔案
S_IXOTN 其他執行 許可其他讀檔案 許可其他在目錄中搜索給定路徑名

S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR
S_IRWXG = S_IRGRP | S_IWGRP | S_IXGRP
S_IRWXO = S_IROTH | S_IWOTH | S_IXOTH

檔案系統

符號連結

檔案時間

目錄

裝置特殊檔案