在目录上使用`read`系统调用

时间:2013-07-12 15:27:25

标签: c operating-system directory system-calls kernighan-and-ritchie

我在查看K&R 2中的示例(8.6示例 - 列表目录)。它是Linux命令ls或Windows“dir的精简版本。该示例显示了opendirreaddir等函数的实现。我已经尝试过逐字输入代码,但它仍然不起作用。它只是打印一个点(对于当前目录)并退出。

我在代码中找到的一个有趣的事情(在readdir的实现中)是它在目录上调用系统调用,如openread。像 -

这样的东西
int fd, n;
char buf[1000], *bufp;

bufp = buf;
fd = open("dirname", O_RDONLY, 0);
n = read(fd, bufp, 1000);
write(fd, bufp, n);

当我运行此代码时,即使文件夹名称"dirname"中包含一些文件,我也没有输出。

此外,该书还说,该实现适用于 Version 7和System V UNIX系统。这就是它不能在Linux上工作的原因吗?

以下是代码 - http://ideone.com/tw8ouX

Linux不允许对目录进行read系统调用吗?还是别的东西导致了这个?

2 个答案:

答案 0 :(得分:5)

在版本7 UNIX中,只有一个unix文件系统,其目录采用简单的磁盘格式:struct direct数组。阅读它并解释结果是微不足道的。系统调用是多余的。

在现代,Linux和其他类似unix的系统(ext4,ZFS,NTFS!)可以安装多种文件系统,其中一些系统具有复杂的目录格式。你不能对任意目录的原始字节做任何明智的事情。因此内核承担了为目录提供通用接口作为抽象对象的责任。 readdir是该界面的核心部分。

一些现代统一版仍允许在目录上使用read(),因为它是其历史记录的一部分。 Linux历史始于90年代,当时很明显目录上的read()永远不会有用,因此Linux从未允许它。

Linux确实提供了readdir系统调用,但它已经不再使用了,因为有更好的东西出现了:getdents。 readdir一次只返回一个目录条目,因此如果在循环中使用readdir系统调用来获取目录中的文件列表,则在每次循环迭代时输入内核。 getdents将多个条目返回缓冲区。

然而,

readdir是标准接口,因此glibc提供了一个readdir函数,它调用getdents syscall而不是readdir系统调用。在一个普通的程序中,你会在源代码中看到readdir,但在strace中会看到getdir。 C库通过缓冲帮助提高性能,就像在调用getchar()时在常规文件的stdio中一样,并且它一次执行几千字节的read()而不是一堆单字节read()秒。

你永远不会在现代Linux系统上使用原始的无缓冲readdir系统调用,除非你运行很久以前编译过的可执行文件,或者不遗余力地绕过C库。

答案 1 :(得分:1)

实际上Linux不允许read用于目录。请参阅man page并搜索错误 EISDIR 。你会发现

  

如果......(/ p>),read()和pread()函数将失败      

fildes参数引用目录,并且实现不允许使用read()或pread()读取目录。应该使用readdir()函数。

。其他UNIX允许它。