檔案屬性是作業系統管理資料的基石。本文系統整理 stat、fstat、lstat 三大系統呼叫,並深入剖析 struct stat 結構體中的檔案類型、權限位元、時間戳記、連結計數等核心欄位,附完整 C 語言範例與實測輸出,助你從核心視角掌握檔案元資料。
#include#include int stat(const char *pathname, struct stat *buf); // 依路徑取得,追蹤符號連結 int fstat(int fd, struct stat *buf); // 依檔案描述符取得 int lstat(const char *pathname, struct stat *buf); // 依路徑取得,不追蹤符號連結 // 回傳:成功 0,失敗 -1 (設 errno)
關鍵差異:stat/lstat 接收路徑,fstat 接收已開啟的 fd;lstat 回傳符號連結本身屬性,而非目標檔案。
struct stat {
mode_t st_mode; // 檔案類型 + 權限位元
ino_t st_ino; // inode 號
dev_t st_dev; // 所在裝置號
nlink_t st_nlink; // 硬連結數
uid_t st_uid; // 擁有者 UID
gid_t st_gid; // 群組 GID
off_t st_size; // 檔案大小 (位元組),普通檔有效
time_t st_atime; // 最後存取時間
time_t st_mtime; // 內容最後修改時間
time_t st_ctime; // 狀態 (權限/擁有者/內容) 最後變更時間
};
ls -l 即是呼叫 stat() 後格式化輸出。
st_mode 同時編碼類型與權限。POSIX 定義判斷巨集:
| 巨集 | 檔案類型 | ls -l 首字元 |
|---|---|---|
| S_ISREG() | 普通檔案 | - |
| S_ISDIR() | 目錄 | d |
| S_ISBLK() | 區塊特殊檔 (硬碟等) | b |
| S_ISCHR() | 字元特殊檔 (終端、序列埠) | c |
| S_ISFIFO() | 命名管道 (FIFO) | p |
| S_ISSOCK() | Socket | s |
| S_ISLNK() | 符號連結 | l |
#include#include #include #include int main(int argc, char *argv[]) { struct stat sb; const char *type; for (int i = 1; i < argc; i++) { if (lstat(argv[i], &sb) == -1) { fprintf(stderr, "%s: lstat error\n", argv[i]); continue; } if (S_ISREG(sb.st_mode)) type = "regular"; else if (S_ISDIR(sb.st_mode)) type = "directory"; else if (S_ISCHR(sb.st_mode)) type = "char special"; else if (S_ISBLK(sb.st_mode)) type = "block special"; else if (S_ISLNK(sb.st_mode)) type = "symlink"; else if (S_ISFIFO(sb.st_mode)) type = "fifo"; else if (S_ISSOCK(sb.st_mode)) type = "socket"; else type = "unknown"; printf("%s → %s\n", argv[i], type); } return 0; }
編譯測試:
$ gcc file_type.c -o file_type $ ./file_type /dev/initctl /etc/passwd /dev/sda /dev/tty /dev/log /dev/cdrom /dev/initctl → fifo /etc/passwd → regular /dev/sda → block special /dev/tty → char special /dev/log → socket /dev/cdrom → symlink
rwx (owner/group/other),對應 st_mode 低 9 位。passwd)。/tmp)。相關系統呼叫:
umask(mode_t mask):設定預設權限遮罩。chmod/fchmod/fchmodat:修改權限。chown/fchown/lchown/fchownat:修改擁有者/群組。st_atime:read()、stat() 更新。st_mtime:write()、truncate() 更新。st_ctime:chmod()、chown()、link()、unlink()、write() 更新。現代程式建議使用 utimensat() (支援奈秒精度) 替代舊有 utime()/utimes()。
熟稔 stat 族群與 struct stat,即能編寫健壯的檔案系統工具、備份軟體、安全稽核腳本。下一步可探討 inotify 監控檔案變更、fanotify 全系統存取審計等進階主題。