为什么 Linux 对目录使用 getdents() 而不是 read()?

2024-05-14

我浏览 K&R C 时注意到,为了读取目录中的条目,他们使用了:

while (read(dp->fd, (char *) &dirbuf, sizeof(dirbuf)) == sizeof(dirbuf))
    /* code */

Where dirbuf是系统特定的目录结构,并且dp->fd有效的文件描述符。在我的系统上,dirbuf本来会是一个struct linux_dirent。请注意,一个struct linux_dirent有一个灵活的数组成员作为条目名称,但为了简单起见,我们假设它没有。 (在这种情况下处理灵活的数组成员只需要一点额外的样板代码)。

然而,Linux 不支持这种结构。使用时read()尝试读取上面的目录条目,read()回报-1 and errno被设定为EISDIR.

相反,Linux 专门提供了一个系统调用来读取目录,即getdents()系统调用。然而,我注意到它的工作方式与上面几乎相同。

while (syscall(SYS_getdents, fd, &dirbuf, sizeof(dirbuf)) != -1)
    /* code */

这背后的理由是什么?与使用相比似乎没有什么好处read()正如 K&R 中所做的那样。


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 型会有困难。所以getdentsVFS 调用处理这个问题。

难道 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”。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 Linux 对目录使用 getdents() 而不是 read()? 的相关文章

  • 错误:表达式不可赋值三元运算符

    我有以下代码 MPLABX XC8 编译器给出此错误 错误 表达式不可分配 U1ERRIRbits RXFOIF uart1 oerr 1 uart1 oerr 0 这是相关代码部分 typedef union struct bool fe
  • 并行运行多个任务

    我有一个代理列表 每个代理都会访问不同的站点并从站点中提取所需的数据 目前它一次只做一个 但我希望同时运行 10 20 个任务 这样它就可以一次性从 20 个站点下载 而不是只下载一个 这是我目前正在做的事情 private async T
  • 如何从经过身份验证的 SecurityToken 中获取声明

    我将令牌作为字符串传递到 SOAP 服务中 并验证了该令牌是否有效 我现在有一个 SecurityToken 在调试模式下我可以看到所有声明 特别是我想传递到另一个方法的 userId 声明 我似乎不知道如何获得这些索赔 现在 我解码了令牌
  • CMake(Ninja 后端)使用 /MT 编译

    我有一个类似的问题CMake 使用 MT 而不是 MD 进行编译 https stackoverflow com questions 14172856 cmake compile with mt instead of md但有一些差异 我正
  • 如何以编程方式删除受信任的根证书颁发机构中的证书?

    我需要能够从组织中的每台电脑中删除特定的证书 是的 我可以逐个座位 但我要到周四才能完成 而且我没有人力逐个座位 是否有使用 C 的编程方式来执行此操作 我认为你不需要编写任何 C 看看certmgr exe del http msdn m
  • 获取列表框中视图中的项目

    我有一个 ListBox 其属性 VirtualizingStackPanel VirtualizationMode 设置为 回收 我正在绑定一个自定义集合 实现IList and IList
  • 我担心我添加了太多接口

    我正在构建我的领域模型并继续重构它 正如我所做的那样 我发现我喜欢接口 因为它允许我根据接口为具体类型创建可重用的方法 控制器 视图 但是 我发现每次向域实体之一添加新属性时 我都会创建一个接口 例如 我有一个会员状态从抽象继承的对象Ent
  • Windows Phone 7 - ScrollViewer 值已更改

    我一直在寻找解决方案 但无法找到正确的解决方案 我的网格宽度为 960 并且有ScrollViewer在里面 现在我想知道滚动时滚动的值 水平偏移 我找到的所有解决方案都是针对 wpf silverlight 的 它对我不起作用 Edit
  • 在 C# 中解析 JS Date.toIsoString

    我需要将 JS 日期存储为 ISO 8601 日期 我目前正在从格式为 2019 06 22T00 00 00 000Z 的表单中获取日期 正如 JS 的 toIsoString 方法所期望的那样 当这个日期传递到我的 API 控制器时 我
  • 维护 VS Test Project 中单元测试方法之间的上下文

    我想按顺序运行以下单元测试 使用随机数字的名称 密码等创建新客户 检索刚刚创建的客户并断言其属性包含相同的随机数 对同一用户调用 ForgotPassword 函数 并使用相同的随机数作为用户名 清楚地看到 我需要生成一次随机数 并在 3
  • 公交车公共交通算法

    我正在开发一个可以查找公交路线的离线 C 应用程序 我可以提取时间表 巴士 路线数据 我正在寻找适用于基本数据的最简单的解决方案 可以使用什么算法来查找从巴士站 A 到巴士站 B 的路线 是否有适用于 C Java 的开源解决方案 数据库的
  • 使用 STL 流时如何格式化我自己的对象?

    我想将我自己的对象输出到 STL 流 但具有自定义格式 我想出了这样的东西 但由于我之前从未使用过 locale 和 imbue 所以我不知道这是否有意义以及如何实现 MyFacet 和operator 所以我的问题是 这是否有意义以及如何
  • 如何在 C++ 中正确使用 cin.fail()

    我正在编写一个程序 从用户那里获取整数输入cin gt gt iUserSel 如果用户输入一个字母 程序就会进入无限循环 我试图用下面的代码来阻止这种情况 但程序进入无限循环并打印出 错误 输入 我该如何修复我的程序 cin gt gt
  • 更改私有模块片段是否会导致模块重新编译?

    On 此页面有关 C 20 模块功能 https www modernescpp com index php c 20 modules private module fragment and header units 我发现了这样的说法 借
  • 运行实体框架自定义工具,它有什么作用?

    在 Visual Studio 中 当使用实体框架并为 tt 和 Context tt 文件应用运行自定义工具时 它是什么以及它有什么作用 为什么它解决数据库同步问题 有时 为什么我应该在运行 tt 之前运行它 Context tt 它被称
  • fgets溢出后如何清除输入缓冲区?

    当输入字符串超出其预定义限制时 我遇到了 fgets 的小问题 以下面的例子为例 for index 0 index lt max index printf Enter the d string index 1 if fgets input
  • Clang 5.0 上的 vsprintf 和 vsnprintf [-Wformat-nonliteral] 警告

    我有这段代码 static void err doit int errnoflag int level const char fmt va list ap int errno save unsigned long n char buf MA
  • 为什么存在系统调用

    我一直在阅读有关系统调用及其在 Linux 中如何工作的内容 我还有更多的阅读要做 但我读过的一件事都没有回答 那就是 为什么我们需要系统调用 我知道系统调用是用户空间程序要求内核执行某些操作的请求 但我的问题基本上是 为什么用户空间程序本
  • java有类似C#的属性吗? [复制]

    这个问题在这里已经有答案了 C 属性 我的意思是 get 和 set 方法 是一个非常有用的功能 java 也有类似 C 的属性吗 我的意思是我们如何在 java 中实现类似以下 C 代码的内容 public string Name get
  • 将同步 zip 操作转换为异步

    我们有一个现有的库 其中一些方法需要转换为异步方法 但是我不确定如何使用以下方法执行此操作 错误处理已被删除 该方法的目的是压缩文件并将其保存到磁盘 请注意 zip 类不公开任何异步方法 public static bool ZipAndS

