温馨提示×

Debian readdir原理

小樊
36
2026-07-27 23:18:21
栏目: 智能运维

在 Debian(和其他 Linux 发行版)中,readdir 并不是指某一个固定的实现,而是一个 POSIX 接口及其在 Linux 内核、glibc、文件系统层的整体机制。下面从用户态 → C 库 → 内核 → 文件系统逐层说明它的“原理”。


一、readdir 是什么?

readdir 是用于读取目录内容的函数,定义在 POSIX 标准中。

常见相关接口:

#include <dirent.h>

DIR *opendir(const char *name);
struct dirent *readdir(DIR *dirp);
int closedir(DIR *dirp);

示例:

DIR *dir = opendir("/tmp");
struct dirent *entry;

while ((entry = readdir(dir)) != NULL) {
    printf("%s\n", entry->d_name);
}
closedir(dir);

二、readdir 在 Debian 中的整体调用链

Debian + glibc + Linux 内核 为例:

应用程序
  ↓
glibc (readdir / readdir64)
  ↓
getdents / getdents64 系统调用
  ↓
Linux 内核 VFS
  ↓
具体文件系统(ext4 / xfs / overlay 等)

三、glibc 层:readdir 的本质

1️⃣ readdir 不是系统调用

readdir 本身不是系统调用,而是:

  • glibc 提供的 库函数
  • 内部会调用 Linux 的 getdents / getdents64

2️⃣ glibc 做了什么?

  • 维护一个 DIR 结构体(内部有缓冲区)
  • 一次系统调用读取多个目录项
  • 在用户态缓存并返回一个个 struct dirent
struct __dirstream {
    int fd;
    char *buf;
    size_t buf_size;
    size_t offset;
};

四、内核层:getdents / getdents64

1️⃣ 系统调用

Linux 提供两个主要系统调用:

系统调用 说明
getdents 老接口(32 位)
getdents64 新接口,支持 64 位 inode

glibc 默认使用 getdents64

int getdents64(unsigned int fd, struct linux_dirent64 *dirp, unsigned int count);

2️⃣ 内核中做什么?

进入内核后:

fd → struct file → f_op->iterate_dir

核心函数:

iterate_dir()

它会调用具体文件系统的 ->readdir 实现。


五、VFS 层(虚拟文件系统)

Linux 使用 VFS(Virtual File System) 抽象目录操作。

目录在 VFS 中是一个特殊文件,其操作由:

struct file_operations {
    ...
    int (*iterate_shared)(struct file *, struct dir_context *);
};

或老版本:

int (*readdir)(struct file *, struct dir_context *);

六、具体文件系统层(以 ext4 为例)

ext4 的 readdir 实现

ext4 中目录本身也是文件,目录项存储在:

  • 目录文件的数据块中
  • 使用 目录项结构(dx_entry / ext4_dir_entry)

调用路径大致是:

ext4_iterate()
  → ext4_read_dirblock()
  → 解析目录块
  → 填充 dir_context

目录项结构(简化)

struct ext4_dir_entry_2 {
    __le32 inode;
    __le16 rec_len;
    __u8 name_len;
    __u8 file_type;
    char name[];
};

七、为什么 readdir 返回的是“快照式”结果?

  • opendir 打开目录时获得一个 目录句柄
  • readdir 内部维护 当前偏移量
  • 内核返回的是当前目录内容
  • 后续对目录的修改(新增/删除)不一定反映到已打开的 DIR 流

这解释了:

  • readdir 不保证顺序
  • 删除正在遍历的文件是安全的
  • 多线程/多进程下行为复杂

八、readdir 与 readdir_r(已废弃)

函数 状态
readdir ✅ 安全(glibc 内部加锁)
readdir_r ❌ 已废弃

原因:

  • readdir 内部已有互斥保护
  • readdir_r 存在接口设计问题

九、Debian 下的实际实现位置(参考)

  • glibc:sysdeps/unix/sysv/linux/readdir.c
  • 内核:fs/readdir.c
  • ext4:fs/ext4/dir.c

十、一句话总结

Debian 中的 readdir,本质是 glibc 对 Linux getdents64 系统调用的封装,通过 VFS 调用具体文件系统的目录遍历函数,从目录文件中解析目录项并返回给用户。

如果你愿意,我可以:

  • 画一张 readdir 调用流程图
  • 分析 overlayfs / procfs / tmpfs 的 readdir 差异
  • 结合 strace / ltrace 实际演示一次 readdir 调用

0