fstat、stat和lstat的區別
stat系統呼叫系列包括了fstat、stat和lstat,它們都是用來返回“相關檔案狀態資訊”的,三者的不同之處在於設定原始檔的方式不同。
1
首先隆重介紹的是一個非常重要的”VIP”人物,他是fstat, stat和lstat三者都要用到的一個結構體型別,名字叫做struct stat。可以說,沒有這個struct stat的支援,上述三個系統呼叫將寸步難行。
這個struct stat結構體在不同的UNIX/Linux系統中的定義是有小的區別的,但你完全不用擔心,這並不會影響我們的使用。
在struct stat結構體中我們常用的且各個平臺都一定有的域是:
st_mode 檔案許可權和檔案型別資訊
(記住這個黑體橘紅色)
st_ino 與該檔案關聯的inode
st_dev 儲存檔案的裝置
st_uid 檔案屬主的UID號
st_gid 檔案屬主的GID號
st_atime 檔案上一次被訪問的時間
st_ctime 檔案的許可權、屬主、組或內容上一次被修改的時間
st_mtime 檔案的內容上一次被修改的時間。(和st_ctime的不同之處顯而易見)
st_nlink 該檔案上硬連線的個數
我分別提取了solaris(UNIX)和fedora(Linux)的struct stat結構體的原始定義:大家可以自己比對一下便可以發現兩者確實有所不同,但主要的域是完全相同的。
solaris的struct stat定義:
struct stat {
dev_t st_dev;
ino_t st_ino;
mode_t st_mode;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
dev_t st_rdev;
off_t st_size;
timestruc_t st_atim;
timestruc_t st_mtim;
timestruc_t st_ctim;
blksize_t st_blksize;
blkcnt_t st_blocks;
char st_fstype[_ST_FSTYPSZ];
};
fedora的struct stat定義:
struct stat
{
__dev_t st_dev; /* Device. */
unsigned short int __pad1;
__ino_t st_ino; /* File serial number. */
__mode_t st_mode; /* File mode. */
__nlink_t st_nlink; /* Link count. */
__uid_t st_uid; /* User ID of the file’s owner. */
__gid_t st_gid; /* Group ID of the file’s group.*/
__dev_t st_rdev; /* Device number, if device. */
unsigned short int __pad2;
__off_t st_size; /* Size of file, in bytes. */
__blksize_t st_blksize; /* Optimal block size for I/O. */
__blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */
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. */
unsigned long int __unused4;
unsigned long int __unused5;
};
2
大家一定注意到了,在上面列舉域的時候,我在st_mode處使用了黑體橘紅色標識,原因在於這個域不像其他域那麼容易使用,其他的域的值顯而易見,而st_mode域是需要一些巨集予以配合才能使用的。其實,通俗說,這些巨集就是一些特定位置為1的二進位制數的外號,我們使用它們和st_mode進行”&”操作,從而就可以得到某些特定的資訊。
檔案型別標誌包括:
S_IFBLK:檔案是一個特殊的塊裝置
S_IFDIR:檔案是一個目錄
S_IFCHR:檔案是一個特殊的字元裝置
S_IFIFO:檔案是一個FIFO裝置
S_IFREG:檔案是一個普通檔案(REG即使regular啦)
S_IFLNK:檔案是一個符號連結
其他模式標誌包括:
S_ISUID:檔案設定了SUID位
S_ISGID:檔案設定了SGID位
S_ISVTX:檔案設定了sticky位
用於解釋st_mode標誌的掩碼包括:
S_IFMT:檔案型別
S_IRWXU:屬主的讀/寫/執行許可權,可以分成S_IXUSR, S_IRUSR, S_IWUSR
S_IRWXG:屬組的讀/寫/執行許可權,可以分成S_IXGRP, S_IRGRP, S_IWGRP
S_IRWXO:其他使用者的讀/寫/執行許可權,可以分為S_IXOTH, S_IROTH, S_IWOTH
還有一些用於幫助確定檔案型別的巨集定義,這些和上面的巨集不一樣,這些是帶有引數的巨集,類似與函式的使用方法:
S_ISBLK:測試是否是特殊的塊裝置檔案
S_ISCHR:測試是否是特殊的字元裝置檔案
S_ISDIR:測試是否是目錄(我估計find . -type d的原始碼實現中就用到了這個巨集)
S_ISFIFO:測試是否是FIFO裝置
S_ISREG:測試是否是普通檔案
S_ISLNK:測試是否是符號連結
S_ISSOCK:測試是否是socket
3
我們已經學習完了struct stat和各種st_mode相關巨集,現在就可以拿它們和stat系統呼叫相互配合工作了!
int fstat(int filedes, struct stat *buf);
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
聰明人一眼就能看出來fstat的第一個引數是和另外兩個不一樣的,對!fstat區別於另外兩個系統呼叫的地方在於,fstat系統呼叫接受的是 一個“檔案描述符”,而另外兩個則直接接受“檔案全路徑”。檔案描述符是需要我們用open系統呼叫後才能得到的,而檔案全路經直接寫就可以了。
stat和lstat的區別:當檔案是一個符號連結時,lstat返回的是該符號連結本身的資訊;而stat返回的是該連結指向的檔案的資訊。(似乎有些暈吧,這樣記,lstat比stat多了一個l,因此它是有本事處理符號連結檔案的,因此當遇到符號連結檔案時,lstat當然不會放過。而 stat系統呼叫沒有這個本事,它只能對符號連結檔案睜一隻眼閉一隻眼,直接去處理連結所指檔案嘍)
判斷檔案是否存在的程式碼例項
struct stat s;
int r = stat(pszDir, &s);
if((r == 0) && (s.st_mode & S_IFDIR) == S_IFDIR)
{
return true;//存在返回true
}