【发布时间】:2019-11-26 15:29:29
【问题描述】:
假设您有一个名为foo 的文件,其中包含一些明确的字节序列X,并且您想用一个包含字节序列Y 的名为bar 的文件自动替换它。这通常通过rename() 系统调用来完成——在这种情况下,通过调用rename("bar", "foo")。但是,您希望遵守以下两个约束:
- 仅当名为
bar的文件确实包含数据Y时才应执行替换,否则将失败。 - 仅当名为
foo的文件确实包含数据X时才应执行替换,否则将失败。
如何正确地做到这一点?
为了防止foo 和bar 在我们调用rename() 之前被编辑,我们可以使用fnctl 或等效项锁定它们。但是锁只有助于防止修改文件数据,它们对目录条目没有影响,因此,当rename() 发挥作用时,foo 或bar 引用的数据可能不一样。
两个数据丢失场景示例,针对上述两个约束:
- 我们已锁定名为
bar的文件,并确保其中包含数据Y - 在我们有时间将
foo替换为bar之前,一些程序将bar替换为之前名为qux的文件,该文件包含数据Z。 - 我们将
foo替换为bar。 - 现在文件
foo,我们预计包含bar的数据,而包含qux的数据。foo和bar的数据都丢失了。
- 我们已锁定名为
- 我们已锁定名为
foo的文件,并确保其中包含数据X。 - 在我们有时间将
foo替换为bar之前,一些程序将foo替换为之前名为qux的文件,该文件包含Z的数据。 - 我们将
foo替换为bar。 - 现在文件
foo确实包含bar的数据,但文件qux的数据在这个过程中丢失了。
- 我们已锁定名为
【问题讨论】:
-
你为什么关心
foo如果你替换它会被编辑? -
@EugeneSh。这是一个重复数据删除工具。我想将
foo替换为指向另一个文件的链接,该文件包含与foo相同的数据,而不会在此过程中丢失数据。 -
这在大多数 CoW 文件系统上都是可能的,比如 Btrfs,它有一个 ioctl 来验证和去重内核中的特定范围。
-
这真的没有任何意义。文件没有名称。目录中有引用文件的名称,我想这就是您的意思,但是....如果您通过链接“栏”访问的文件有一个打开的文件句柄,并且它包含您想要的数据,而其他一些进程更改“bar”以使其引用另一个文件,您的进程仍然具有原始文件并且数据仍然存在。即使文件系统中没有任何链接,您仍然可以修改数据并创建一个名为“foo”的链接。
-
@WilliamPursell 您当然可以修改已取消链接的文件的数据,甚至可以将其数据复制到新文件中,但您不能重命名、链接到它或从中链接,并且依此类推,因为要使这些功能起作用,文件的目录条目必须是可访问的,但目前还不能访问。