在 Debian(和其他 Linux 发行版)中,readdir 并不是指某一个固定的实现,而是一个 POSIX 接口及其在 Linux 内核、glibc、文件系统层的整体机制。下面从用户态 → C 库 → 内核 → 文件系统逐层说明它的“原理”。
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);
以 Debian + glibc + Linux 内核 为例:
应用程序
↓
glibc (readdir / readdir64)
↓
getdents / getdents64 系统调用
↓
Linux 内核 VFS
↓
具体文件系统(ext4 / xfs / overlay 等)
readdir 本身不是系统调用,而是:
getdents / getdents64DIR 结构体(内部有缓冲区)struct direntstruct __dirstream {
int fd;
char *buf;
size_t buf_size;
size_t offset;
};
Linux 提供两个主要系统调用:
| 系统调用 | 说明 |
|---|---|
getdents |
老接口(32 位) |
getdents64 |
新接口,支持 64 位 inode |
glibc 默认使用 getdents64
int getdents64(unsigned int fd, struct linux_dirent64 *dirp, unsigned int count);
进入内核后:
fd → struct file → f_op->iterate_dir
核心函数:
iterate_dir()
它会调用具体文件系统的 ->readdir 实现。
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_iterate()
→ ext4_read_dirblock()
→ 解析目录块
→ 填充 dir_context
struct ext4_dir_entry_2 {
__le32 inode;
__le16 rec_len;
__u8 name_len;
__u8 file_type;
char name[];
};
opendir 打开目录时获得一个 目录句柄readdir 内部维护 当前偏移量这解释了:
readdir 不保证顺序| 函数 | 状态 |
|---|---|
readdir |
✅ 安全(glibc 内部加锁) |
readdir_r |
❌ 已废弃 |
原因:
readdir 内部已有互斥保护readdir_r 存在接口设计问题sysdeps/unix/sysv/linux/readdir.cfs/readdir.cfs/ext4/dir.cDebian 中的 readdir,本质是 glibc 对 Linux
getdents64系统调用的封装,通过 VFS 调用具体文件系统的目录遍历函数,从目录文件中解析目录项并返回给用户。
如果你愿意,我可以: