跳轉到內容

C 程式設計/POSIX 參考/sys/stat.h/stat

來自華夏公益教科書,開放的書籍,為一個開放的世界

stat() 是一個 Unix 系統呼叫,它返回有關檔案 inode 的有用資料。stat() 的語義在不同的 作業系統 之間有所不同。例如,Unix 命令 ls 使用它來檢索有關(除許多其他資訊外)的資訊

  • mtime: 時間 最後修改(ls -l),
  • ctime: 最後狀態更改時間(ls -lc)和
  • atime: 最後訪問時間(ls -lu)。

stat() 函式和 stat 結構

[編輯 | 編輯原始碼]

在所有符合 POSIX 標準的 類 Unix 作業系統上都可以找到的 POSIX 庫標頭檔案 sys/stat.h 聲明瞭 stat()fstat()lstat() 例程

 int stat(const char *filename, struct stat *buf);
 int lstat(const char *filename, struct stat *buf);
 int fstat(int filedesc, struct stat *buf);

並定義了 struct stat 結構,其中至少包含以下成員

     dev_t       st_dev;     /* ID of device containing file */
     ino_t       st_ino;     /* inode number */
     mode_t      st_mode;    /* protection */
     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 */
     time_t      st_atime;   /* time of last access */
     time_t      st_mtime;   /* time of last modification */
     time_t      st_ctime;   /* time of last status change */
     blksize_t   st_blksize; /* blocksize for filesystem I/O */
     blkcnt_t    st_blocks;  /* number of blocks allocated */
[編輯 | 編輯原始碼]

lstat() 是一個 庫函式,它檢索 檔案 的狀態。它與 stat() 相同,不同之處在於當檔案是 符號連結 時,它返回有關連結本身的資訊,而不是連結到的檔案的資訊。

fstat() 是一個 庫函式,它檢索檔案的狀態。它與 stat() 相同,不同之處在於檔案的標識作為 檔案描述符 而不是作為 檔名 傳遞。

atime 的批評

[編輯 | 編輯原始碼]

寫入檔案會更改其 mtimectime,而讀取檔案會更改其 atime。因此,在符合 POSIX 標準的系統上,讀取檔案會導致寫入,這一點受到了批評。這種行為通常可以透過在 /etc/fstab 中新增一個掛載選項來停用。

但是,關閉 atime 更新會破壞 POSIX 相容性,並且一些應用程式(尤其是 mutt 郵件閱讀器(在某些配置中)和一些檔案使用監視工具,尤其是 tmpwatch)也會因此而無法正常工作。在最壞的情況下,不更新 atime 會導致某些備份程式無法備份檔案。

Linux 核心開發人員 Ingo Molnár 將 atime 稱為“可能是歷史上最愚蠢的 Unix 設計理念”,[1][2] 並補充道:“想一想:‘對於從磁碟讀取的每個檔案,讓我們執行...寫入磁碟!並且,對於已經快取並從快取中讀取的每個檔案...執行寫入磁碟!’”他還強調了這種效能影響

Atime 更新是 Linux 今天面臨的最大的 IO 效能缺陷。擺脫 atime 更新將比過去 10 年所有頁面快取加速的總和,_加在一起_,為我們帶來更多日常的 Linux 效能。

解決方案

[編輯 | 編輯原始碼]

當前版本的 LinuxMac OS XSolarisFreeBSDNetBSDOpenBSD 支援 noatime 掛載選項,該選項會導致 atime 欄位永遠不會被更新。這會破壞與 POSIX 的相容性。

當前版本的 Linux 支援四個掛載選項,可以在 fstab 中指定

  • strictatime(以前是 atime,以前是預設值;從 2.6.30 開始是 strictatime)– 始終更新 atime。
  • relatime –(相對 atime),在 2.6.20 中引入,從 2.6.30 開始是預設值
  • nodiratime – 永遠不要更新目錄的 atime
  • noatime – 永遠不要更新 atime;包括 nodiratime;最高效能,最低相容性

strictatime 符合 POSIX 標準;Alan Cox 將其他選擇描述為

關閉 atime,它與標準不相容,切換到 relatime,它與標準不相容,但不會破壞任何東西(這很好)

使用 noatime 選項掛載的檔案系統不會在讀取時更新 atime,而 relatime 選項僅在先前 atime 早於 mtime 或 ctime 或者先前 atime 超過 24 小時之前時才會更新 atime。許多使用者使用 noatime 沒有任何問題,只要他們不使用依賴 atime 的應用程式,並且這比 relatime 提供了一些好處(讀取時永遠不會寫入 atime)。

從 2.6.30(2009 年 6 月 9 日)開始,Linux 預設使用 relatime,[3] 這樣它就不會在所有檔案讀取時更新 atime。這種行為為大多數用途提供了足夠的效能,並且不應破壞任何重要的應用程式。在做出決定之前,對檔案系統性能進行了擴充套件討論。[4] 事實上,relatime 預設是 Linux 在 2.6.29 版本釋出後應用的首個補丁。在最初的補丁中,relatime 僅在 atime < mtime 或 atime < ctime 時更新 atime;後來進行了修改,以更新 24 小時或更長時間之前的時間,以便 tmpwatch 和 Debian 的流行度計數器(popcon)能夠正常執行。

在參考文獻中可以找到進一步的討論。[5][6]

請注意,ctime 與檔案建立時間無關。它在每次檔案內容更改時(與 mtime 同時)更新,以及在元資料更改時更新,例如檔案許可權檔案所有權以及硬連結的建立和刪除。在某些實現中,ctime 會因檔案重新命名而受到影響(原始 Unix 和現代 Linux 都傾向於這樣做)。

atimemtime 不同,ctime 無法透過 utime() 設定(如 touch 所使用的);唯一能將其設定為任意值的方法是更改系統時鐘。

mtime 等的粒度

[編輯 | 編輯原始碼]

time_t 提供精確到 1 秒的時間。

某些檔案系統提供更高的粒度。在 Linux 核心 2.5.48 及以上版本中,stat 結構支援三個檔案時間戳欄位的納秒級解析度。這些以 stat 結構中的附加欄位形式公開。

FAT 檔案系統提供的 timestamps 粒度為 2 秒。[7]

參考資料

[編輯 | 編輯原始碼]
  1. Kernel Trap: Linux: Replacing atime With relatime,由 Jeremy 於 2007 年 8 月 7 日撰寫
  2. Once upon atime,LWN,由 Jonathan Corbet 於 2007 年 8 月 8 日撰寫
  3. Linux 2 6 30,Linux 核心新手
  4. That massive filesystem thread,LWN,由 Jonathan Corbet 於 2009 年 3 月 31 日撰寫
  5. Installing Linux on USB – Part 4: noatime and relatime mount options
  6. Relatime Recap,Valerie Aurora
  7. How accurate is ruby mtime and friends at StackOverflow.com
[編輯 | 編輯原始碼]
華夏公益教科書