1. 程式人生 > >【Linux學習筆記】獲取檔案屬性 — stat()、fstat()、lstat()小結

【Linux學習筆記】獲取檔案屬性 — stat()、fstat()、lstat()小結

相關文章

Linux是基於檔案的作業系統,一切皆檔案。下面就詳細的整理一下關於Linux檔案屬性的內容。

一、檔案屬性函式

系統提供了3個獲取檔案屬性的函式,分別是:stat()、fstat()、lstat()。

1、函式原型

  標頭檔案包含:

  1. #include <unistd.h>
  2. #include <sys/stat.h>
  3. #include <sys/types.h>
  4. int stat(constchar *path, struct stat *buf);  
  5. int fstat(int fd, struct stat *buf);  
  6. int lstat(constchar *path, struct stat *buf);  

  注意:

  (1) stat() 和 lstat() 都是通過檔案路徑和檔名訪問到檔案,然後把檔案屬性放到 struct stat *buf中;而 fstat() 是通過檔案描述符得到檔案的屬性。

  (2) 檔案本身沒有什麼許可權限制,但是檔案的上層目錄必須有訪問許可權才能獲取到檔案的屬性。

  (3) 當檔案是符號連結時,lstat() 返回的是該符號連結本身的資訊;而 stat() 返回的是該該符號連結指向的檔案的資訊。


2、檔案屬性結構體

  在獲取檔案屬性的時候,使用到了系統定義的檔案屬性結構體,結構體定義在<sys/stat.h>中,原型如下:

  1. struct stat {  
  2.    dev_t     st_dev;     /* ID of device containing file */
  3.    ino_t     st_ino;     /* inode number */
  4.    mode_t    st_mode;    /* protection */
  5.    nlink_t   st_nlink;   /* number of hard links */
  6.    uid_t     st_uid;     /* user ID of owner */
  7.    gid_t     st_gid;     /* group ID of owner */
  8.    dev_t     st_rdev;    /* device ID (if special file) */
  9.    off_t     st_size;    /* total size, in bytes */
  10.    blksize_t st_blksize; /* blocksize for file system I/O */
  11.    blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
  12.    time_t    st_atime;   /* time of last access */
  13.    time_t    st_mtime;   /* time of last modification */
  14.    time_t    st_ctime;   /* time of last status change */
  15. };  

其中,st_mode成員描述了檔案的 型別 和 許可權 兩個屬性。

st_mode是32位的整型變數,目前只使用了該變數的低16位。

// 八進位制,過濾出前四位表示的檔案型別

S_IFMT 0170000 bit mask for the file type bit fields

// bit12 ~ bit15

S_IFSOCK 0140000 socket 

S_IFLNK 0120000 symbolic link 

S_IFREG 0100000 regular file 

S_IFBLK 0060000 block device 

S_IFDIR 0040000 directory 

S_IFCHR 0020000 character device 

S_IFIFO 0010000 FIFO

// 特殊屬性,分別為set-user-ID位、set-group-ID位和sticky位

S_ISUID 0004000 set UID bit 

S_ISGID 0002000 set-group-ID bit (see below) 

S_ISVTX 0001000 sticky bit (see below)

// Permission屬性區域的bit0~bit8,即st_mode欄位的最低9位,代表檔案的許可許可權,
// 標識了檔案所有者(owner)、組使用者(group)、其他使用者(other)的
// 讀(r)、寫(w)、執行(x)許可權。

S_IRWXU 00700 mask for file owner permissions 

S_IRUSR 00400 owner has read permission 

S_IWUSR 00200 owner has write permission 

S_IXUSR 00100 owner has execute permission 

S_IRWXG 00070 mask for group permissions 

S_IRGRP 00040 group has read permission 

S_IWGRP 00020 group has write permission 

S_IXGRP 00010 group has execute permission 

S_IRWXO 00007 mask for permissions for others (not in group) 

S_IROTH 00004 others have read permission 

S_IWOTH 00002 others have write permission 

S_IXOTH 00001 others have execute permission

在最後面的示例程式碼中,會通過 st_mode 成員來判斷檔案的型別。

3、返回值及錯誤

  老規矩:

  成功返回0,錯誤返回-1,並設定errno。

  錯誤返回:

  1、ENOENT 引數file_name 指定的檔案不存在
  2、ENOTDIR 路徑中的目錄存在但卻非真正的目錄
  3、ELOOP 欲開啟的檔案有過多符號連線問題, 上限為16 符號連線
  4、EFAULT 引數buf 為無效指標, 指向無法存在的記憶體空間
  5、EACCESS 存取檔案時被拒絕
  6、ENOMEM 核心記憶體不足
  7、ENAMETOOLONG 引數file_name 的路徑名稱太長

二、示例

  1. /* file stat example */
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <sys/stat.h>
  5. #include <sys/types.h>
  6. #include <stdlib.h>
  7. #include <time.h>
  8. int main(int argc, char **argv){  
  9.   struct stat st;  
  10.   if(argc != 2){  
  11.     fprintf(stderr, "Usage: %s <file_pathname> \n", argv[0]);  
  12.         exit(EXIT_FAILURE);  
  13.     }  
  14.     if(stat(argv[1], &st) == -1){  
  15.         perror("stat");  
  16.         exit(EXIT_SUCCESS);  
  17.     }  
  18.     printf("File type:                ");  
  19.     switch(st.st_mode & S_IFMT){  
  20.       case S_IFBLK:  printf("block device\n");            break;  
  21.       case S_IFCHR:  printf("character device\n");        break;  
  22.       case S_IFDIR:  printf("directory\n");               break;  
  23.       case S_IFIFO:  printf("FIFO/pipe\n");               break;  
  24.       case S_IFLNK:  printf("symlink\n");                 break;  
  25.       case S_IFREG:  printf("regular file\n");            break;  
  26.       case S_IFSOCK: printf("socket\n");                  break;  
  27.       default:       printf("unknown?\n");                break;  
  28.   }  
  29.   printf("I-node number:            %ld\n", (long) st.st_ino);  
  30.   printf("Mode:                     %lo (octal)\n", (unsigned long) st.st_mode);  
  31.   printf("Link count:               %ld\n", (long) st.st_nlink);  
  32.   printf("Ownership:                UID=%ld   GID=%ld\n", (long) st.st_uid, (long) st.st_gid);  
  33.   printf("device containing file id:%ld \n", (long) st.st_dev);  
  34.   printf("device id:                %ld \n", (long) st.st_rdev);  
  35.   printf("File size:                %lld bytes\n", (longlong) st.st_size);  
  36.   printf("Preferred I/O block size: %ld bytes\n", (long) st.st_blksize);  
  37.   printf("Blocks allocated:         %lld\n", (longlong) st.st_blocks);  
  38.   printf("Last status change:       %s", ctime(&st.st_ctime));  
  39.   printf("Last file access:         %s", ctime(&st.st_atime));  
  40.   printf("Last file modification:   %s", ctime(&st.st_mtime));  
  41.   exit(EXIT_SUCCESS);  
  42. }  

三、執行結果