getdents
将返回struct linux_dirent
。它将为任何底层类型的文件系统执行此操作。 “磁盘上”格式可能完全不同,只有给定的文件系统驱动程序知道,因此简单的用户空间读取调用无法工作。那是,getdents
可以从本机格式转换来填充linux_dirent
.
难道用 read() 从文件中读取字节不能说同样的话吗?文件内数据的磁盘格式不需要在文件系统之间统一,甚至不需要在磁盘上连续 - 因此,从磁盘读取一系列字节将再次成为我希望委托给文件系统驱动程序的事情。
不连续的文件数据由 VFS [“虚拟文件系统”] 层处理。无论 FS 选择如何组织文件的块列表(例如 ext4 使用“inodes”:“索引”或“信息”节点。这些节点使用“ISAM”(“索引顺序访问方法”)组织。但是, MS/DOS FS 可以有完全不同的组织)。
每个 FS 驱动程序在启动时都会注册一个 VFS 函数回调表。对于给定的操作(例如open/close/read/write/seek
),表中有对应的条目。
VFS 层(即从用户空间系统调用)将“调用”FS 驱动程序,FS 驱动程序将执行操作,执行其认为必要的任何操作来满足请求。
我假设 FS 驱动程序会知道磁盘上常规文件内数据的位置 - 即使数据是碎片化的。
是的。例如,如果读取请求是从文件中读取前三个块(例如0、1、2),FS将查找文件的索引信息并获取要读取的物理块列表(例如1000000、 200,37) 从磁盘表面。这一切都在 FS 驱动程序中透明地处理。
用户空间程序将简单地看到其缓冲区被正确的数据填充,而不考虑 FS 索引和块获取必须有多复杂。
也许将其称为传输 inode 数据更为合适,因为存在文件的 inode(即 inode 具有用于“分散/收集”文件的 FS 块的索引信息)。但是,FS 驱动程序也在内部使用它来从目录中读取。也就是说,每个目录都有一个索引节点来跟踪该目录的索引信息。
因此,对于 FS 驱动程序来说,目录很像具有特殊格式信息的平面文件。这些是目录“条目”。这是什么getdents
返回。它“位于”inode 索引层的顶部。
目录条目的长度可以是可变的[基于文件名的长度]。因此,磁盘格式为(称为“A 型”):
static part|variable length name
static part|variable length name
...
但是……一些 FS 的组织方式不同(称之为“B 型”):
<static1>,<static2>...
<variable1>,<variable2>,...
所以,A型组织might被阅读原子地通过用户空间read(2)
调用时,B 型会有困难。所以getdents
VFS 调用处理这个问题。
难道 VFS 不能像 VFS 呈现文件的“平面视图”一样呈现目录的“linux_dirent”视图吗?
就是这样getdents
is for.
再说一次,我假设 FS 驱动程序知道每个文件的类型,因此当对目录而不是一系列字节调用 read() 时,可以返回 linux_dirent。
getdents
did not永远存在。当 dirents 大小固定并且只有oneFS 格式,readdir(3)
可能打电话read(2)
在下面并得到一系列字节[这是only what read(2)
提供]。其实IIRC一开始只有readdir(2)
and getdents
and readdir(3)
不存在。
但是,如果read(2)
是否“短”(例如两个字节太小)?您如何将其传达给应用程序?
我的问题更像是因为 FS 驱动程序可以确定文件是目录还是常规文件(我假设它可以),并且由于它最终必须拦截所有 read() 调用,为什么不读取( )在作为读取 linux_dirent 实现的目录上?
read
目录上的内容不会被拦截并转换为getdents
因为操作系统是极简的。它希望您了解差异并进行适当的系统调用。
You do open(2)
对于文件或目录 [opendir(3)
是包装器并且做open(2)
下]。您可以读/写/查找文件并查找/获取目录。
但是...做read
退货EISDIR
. [边注:我在原来的评论中忘记了这一点]。在它提供的简单“平面数据”模型中,没有办法传达/控制所有这些getdents
可以/确实。
因此,对于内核来说,它更简单,而不是允许使用较差的方式来获取部分/错误的信息and应用程序开发人员要经历getdents
界面。
更远,getdents
做事原子地。如果您正在读取给定程序中的目录条目,则可能有其他程序正在该目录中创建和删除文件或重命名它们 - 就在您的目录中间getdents
顺序。
getdents
将呈现一个atomic看法。文件要么存在,要么不存在。要么已经更名,要么没有。因此,无论你周围发生了多少“骚乱”,你都不会得到“半修改”的观点。当你问getdents
对于 20 个条目,您将获得它们 [如果只有那么多,则为 10 个]。
边注:一个有用的技巧是“过度指定”计数。也就是说,告诉getdents
您想要 50,000 个条目[您必须提供空间]。通常你会得到 100 左右的回报。但是,现在,你所拥有的是atomic完整目录的及时快照。有时我会这样做,而不是循环计数 1--YMMV。您仍然必须防止立即消失,但至少您可以看到它(即后续文件打开失败)
因此,您总是会得到“完整”条目并且no的条目just已删除的文件。那是not说该文件仍然存在,只是说它was那里在当时的getdents
。另一个进程可能会立即删除它,但是not在中间getdents
If read(2)
were如果允许,您必须猜测要读取多少数据,并且不知道哪些条目在部分状态下完全形成。如果 FS 具有上述 B 型组织,则单次读取可以not一步即可原子地获取静态部分和可变部分。
放慢速度在哲学上是不正确的read(2)
做什么getdents
does.
getdents
, unlink
, creat
, rmdir
, and rename
(等)操作是互锁的并且连载的防止任何不一致[更不用说 FS 损坏或泄漏/丢失 FS 块]。换句话说,这些系统调用都“彼此了解”。
如果 pgmA 将“x”重命名为“z”并且 pgmB 将“y”重命名为“z”,则它们don't碰撞。一个先走,另一个第二走,但没有 FS 块丢失/泄漏。getdents
获取整个视图(无论是“x y”、“y z”、“x z”还是“z”),但它永远不会同时看到“x y z”。