sys_stat (调用号为4)、sys_fstat (调用号为5)和 sys_lstat (调用号为6)是 Linux 系统中的三个基本文件状态查询系统调用,用于获取文件的元信息(如大小、权限、时间戳等)。

这三个系统调用虽然都用于获取文件元信息,但三者仍然存在明显的不同。sys_statsys_lstat都是通过文件的路径对文件进行访问的,而sys_fstat 却是通过文件描述符fd 对某一文件进行访问。与sys_stat相比,sys_lstat 虽然也通过文件的路径对文件进行访问,但在处理符号链接的方式上有很大的区别。前者查询到符号链接时,会对其所指向的那个目标文件进行查询;而后者则会对符号链接这个文件本身进行查询,并不会重定向至符号链接所指向的那个文件。

无论是这三者中的哪一个,返回元信息的结构体struct stat 的定义都是一致的。struct stat 被定义为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct stat {
dev_t st_dev; /* 文件所在设备号 */
ino_t st_ino; /* 文件 i-node 号 */
nlink_t st_nlink; /* 硬链接数 */
mode_t st_mode; /* 文件类型与权限模式 */
uid_t st_uid; /* 所有者用户 ID */
gid_t st_gid; /* 所有者组 ID */
dev_t st_rdev; /* 特殊文件的设备号(字符/块设备) */
off_t st_size; /* 文件大小(字节数) */
blksize_t st_blksize; /* 文件系统 I/O 块大小 */
blkcnt_t st_blocks; /* 分配的块数 */

/* 时间戳 */
struct timespec st_atim; /* 最后访问时间 */
struct timespec st_mtim; /* 最后修改时间 */
struct timespec st_ctim; /* i-node 状态改变时间 */
};
  • sys_stat

    • 函数原型

      1
      int stat(const char *pathname, struct stat *statbuf);
    • 参数

      • pathname: 要查询的文件路径(字符串)
      • statbuf: 指向 struct stat 结构的指针,用于存储文件信息
    • 返回值

      • 成功时返回 0
      • 失败时返回 errno(如 ENOENT, EACCES, ENOTDIR
  • sys_fstat

    • 函数原型

      1
      2
      int fstat(int fd, struct stat *statbuf);

    • 参数

      • fd: 已打开文件的文件描述符
      • statbuf: 指向 struct stat 结构的指针,用于存储文件信息
    • 返回值

      • 成功时返回 0
      • 失败时返回 errno(如 EBADF, EFAULT
  • sys_lstat

    • 函数原型

      1
      2
      int lstat(const char *pathname, struct stat *statbuf);

    • 参数

      • pathname: 要查询的文件路径(字符串)
      • statbuf: 指向 struct stat 结构的指针,用于存储文件信息
    • 返回值

      • 成功时返回 0
      • 失败时返回 errno(如 ENOENT, EACCES, ENOTDIR
  • 用例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    	.equ SYS_STAT, 4         # sys_stat 系统调用号
    .equ SYS_FSTAT, 5 # sys_fstat 系统调用号
    .equ SYS_LSTAT, 6 # sys_lstat 系统调用号

    .section .data
    filename:
    .ascii "/tmp/test.txt"
    statbuf:
    .space 144 # struct stat 通常为 144 字节(x86-64)

    .section .text
    .globl _start

    _start:
    # 使用 sys_stat 查询文件状态
    mov $SYS_STAT, %rax
    lea filename(%rip), %rdi
    lea statbuf(%rip), %rsi
    syscall

    # 使用 sys_fstat 查询已打开文件描述符状态
    # 假设文件描述符保存在 %r8
    mov $SYS_FSTAT, %rax
    mov %r8, %rdi
    lea statbuf(%rip), %rsi
    syscall

    # 使用 sys_lstat 查询符号链接状态
    mov $SYS_LSTAT, %rax
    lea filename(%rip), %rdi
    lea statbuf(%rip), %rsi
    syscall

    # 退出
    mov $60, %rax
    xor %rdi, %rdi
    syscall

    分析

    • sys_stat 根据文件路径获取目标文件的状态信息,如果路径是符号链接,它返回链接指向文件的信息。
    • sys_fstat 直接通过文件描述符获取文件状态,不依赖文件路径。
    • sys_lstat 类似于 stat,但如果路径是符号链接,它返回链接本身的信息而不是目标文件。

    在汇编中,这三个系统调用都通过 %rax 指定系统调用号,文件路径或文件描述符通过 %rdistruct stat 结构指针通过 %rsi,调用 syscall 指令执行系统调用,返回值存放在 %rax:成功为 0,失败为 -errno