调用 rename() 而不覆盖意外数据且不覆盖意外数据

标签 c linux posix rename

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

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

如何正确地做到这一点?

防止foobar在我们打电话之前被编辑 rename() ,我们可以用 fnctl 锁定它们或等效的。但是锁只能帮助防止修改文件数据,它们对目录条目没有影响,所以到rename()做它的魔法,数据foobar引用可能不一样。

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

    • 我们已锁定名为 bar 的文件并确保它包含数据 Y
    • 在我们有时间替换之前 foobar , 一些程序取代了 bar使用以前名为 qux 的文件保存数据 Z .
    • 我们替换foobar .
    • 现在文件 foo ,我们希望它包含 bar 的数据, 而是包含 qux 的数据. foo的数据和 bar迷路了。
    • 我们已锁定名为 foo 的文件并确保它包含数据 X .
    • 在我们有时间替换之前 foobar , 一些程序取代了 foo使用以前名为 qux 的文件保存数据 Z .
    • 我们替换foobar .
    • 现在文件 foo确实包含 bar 的数据, 但文件的数据 qux在这个过程中丢失了。

最佳答案

根据您的评论:

It's for a deduplication tool. I want to replace foo with a link to another file that holds the same data as foo, without losing data in the process

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

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

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

  • 任何打算修改正在删除重复的文件之一的进程都会在硬链接(hard link)后同时修改所有副本,这可能与您的预期相反。

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

关于调用 rename() 而不覆盖意外数据且不覆盖意外数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57081914/

相关文章:

c - 循环永不停止

linux - 从 root (unix) 运行脚本时变量不存储值

linux - curl:/usr/local/lib/libldap_r-2.4.so.2:没有可用的版本信息

java - 来自 Linux-Java 线程转储的套接字信息

c++ - 如何关闭cerr

c - 在 tmp 文件夹中打开文件时使用信号量不起作用

c - 将一维数组添加到 C 中的 POSIX 共享内存对象

c - 添加 HTML 表格标签

c - 三元运算符中的所有参数都是强制性的还是你可以做 "(exp1 ? : value)"?

c - C 中的 open() 函数