1. 程式人生 > >fstat、stat和lstat的區別

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
 }