检查close()错误的原因是什么?

R..*_*R.. 15 c linux posix

注意:请在将此标记为重复之前阅读结尾.虽然它很相似,但我在答案中寻找的范围超出了之前的问题所要求的范围.

我倾向于认同的广泛实践往往close纯粹作为文件描述符的资源释放函数而不是具有有意义的失败案例的潜在IO操作.事实上,在解决问题529之前,POSIX在错误之后离开了文件描述符的状态(即它是否仍然被分配)未指定,使得无法以任何有意义的方式对错误进行可移植的响应.

然而,很多GNU软件都花了很大的力气来检查错误close,并且Linux手册页面的close调用失败了"这是一个常见的但仍然很严重的编程错误".NFS和配额被引用作为close可能产生错误但不提供细节的情况.

close在现实世界的系统中,哪些情况可能会失败?它们今天是否相关?我特别感兴趣的是知道是否有任何现代系统close因任何非NFS,非设备节点特定的原因而失败,以及对于NFS或与设备相关的故障,在什么条件下(例如配置)它们可能是看到.

Nis*_*röm 11

曾几何时(2007年3月24日),Eric Sosmancomp.lang.c新闻组中分享了以下故事:

(让我首先承认一个小小的谎言:它不是fclose(),其失败未被发现,但是POSIX close()函数;应用程序的这一部分使用了POSIX I/O.然而,谎言是无害的,因为CI/O设施会以完全相同的方式失败,并且未检测到的故障也会产生相同的后果.我将描述C的I/O方面发生的事情,以避免过多地停留在POSIX上.)

理查德托宾描述的情况非同样如此.该应用程序是一个文档管理系统,它将文档文件加载到内存中,将用户的编辑应用于内存副本,然后在被告知保存编辑时将所有内容写入新文件.为安全起见,它还维护了一个级别的"旧版本"备份:保存操作写入临时文件,然后如果成功则删除旧备份,将旧文档文件重命名为备份名称,并重命名为临时文件到文件.bak - > trash,doc - > bak,tmp - > doc.

写入临时文件步骤几乎检查了所有内容.显然,fopen(),以及所有fwrite()和甚至最后的fflush()都被检查错误指示 - 但fclose()不是.在一个系统上,最后几个磁盘块实际上没有被分配,直到fclose() - I/O系统位于VMS的低级文件访问机制之上,并且在安排中有一点点不同步.

客户的系统启用了磁盘配额,受害者接近他的限制.他打开了一份文件,编辑了一段时间,保存了他的工作到目前为止,并且超出了他的配额 - 由于错误直到未经检查的fclose()才出现,因此没有检测到.考虑到保存成功,应用程序丢弃旧备份,将原始文档重命名为备份,并将截断的临时文件重命名为新文档.用户工作了一段时间并再次保存 - 同样的事情,除了你会注意到这次唯一幸存的完整文件被删除,备份和主文档文件都被截断.结果:整个文档文件变成了垃圾,不仅仅是最新的工作会话,而是之前的所有内容.

正如墨菲所说的那样,受害者是该部门的老板,该部门为我们的软件购买了数百个许可证,我有幸飞往圣路易斯被扔到狮子身上.

[...]

在这种情况下,fclose()的失败(如果检测到)将停止删除和重命名序列.用户可能会被告知"嘿,保存文档时出现问题;对此进行一些操作并再试一次.同时,磁盘上没有任何变化." 即使他无法保存他最新一批作品,他至少也不会丢失以前的所有作品.

  • @R ..:允许使用fuse文件系统缓存*logical*文件,因为访问它的所有进程都将看到相同的缓存状态.在任何时候都不需要刷新缓存来说明下划线文件系统; 如果它在关闭时进行最终刷新,那么这是报告写入错误的完全有效点(源自底层存储文件系统,而不是逻辑层).NisseEngström:融合文件系统与VMS文件系统没有什么不同,所以在我看来,这个轶事是有效和有用的. (2认同)

Ant*_*ton 1

考虑一下你的问题的反面:“在什么情况下我们可以保证close会成功?” 答案是:

  • 当你正确调用它时,并且
  • 当您知道该文件所在的文件系统不会从close该操作系统和内核版本中返回错误时

如果您确信您的程序没有任何逻辑错误并且您可以完全控制内核和文件系统,那么您不需要检查 的返回值close

否则,您必须问自己您有多关心诊断问题close。我认为检查和记录错误以用于诊断目的是有价值的:

  • 如果编码员犯了逻辑错误并将无效的 fd 传递给close,那么您将能够快速追踪到它。这可能有助于在错误引起问题之前尽早发现它。
  • 如果用户在close(例如)数据未刷新时返回错误的环境中运行程序,那么您将能够快速诊断数据损坏的原因。这是一个简单的危险信号,因为您知道该错误不应该发生。