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

时间:2014-06-29 15:56:01

标签: c linux posix

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

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

然而,很多GNU软件都花了很大的力气来检查来自close的错误,Linux man page for close调用失败了#34;一个常见但严重的编程错误&#34 ;。 NFS和配额被引用为close可能产生错误但不提供详细信息的情况。

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

2 个答案:

答案 0 :(得分:10)

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

  

(让我首先承认一个小小的谎言:事实并非如此   fclose()失败未被发现,但POSIX关闭()   功能;这部分应用程序使用了POSIX I / O.谎言   但是,这是无害的,因为C I / O设施会有   以完全相同的方式失败,并且未检测到失败   也有同样的后果。我将描述发生的事情   C的I / O条款,以避免过多地停留在POSIX上。)

     

情况与理查德托宾所描述的非常相似。   该应用程序是一个文件管理系统,加载了一个   将文件文件存入内存,将用户的编辑应用于 -   内存复制,然后在被告知时将所有内容写入新文件   保存编辑。它还保持了一个级别的“旧版本”   出于安全考虑进行备份:保存操作写入临时文件   文件,然后如果成功则删除旧备份,   将旧文档文件重命名为备份名称,并重命名为   临时文件到文件。 bak - > trash,doc - > bak,tmp - >文件:

     

写入临时文件步骤几乎检查了所有内容。该   fopen(),显然,也是所有的fwrite(),甚至是最后的   fflush()检查错误指示 - 但fclose()   不是。在一个系统上发生了最后几个磁盘   直到fclose() - I / O才实际分配块   系统坐在VMS的低级文件访问机器上面,和a   这种安排中固有的一点点不同步。

     

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

     

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

     

[...]

     

在这种情况下,fclose()失败(如果检测到)   停止了删除和重命名序列。用户本来就是   告诉“嘿,保存文件有问题;做点什么   关于它,然后再试一次。与此同时,磁盘上没有任何变化。“   即使他无法保存他最新一批作品,他也愿意   至少没有失去以前的一切。

答案 1 :(得分:1)

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

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

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

否则,您必须问自己,您对使用close诊断问题的程度有多关注。我认为检查和记录错误有助于诊断目的:

  • 如果编码器出现逻辑错误并将无效的fd传递给close,那么您将能够快速跟踪它。这可能有助于在问题出现之前及早发现错误。
  • 如果用户在close确实在(例如)数据未刷新时返回错误的环境中运行程序,那么您将能够快速诊断数据被破坏的原因。这是一个简单的红旗,因为你知道不应该发生错误。