stat(2) - Linux 手册页

名称

stat, fstat, lstat - 获取文件状态

概要

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

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

glibc 的功能测试宏要求(参见 feature_test_macros(7))

lstat():
_BSD_SOURCE || _XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
|| /* 自 glibc 2.10 起: */ _POSIX_C_SOURCE >= 200112L

描述

这些函数返回有关文件的信息。文件本身不需要任何权限,但在使用 stat() 和 lstat() 时,需要对 path 中通往该文件的所有目录拥有执行(搜索)权限。

stat() 获取 path 指向的文件状态,并填充到 buf 中。

lstat() 与 stat() 相同,唯一的区别是如果 path 是一个符号链接,则获取的是链接本身的状态,而不是它所指向的文件。

fstat() 与 stat() 相同,唯一的区别是需要获取状态的文件是通过文件描述符 fd 指定的。

所有这些系统调用都会返回一个 stat 结构体,其中包含以下字段

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 */
    blksize_t st_blksize; /* blocksize for file system I/O */
    blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
    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 */
};
st_dev 字段描述了该文件驻留的设备。(major(3) 和 minor(3) 宏可用于解析该字段中的设备 ID。)

st_rdev 字段描述了该文件(inode)所表示的设备。

st_size 字段给出文件的大小(如果是普通文件或符号链接),单位为字节。符号链接的大小是其所包含路径名的长度,不包含结尾的空字节。

st_blocks 字段表示分配给文件的块数,单位为 512 字节。(当文件有空洞时,此值可能小于 st_size/512。)

st_blksize 字段给出了文件系统进行高效 I/O 操作的“首选”块大小。(以较小的块写入文件可能会导致低效的读取-修改-重写。)

并非所有的 Linux 文件系统都实现了所有的时间字段。某些文件系统类型允许以一种方式挂载,使得文件和/或目录的访问不会更新 st_atime 字段。(请参阅 mount(8) 中的 noatimenodiratimerelatime,以及 mount(2) 中的相关信息。)此外,如果文件是以 O_NOATIME 打开的,则不会更新 st_atime;请参阅 open(2)。

st_atime 字段会在文件被访问时发生改变,例如通过 execve(2)、mknod(2)、pipe(2)、utime(2) 和 read(2)(读取超过零字节)。其他例程,如 mmap(2),可能会也可能不会更新 st_atime

st_mtime 字段会在文件被修改时发生改变,例如通过 mknod(2)、truncate(2)、utime(2) 和 write(2)(写入超过零字节)。此外,目录的 st_mtime 会随着该目录下文件的创建或删除而改变。st_mtime 字段不会因所有者、组、硬链接数或模式的更改而改变。

st_ctime 字段会在写入数据或设置 inode 信息(即所有者、组、链接数、模式等)时发生改变。

定义了以下 POSIX 宏来通过 st_mode 字段检查文件类型

S_ISREG(m)

是否是普通文件?

S_ISDIR(m)

目录?

S_ISCHR(m)

字符设备?

S_ISBLK(m)

块设备?

S_ISFIFO(m)

FIFO(命名管道)?

S_ISLNK(m)

符号链接?(不在 POSIX.1-1996 中。)

S_ISSOCK(m)

套接字?(不在 POSIX.1-1996 中。)

st_mode 字段定义了以下标志
设置组 ID 位 (S_ISGID) 有几种特殊用途。对于目录,它表示该目录应使用 BSD 语义:在此目录下创建的文件会从目录继承其组 ID,而不是从创建进程的有效组 ID 继承,并且在此目录下创建的目录也会设置 S_ISGID 位。对于未设置组执行位 (S_IXGRP) 的文件,设置组 ID 位表示强制文件/记录锁定。

目录上的粘滞位 (S_ISVTX) 表示该目录中的文件只能由文件所有者、目录所有者或特权进程重命名或删除。

返回值

成功时返回零。出错时返回 -1,并相应地设置 errno

错误

EACCES

path 的路径前缀中的某个目录拒绝搜索权限。(另请参阅 path_resolution(7)。)

EBADF

fd 无效。

EFAULT

地址错误(Bad address)。

ELOOP

在遍历路径时遇到过多的符号链接。

ENAMETOOLONG
path 太长。
ENOENT

path 的某个组成部分不存在,或 path 是空字符串。

ENOMEM

内存不足(即内核内存)。

ENOTDIR
path 的路径前缀的某个组成部分不是目录。
EOVERFLOW
pathfd 指向的文件,其大小、inode 编号或块数无法分别由 off_tino_tblkcnt_t 类型表示。当例如在未定义 -D_FILE_OFFSET_BITS=64 的 32 位平台上编译的应用程序调用 stat() 操作一个大小超过 (1<<31)-1 字节的文件时,可能会发生此错误。

符合

这些系统调用符合 SVr4、4.3BSD、POSIX.1-2001。

根据 POSIX.1-2001,对符号链接使用 lstat() 仅需在 stat 结构体中返回 st_size 字段和 st_mode 字段的文件类型部分中的有效信息。POSIX.1-2008 强化了该规范,要求 lstat() 在除 st_mode 中的权限位之外的所有字段中都返回有效信息。

使用 st_blocksst_blksize 字段的可移植性可能较差。(它们是在 BSD 中引入的。在不同系统之间,甚至在同一系统涉及 NFS 挂载时,解释可能会有所不同。)如果需要从 <sys/stat.h> 获取 blkcnt_tblksize_t 类型的定义,请定义 _XOPEN_SOURCE 且值为 500 或更高(在包含任何头文件之前)。

