獲取檔案狀態 (stat, lstat和fstat)
獲取檔案狀態的系統呼叫有三個,分別是stat,fstat和lstat,其實他們的作用是一樣的,都是查詢某個檔案的狀態。如果查詢成功,會把檔案狀態的資訊填充在一個stat結構體中。他們的函式定義分別如下:
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
可以看到,這三個系統呼叫用於輸出的引數型別是一樣的,都是struct stat,其中,state與fstat的區別在於,stat()用檔名來指定要查詢的檔案,而fstat()用檔案描述符來指定目標檔案;而stat()與lstat()的區別在於,如果指定的檔案是一個符號連結,那麼stat會解引用,查詢該連結指向的普通檔案的屬性,而lstat()在遇到符號連結檔案是,不去解引用,而是直接返回這個符號連結檔案本身的屬性。要成功獲取到指定檔案的狀態資訊,需要使用者對檔案儲存位置的每一層目錄都具有執行和讀取許可權。
Linux的系統呼叫中還有很多類似的以 f 和 l 開頭的系統呼叫,他們的區別與作用和stat系列函式都是類似的。
返回引數struct stat的結構定義與各欄位的含義分別為:
struct stat { dev_t st_dev; /* 檔案存放的裝置ID */ ino_t st_ino; /* 索引節點號 */ mode_t st_mode; /* 檔案的屬性掩碼 */ nlink_t st_nlink; /* 硬連結的數量 */ uid_t st_uid; /* 檔案擁有者的使用者ID */ gid_t st_gid; /* 檔案擁有者的組ID */ dev_t st_rdev; /* 裝置ID,僅對部分特殊檔案有效 */ off_t st_size; /* 檔案大小,單位位元組,軟連線檔案的大小是連結名長度 */ blksize_t st_blksize; /* 檔案使用的儲存塊大小 */ blkcnt_t st_blocks; /* 檔案佔用的儲存塊數量,以512位元組為單位 */ time_t st_atime; /* 最後一次訪問的時間 */ time_t st_mtime; /* 最後一次內容修改的時間 */ time_t st_ctime; /* 最後一次狀態變化的時間 */ };
對於st_mode欄位,系統定義了一些巨集來檢查檔案的型別:
S_ISREG(m) 檢查是否是常規檔案
S_ISDIR(m) 檢查是否是目錄
S_ISCHR(m) 檢查是否是字元裝置 (如鍵盤)
S_ISBLK(m) 檢查是否是塊裝置(如硬碟)
S_ISFIFO(m) 是否是命名管道
S_ISLNK(m) 是否是符號連結
S_ISSOCK(m) 是否是套接字
與其他的很多系統呼叫一樣,這幾個系統呼叫都是成功是返回0,否則返回-1,並設定對應的errno,常見的可能出現的errno有:
EACCES:目標檔案所在的目錄或某個上級目錄沒有查詢許可權
EBADF:指定的檔案描述符無效.
EFAULT:無效的檔案地址
ELOOP:可能遇到了迴圈引用的軟連結檔案
ENAMETOOLONG:檔案路徑名太長.
ENOENT:目錄或檔案不存在
ENOMEM:核心記憶體耗盡
ENOTDIR:指定的檔案路徑上,某個部分不是目錄
EOVERFLOW:引用的檔案太大了,或者使用的索引節點太多了,或者佔用的儲存塊太多了。
如下是使用stat()系統呼叫的演示程式:
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
struct stat sb;
if (argc != 2) {
fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (stat(argv[1], &sb) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
printf("File type: ");
switch (sb.st_mode & S_IFMT) {
case S_IFBLK: printf("block device\n"); break;
case S_IFCHR: printf("character device\n"); break;
case S_IFDIR: printf("directory\n"); break;
case S_IFIFO: printf("FIFO/pipe\n"); break;
case S_IFLNK: printf("symlink\n"); break;
case S_IFREG: printf("regular file\n"); break;
case S_IFSOCK: printf("socket\n"); break;
default: printf("unknown?\n"); break;
}
printf("I-node number: %ld\n", (long) sb.st_ino);
printf("Mode: %lo (octal)\n",
(unsigned long) sb.st_mode);
printf("Link count: %ld\n", (long) sb.st_nlink);
printf("Ownership: UID=%ld GID=%ld\n",
(long) sb.st_uid, (long) sb.st_gid);
printf("Preferred I/O block size: %ld bytes\n",
(long) sb.st_blksize);
printf("File size: %lld bytes\n",
(long long) sb.st_size);
printf("Blocks allocated: %lld\n",
(long long) sb.st_blocks);
printf("Last status change: %s", ctime(&sb.st_ctime));
printf("Last file access: %s", ctime(&sb.st_atime));
printf("Last file modification: %s", ctime(&sb.st_mtime));
exit(EXIT_SUCCESS);
}