随机推荐

  • C 中带有指针的结构的内存开销[重复]

    这个问题在这里已经有答案了 我意识到当我的结构包含指针时 它们会产生内存开销 这里有一个例子 typedef struct int num1 int num2 myStruct1 typedef struct int p int num2
  • 我对一些小概念感到困惑

    我对 VBscript 非常陌生 正在努力学习所有概念 在我的实践过程中 我一直有一个疑问 dim a b c set a CreateObject scripting filesystemobject initiate the file
  • 弱变量中间为零

    弱变量什么时候变为零 weak var backgroundNode SKSpriteNode texture SKTexture image initialBackgroundImage backgroundNode position C
  • 如何引用解决方案之外的项目?

    我有一个 Visual Studio C 解决方案 其中包含一些项目 其中一个项目需要引用另一个不属于解决方案的项目 一开始我引用了dll
  • 带缩略图的轮播和 bootstrap v4

    我看到了带有缩略图的轮播演示bootstrap 3 here http jsfiddle net talmand JS6JV 我正在尝试为 bootstrap v4 实现相同的功能 但无法弄清楚如何修复一些 UI 细节 例如左 右阴影覆盖整
  • 将下拉按钮和下拉菜单放在中心?

    div class dropup center block div
  • 网络音频 API:查找、播放/缓冲进度

    当您使用 Chrome 中的音频元素播放音频时 您会听到烦人的咔嗒声和破裂声 至少在我的 64 位 Linux 安装下 即使在我格式化并安装了新的 Fedora 版本之后也是如此 Firefox 和 Opera 都可以 甚至 Virtual
  • 如何显示 zsh 函数定义(如 bash“type myfunc”)?

    如何在 zsh 中显示函数的定义 type foo没有给出定义 在bash中 bash function foo echo hello bash foo hello bash type foo foo is a function foo e
  • Visual Studio 2017 完全支持 C99 吗?

    Visual Studio 的最新版本改进了对 C99 的支持 最新版本VS2017现在支持所有C99吗 如果没有 C99 还缺少哪些功能 No https learn microsoft com en us cpp visual cpp
  • 在 VBA 中按键对字典进行排序

    我使用 VBA 创建了一个字典CreateObject Scripting Dictionary 将源单词映射到要在某些文本中替换的目标单词 这实际上是为了混淆 不幸的是 当我按照下面的代码进行实际替换时 它将按照源单词添加到字典中的顺序替
  • python 日志记录替代方案 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 蟒蛇记录模块 http docs python org library logging html使用起来
  • 这个 JQuery 指令做什么 $(function(){...}) [重复]

    这个问题在这里已经有答案了 我最近一直在研究JQuery 尽管我知道一些东西 但书上有这样一句话我根本无法理解 function current entry 1 有谁知道这条线是如何工作的以及它的作用是什么 它类似于 JQuery 函数中的
  • 在 C++17 中使用 成员的链接错误

    我在 Ubuntu 16 04 上使用 gcc 7 2 并且需要使用 C 17 中的新文件系统库 尽管确实有一个名为experimental filesystem的库 但我无法使用它的任何成员 例如 当我尝试编译此文件时 include
  • ASP.NET 中 HTTP 缓存相关标头的有效含义

    我正在 ASP NET 2 0 中开发一个 Web 应用程序 其中涉及通过资源处理程序 ashx 提供图像 我刚刚实现了处理缓存标头和条件 GET 请求 这样我就不必为每个请求提供所有图像 但我不确定我是否完全理解浏览器缓存发生了什么 图像
  • 当一组工作人员完成时如何执行 Sidekiq 回调

    假设我有一个 Sidekiq 任务将产品处理到我的数据库 每个产品都按商店分组 因此我的代码的一个过于简化的示例将是这样的 stores each do store store products each do product Produc
  • JsGrid 将嵌套对象加载到表中

    我正在 Django 中开发一个 Web 项目并使用 jsGrid 我遇到了问题并且找不到解决方案 我有一个嵌套的 JSON 数据 它是通过组合多个数据库表记录创建的 这是我的 JSON count 3 results personnel
  • #1115 - 未知字符集:'utf8mb4'

    我的电脑上运行着一个本地网络服务器 用于本地开发 我现在正处于导出数据库并导入到我的托管 VPS 的阶段 导出然后导入时出现以下错误 1115 未知字符集 utf8mb4 有人能指出我正确的方向吗 该错误明确表明您没有utf8mb4您的阶段
  • 输出带有SAS表测试结果的表的宏

    Problem 我不是一个非常有经验的 SAS 用户 但不幸的是我可以访问数据的实验室仅限于 SAS 另外 我目前无法访问这些数据 因为它只能在实验室中使用 因此我创建了模拟数据进行测试 我需要创建一个宏来获取值和尺寸PROC MEANS表
  • 如何让 Firebase 与 Java 后端配合使用

    首先 如果这个问题过于抽象或不适合本网站 我想表示歉意 我真的不知道还能去哪里问 目前我已经在 iOS 和 Android 上开发了应用程序 他们将所有状态保存在 Firebase 中 因此所有内容都会立即保存到 Firebase 实时数据
  • 为什么 Linux 对目录使用 getdents() 而不是 read()?

    我浏览 K R C 时注意到 为了读取目录中的条目 他们使用了 while read dp gt fd char dirbuf sizeof dirbuf sizeof dirbuf code Where dirbuf是系统特定的目录结构