11.08.2018

Linux C, fstat(), stat(), lstat()

這一次要做的筆記是fstat()stat()lstat()這3個函式的差異和比較。fstat()在之前的文章就已經記錄過了,不過當時並沒有注意到還有stat()和lstat()這2個類似的函式。

跟這3個函式相關的,有1個很重要的struct stat結構,如下:
#include <bits/stat.h>

struct stat {
  dev_t st_dev;
  // ID of device containing file (unsigned long int)
  ino_t st_ino;          // inode 數量 (unsigned long int)
  mode_t st_mode;        // 保護 (unsigned int)
  nlink_t st_nlink;      // hard links 數量 (unsigned int)
  uid_t st_uid;          // user ID 擁有者 (unsigned int)
  gid_t st_gid;          // group ID 擁有者 (unsigned int)
  dev_t st_rdev;         // device ID (unsigned long int)
  off_t st_size;         // 以byte為單位,計算大小 (long int)
  blksize_t st_blksize;  // 系統I/O 區塊大小 (long int)
  blkcnt_t st_blocks;    // 區塊取得數量 (long int)
  time_t st_atime;       // 最後一次存取時間
  time_t st_mtime;       // 最後一次修改時間
  time_t st_ctime;       // 狀態修改時間
};

#include <sys/stat.h>

int fstat(int filedes, struct stat *buf);

int stat(const char *path, struct stat *buf);

int lstat(const char *path, struct stat *buf);
這乙些資料型態的大小都不是絕對的,有些還有32-bit/64-bit的差異,可以參考/usr/include/bits/types.h/usr/include/bits/typesizes.h的定義。

這3個函式執行成功會回傳0;執行失敗則是回傳-1。範例程式如下:
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <stdlib.h>
#include <strings.h>

#define FILENAME    "./TEXT.TXT"
#define STAT_FLAG   0 // 0: fstat; 1: stat; 2: lstat

int main(int argc, char **argv, char *envp[])
{
  struct stat stStatBuf;
  int fd = -1, nRet = -1;

  bzero((void *)&stStatBuf, sizeof(struct stat));
#if (STAT_FLAG == 0)
  fd = open(FILENAME, O_RDONLY);
  if (fd == -1) {
    perror("open");
    exit(EXIT_FAILURE);
  }

  nRet = fstat(fd, &stStatBuf);
  if (nRet == -1) {
    perror("fstat");
    exit(EXIT_FAILURE);
  }
#elif (STAT_FLAG == 1)
  nRet = stat(FILENAME, &stStatBuf);
  if (nRet == -1) {
    perror("stat");
    exit(EXIT_FAILURE);
  }
#elif (STAT_FLAG == 2)
  nRet = lstat(FILENAME, &stStatBuf);
  if (nRet == -1) {
    perror("lstat");
    exit(EXIT_FAILURE);
  }
#endif
  printf("st_dev = %u \n", stStatBuf.st_dev);
  printf("st_ino = %u \n", stStatBuf.st_ino);
  printf("st_mode = %u \n", stStatBuf.st_mode);
  printf("st_nlink = %u \n", stStatBuf.st_nlink);
  printf("st_uid = %u \n", stStatBuf.st_uid);
  printf("st_gid = %u \n", stStatBuf.st_gid);
  printf("st_rdev = %d \n", stStatBuf.st_rdev);
  printf("st_size = %ld \n", stStatBuf.st_size);
  printf("st_blksize = %ld \n", stStatBuf.st_blksize);
  printf("st_blocks = %ld \n", stStatBuf.st_blocks);
  printf("st_atime= %s", ctime(&stStatBuf.st_atime));
  printf("st_mtime = %s", ctime(&stStatBuf.st_mtime));
  printf("st_ctime = %s", ctime(&stStatBuf.st_ctime));
#if (STAT_FLAG == 0)
  close(fd);
#endif
  return 0;
}
這3個函式的差異:

1. fstat()函式的第1個參數所傳進去的是一個檔案描述子 (File Descriptor),所以必須先用open()函式來開啟檔案產生描述子。而不能用fopen()來產生檔案指標 (FILE *)。所以在程式運作上若是沒有read(), write()或是seek()等行為,大可不需要使用fstat()函式。

2. stat()和lstat()的運作完全一樣,差別在於若是檔案來源是一個軟連結 (Symbolic Link)的話,lstat()函式只會帶出該軟連結的檔案資訊,並不會指到原始檔案;而stat()函式則是會直接帶出原始檔案的資訊。

參考文章:Linux的fstat()函式

沒有留言:

張貼留言