温馨提示×

debian readdir怎么实现

小樊
32
2026-07-13 18:48:32
栏目: 智能运维

Debian / Linux 下,readdir 的实现涉及 用户态 glibc内核 VFS 两层。下面按“从你调用 readdir() 到内核返回目录项”的完整流程说明。


一、用户态:readdir() 是什么

在 Debian 中,readdir()POSIX 标准接口,定义在:

#include <dirent.h>

struct dirent *readdir(DIR *dirp);

它用于读取一个打开目录流中的下一个目录项。


二、glibc 中的 readdir() 实现(用户态)

Debian 使用 glibc,其 readdir() 实现大致流程如下:

1️⃣ opendir() 打开目录

DIR *dir = opendir("/tmp");

opendir() 内部会:

  • 调用 open(dirpath, O_RDONLY | O_DIRECTORY)
  • 返回一个 DIR * 结构体(包含 fd、缓冲区等)

2️⃣ readdir() 内部逻辑

glibc 的 readdir() 不是直接对应一个系统调用,而是封装了 getdents / getdents64

简化逻辑如下:

struct dirent *readdir(DIR *dirp)
{
    if (dirp->buf_pos >= dirp->buf_end) {
        // 从内核读取一批目录项
        int n = syscall(SYS_getdents64, dirp->fd,
                        dirp->buf, sizeof(dirp->buf));
        if (n <= 0)
            return NULL;

        dirp->buf_pos = 0;
        dirp->buf_end = n;
    }

    // 从缓冲区解析一个 dirent
    struct dirent *entry = (struct dirent *)(dirp->buf + dirp->buf_pos);
    dirp->buf_pos += entry->d_reclen;

    return entry;
}

关键点

  • readdir()缓冲式读取
  • 一次系统调用可能返回多个目录项
  • 用户只看到一个个 struct dirent

三、内核态:getdents / getdents64

1️⃣ 系统调用

函数 说明
getdents 老接口(32 位)
getdents64 新接口(64 位 inode)

glibc 在 Debian amd64 上通常使用 getdents64


2️⃣ 内核入口(简化)

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

路径:

getdents64
 └── vfs_readdir()
     └── file->f_op->iterate_shared()
         └── 具体文件系统

四、VFS 与具体文件系统

1️⃣ VFS 层

int vfs_readdir(struct file *file, struct dir_context *ctx)

VFS 统一目录读取接口。


2️⃣ ext4 示例

以 ext4 为例:

ext4_dir_operations = {
    .iterate_shared = ext4_readdir,
};

ext4_readdir() 会:

  • 读取目录文件的 数据块
  • 解析 ext4 的目录项结构
  • 填充 struct dirent

五、目录项结构

用户态 struct dirent

struct dirent {
    ino_t          d_ino;
    off_t          d_off;
    unsigned short d_reclen;
    unsigned char  d_type;
    char           d_name[];
};

内核态 struct linux_dirent64

struct linux_dirent64 {
    u64 d_ino;
    s64 d_off;
    unsigned short d_reclen;
    unsigned char d_type;
    char d_name[];
};

六、一个简单的 readdir 示例

#include <stdio.h>
#include <dirent.h>

int main() {
    DIR *dir = opendir(".");
    if (!dir) return 1;

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

    closedir(dir);
    return 0;
}

编译:

gcc readdir.c -o readdir

七、总结一句话

Debian 中的 readdir() 是 glibc 对 getdents64 系统调用的封装;内核通过 VFS 调用具体文件系统(如 ext4)读取目录数据并返回目录项。


如果你愿意,我可以:

  • 画一张 readdir 调用流程图
  • 分析 ext4 / proc / overlayfs 的 readdir 实现差异
  • readdir 为什么不是线程安全 / 可重入的
  • 对比 readdir vs getdents vs readdir_r

你更想深入哪一块?

0