在不覆盖意外数据和不覆盖意外数据的情况下调用rename()

时间:2019-07-17 18:08:45

标签: c linux posix rename

假设您有一个名为foo的文件,其中包含确定的字节序列X,并且您想将其原子替换为一个名为bar的文件,其中该文件包含字节序列{{ 1}}。这通常是通过Y系统调用完成的,在这种情况下,是通过调用rename()来完成的。但是,您希望遵守以下两个约束:

  1. 仅当名为rename("bar", "foo")的文件确实包含数据bar时才执行替换,否则应失败。
  2. 仅当名为Y的文件确实包含数据foo时才执行替换,否则应失败。

如何正确执行此操作?

为防止在调用X之前对foobar进行编辑,我们可以用rename()或等效名称来锁定它们。但是锁仅有助于防止文件数据被修改,它们对目录条目没有影响,因此,在fnctl发挥神奇作用时,数据rename()foo指向可能不一样。

针对上述两个约束的两个数据丢失方案示例:

    • 我们已锁定名为bar的文件,并确保其中包含数据bar
    • 在我们有时间将Y替换为foo之前,某些程序将bar替换为以前名为bar的文件,其中包含数据qux
    • 我们将Z替换为foo
    • 现在,文件bar(我们希望包含foo的数据)代替了bar的数据。 quxfoo的数据都丢失了。
    • 我们已锁定名为bar的文件,并确保它包含数据foo
    • 在我们有时间将X替换为foo之前,某些程序将bar替换为以前名为foo的文件,其中包含数据qux
    • 我们将Z替换为foo
    • 现在文件bar确实包含foo的数据,但是文件bar的数据在此过程中已经丢失。

1 个答案:

答案 0 :(得分:2)

根据您的评论:

  

用于重复数据删除工具。我想用指向另一个文件的链接替换foo,该文件包含与foo相同的数据,而不会在进程中丢失数据

我认为您有XY问题。您不能使rename操作相对于文件内容是原子的。但是,您的目标只是避免在重复数据删除过程中文件意外更改时避免数据丢失。这适用于其他方法,例如保持与旧文件的硬链接并在执行重命名后 将其还原(还原为原始名称或特殊的恢复区域),然后比较以检测是否已更改

但是,至少有许多基本问题仍然使该问题成为问题:

  • 一个进程可能具有一个打开的句柄,可以在未修改的情况下写入旧文件,并且可以在删除重复数据后对其进行修改和关闭。在这种情况下,关闭操作将使其孤立,并且数据将丢失。

  • 任何打算修改其中一个重复数据删除文件的进程都将在硬链接后同时修改所有重复项,这可能与您的预期相反。

如果您的目标是重复数据删除以节省空间,但保留语义以允许修改,则您确实需要一个文件系统,该文件系统使用写时复制语义(而不是硬链接)对fs块进行重复数据删除。另一方面,如果要硬链接,则应在重复数据删除操作期间和之后将整个重复数据删除树视为本质上是只读的。

相关问题