在 Linux 上原子地交换两个文件的内容

Atomically swap contents of two files on Linux

我有两个文件,AB,每个文件都有自己的内容。

我想交换这两个文件,所以 A 会变成 B,而 B 会变成 A。但我想保证没有其他进程会发现这两个文件处于不一致状态,也没有任何进程会发现这些文件中的任何一个丢失,即使是很短的一段时间。所以,作为副业,我也想保证如果在操作过程中出现任何问题,什么都不会改变(我猜有点像交易)。

在 OS X 上有一个 exchangedata() 函数,所以我想我正在寻找一个 Linux 等效的函数,或者至少是一个等效的方法来执行原子文件交换。

您可以使用(最近的)linux syscall renameat2

定义如下:

int renameat2(int olddir, const char *oldname, 
      int newdir, const char *newname, unsigned int flags);

如果需要,您可以在 the kernel's Git repo 上找到它的源代码。

它与 renameat 基本相同,但是如果您传递标志 RENAME_EXCHANGE 它将交换两个文件而不是将一个文件重命名为另一个文件。

操作是原子的。

我要看你说的"inconsistent state"是什么意思了。如果两个文件在一段时间内是相同的是可以接受的,那么你可以简单地做:

ln A C
ln B D
ln -f D A  
# now, A and B have the same content
ln -f C B

这还取决于您希望已打开文件的进程的行为。请记住路径是 不是 文件,而只是指向文件的链接,因此如果进程 1 通过路径 'A' 打开文件,然后交换名称 A 和 B,进程 1 仍将打开名称 A 引用的文件。