POSIX.1-1990 未描述 S_IFMT, S_IFSOCK, S_IFLNK, S_IFREG, S_IFBLK, S_IFDIR, S_IFCHR, S_IFIFO, S_ISVTX 常量,而是要求使用 S_ISDIR() 等宏。S_IF* 常量在 POSIX.1-2001 及更高版本中存在。

S_ISLNK() 和 S_ISSOCK() 宏不在 POSIX.1-1996 中,但在 POSIX.1-2001 中两者都存在;前者来自 SVID 4,后者来自 SUSv2。

UNIX V7(及后续系统)有 S_IREAD, S_IWRITE, S_IEXEC,而 POSIX 规定了其同义词 S_IRUSR, S_IWUSR, S_IXUSR

其他系统

在各种系统中使用过(或正在使用)的值
粘滞位命令出现在 AT&T UNIX 第 32V 版中。

说明

从内核 2.5.48 开始,stat 结构体支持三个文件时间戳字段的纳秒级分辨率。如果定义了 _BSD_SOURCE_SVID_SOURCE 特性测试宏,Glibc 会使用 st_atim.tv_nsec 格式的名称公开每个字段的纳秒分量。这些字段在 POSIX.1-2008 中有规定,且自 2.12 版本起,如果定义了 _POSIX_C_SOURCE 且值为 200809L 或更高,或者定义了 _XOPEN_SOURCE 且值为 700 或更高,glibc 也会公开这些字段名称。如果未定义上述任何宏,则纳秒值将以 st_atimensec 格式的名称公开。在不支持亚秒时间戳的文件系统上,纳秒字段返回的值为 0。

在 Linux 上,lstat() 通常不会触发自动挂载程序操作,而 stat() 会触发(但请参阅 fstatat(2))。

对于 /proc 目录下的大多数文件,stat() 不会返回 st_size 字段中的文件大小;相反,该字段返回的值为 0。

底层内核接口

随着时间的推移,stat 结构体大小的增加导致了三个连续版本的 stat():sys_stat() (插槽 __NR_oldstat), sys_newstat() (插槽 __NR_stat), 和 sys_stat64() (内核 2.4 中新增;插槽 __NR_stat64)。Glibc 的 stat() 包装函数对应用程序隐藏了这些细节,调用内核提供的最新版本的系统调用,并在需要时为旧二进制文件重新打包返回的信息。对于 fstat() 和 lstat() 也适用类似的说明。

示例

以下程序调用 stat() 并显示返回的 stat 结构体中选定的字段。

#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char *argv[])
{
    struct stat sb;

   if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

   if (stat(argv[1], &sb) == -1) {
        perror("stat");
        exit(EXIT_FAILURE);
    }

   printf("File type:                ");

   switch (sb.st_mode & S_IFMT) {
    case S_IFBLK:  printf("block device\n");            break;
    case S_IFCHR:  printf("character device\n");        break;
    case S_IFDIR:  printf("directory\n");               break;
    case S_IFIFO:  printf("FIFO/pipe\n");               break;
    case S_IFLNK:  printf("symlink\n");                 break;
    case S_IFREG:  printf("regular file\n");            break;
    case S_IFSOCK: printf("socket\n");                  break;
    default:       printf("unknown?\n");                break;
    }

   printf("I-node number:            %ld\n", (long) sb.st_ino);

   printf("Mode:                     %lo (octal)\n",
            (unsigned long) sb.st_mode);

   printf("Link count:               %ld\n", (long) sb.st_nlink);
    printf("Ownership:                UID=%ld   GID=%ld\n",
            (long) sb.st_uid, (long) sb.st_gid);

   printf("Preferred I/O block size: %ld bytes\n",
            (long) sb.st_blksize);
    printf("File size:                %lld bytes\n",
            (long long) sb.st_size);
    printf("Blocks allocated:         %lld\n",
            (long long) sb.st_blocks);

   printf("Last status change:       %s", ctime(&sb.st_ctime));
    printf("Last file access:         %s", ctime(&sb.st_atime));
    printf("Last file modification:   %s", ctime(&sb.st_mtime));

   exit(EXIT_SUCCESS);
}

参见

access(2), chmod(2), chown(2), fstatat(2), readlink(2), utime(2), capabilities(7), symlink(7)

引用自

acl(5), amd.conf(5), attr(5), collectd.conf(5), csh(1), dpns_readdirx(3), dump(8), dvips(1), euidaccess(3), ev(3), explain(1), explain(3), explain_stat(3), explain_stat_or_die(3), fakeroot-tcp(1), fallocate(2), fastrm(1), fcdircacheloadfile(3), fgetln(3), file(1), find(1), fsync(2), ftok(3), fts(3), ftw(3), futimesat(2), getfilecon(3), getseuserbyname(3), getxattr(2), glob(3), guestfish(1), guestfs(3), inotify(7), lam_rfposix(2), lfc_readdirxc(3), libinn(3), libinnhist(3), librrd(3), libssh2_sftp_stat_ex(3), link(2), listxattr(2), llvm-ar(1), lslk(8), lsof(8), makedev(3), mgp(1), mirrordir(1), mkdir(2), mkfifo(3), mtree(8), muttrc(5), nfslogsum(8), nhfsstone(8), obsolete(2), path_resolution(2), pax(1), perl561delta(1), perl56delta(1), perlfunc(1), pipe(7), pivot_root(2), proc(5), rdist(1), rdup(1), rdup(8), readline(3), removexattr(2), samefile(1), sec(1), setfilecon(3), setmode(3), setxattr(2), sh(1), spax(1), spu_create(2), spufs(2), spufs(7), star(1), stat(1), statfs(2), strmode(3), sudo(8), syscalls(2), time(7), umask(2), ustat(2), utimensat(2), watchdog(8), xbiff(1), xdvi(1), xfs_db(8), xfs_io(8), zfs(8), zshmodules(1)