函数原型:
struct dirent *readdir(DIR *dirp);
首先纠正一个很多人都错误理解的事实,readdir不是系统调用,它是glibc的封装函数,而且readdir系统调用是存在的,原型如下:
int readdir(unsigend int fd, struct old_linux_dirent *dirp, unsigned int count);
glibc的readdir所调用的系统调用不是readdir而是getdents系统调用。此处说明一下为什么采用封装getdents而不是readdir系统调用,最重要的一个理由是readdir系统调用每次只会读入一个目录项,而getdents会一下子读入尽可能多的目录项至缓冲。我先分析readdir系统调用的实现,具体的代码如下:
1 SYSCALL_DEFINE3(old_readdir, unsigned int, fd, 2 struct old_linux_dirent __user *, dirent, unsigned int, count) 3 { 4 int error; 5 struct fd f = fdget(fd); 6 struct readdir_callback buf = { 7 .ctx.actor = fillonedir, 8 .dirent = dirent 9 }; 10 11 if (!f.file) 12 return -EBADF; 13 14 error = iterate_dir(f.file, &buf.ctx); 15 if (buf.result) 16 error = buf.result; 17 18 fdput(f); 19 return error; 20 }
6-9行:设置目录项填充函数为fillonedir,filonedir的具体实现不分析,只需知道每次只填充一个目录项即可(作为替代,将会分析更加复杂的filldir函数)
14行:iterate_dir是vfs的封装函数,该函数调用具体的文件系统的iterate函数填充目录
注: 3.11之前并不使用iterate作为读目录的函数而是使用readdir函数
总结:readdir系统调用忽略了count参数并且每次只读一个目录项
接下来分析glibc的readdir函数实现,这个过程可能比较复杂,有兴趣的可以看看,首先给出readdir的实现:
1 DIRENT_TYPE * 2 __READDIR (DIR *dirp) 3 { 4 DIRENT_TYPE *dp; 5 int saved_errno = errno; 6 7 #ifndef NOT_IN_libc 8 __libc_lock_lock (dirp->lock); 9 #endif 10 11 do 12 { 13 size_t reclen; 14 15 if (dirp->offset >= dirp->size) 16 { 17 /* We've emptied out our buffer. Refill it. */ 18 19 size_t maxread; 20 ssize_t bytes; 21 22 #ifndef _DIRENT_HAVE_D_RECLEN 23 /* Fixed-size struct; must read one at a time (see below). */ 24 maxread = sizeof *dp; 25 #else 26 maxread = dirp->allocation;