【问题标题】:Calling rename() without overwriting unexpected data and without overwriting with unexpected data调用 rename() 而不覆盖意外数据且不覆盖意外数据
【发布时间】:2019-11-26 15:29:29
【问题描述】:

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

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

如何正确地做到这一点?

为了防止foobar 在我们调用rename() 之前被编辑,我们可以使用fnctl 或等效项锁定它们。但是锁只有助于防止修改文件数据,它们对目录条目没有影响,因此,当rename() 发挥作用时,foobar 引用的数据可能不一样。

两个数据丢失场景示例,针对上述两个约束:

    • 我们已锁定名为 bar 的文件,并确保其中包含数据 Y
    • 在我们有时间将 foo 替换为 bar 之前,一些程序将 bar 替换为之前名为 qux 的文件,该文件包含数据 Z
    • 我们将foo 替换为bar
    • 现在文件foo,我们预计包含bar 的数据,而包含qux 的数据。 foobar的数据都丢失了。
    • 我们已锁定名为 foo 的文件,并确保其中包含数据 X
    • 在我们有时间将foo 替换为bar 之前,一些程序将foo 替换为之前名为qux 的文件,该文件包含Z 的数据。
    • 我们将foo 替换为bar
    • 现在文件foo确实包含bar的数据,但文件qux的数据在这个过程中丢失了。

【问题讨论】:

  • 你为什么关心foo如果你替换它会被编辑?
  • @EugeneSh。这是一个重复数据删除工具。我想将foo 替换为指向另一个文件的链接,该文件包含与foo 相同的数据,而不会在此过程中丢失数据。
  • 这在大多数 CoW 文件系统上都是可能的,比如 Btrfs,它有一个 ioctl 来验证和去重内核中的特定范围。
  • 这真的没有任何意义。文件没有名称。目录中有引用文件的名称,我想这就是您的意思,但是....如果您通过链接“栏”访问的文件有一个打开的文件句柄,并且它包含您想要的数据,而其他一些进程更改“bar”以使其引用另一个文件,您的进程仍然具有原始文件并且数据仍然存在。即使文件系统中没有任何链接,您仍然可以修改数据并创建一个名为“foo”的链接。
  • @WilliamPursell 您当然可以修改已取消链接的文件的数据,甚至可以将其数据复制到新文件中,但您不能重命名、链接到它或从中链接,并且依此类推,因为要使这些功能起作用,文件的目录条目必须是可访问的,但目前还不能访问。

标签: c linux posix rename


【解决方案1】:

根据您的评论:

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

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

但是,仍有许多基本问题仍然使这个问题成为问题,至少从以下方面开始:

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

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

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

【讨论】:

  • 经过快速检查,似乎确实更好地依赖文件系统功能。尽管如此,POSIX 不允许对目录条目进行更多控制还是有些遗憾。查看Linux内核,fs层中的rename()函数将目录条目和inode作为参数。
猜你喜欢
  • 2022-01-06
  • 1970-01-01
  • 2016-11-23
  • 2020-08-19
  • 2011-12-15
  • 2018-02-19
  • 2015-12-24
  • 2021-08-01
  • 1970-01-01
相关资源
最近更新 更多