如果我想将A重命名为B,但只有当B不存在时,天真的事情就是检查B是否存在(具有访问权限(“B”,F_OK)或类似的东西),如果它不继续重命名.不幸的是,这会打开一个窗口,在这个窗口期间,其他一些进程可能会决定创建B,然后它会被覆盖 – 更糟糕的是,没有迹象表明曾经发生过类似的事情.
其他文件系统访问功能不受此影响 – 打开有O_EXCL(因此复制文件是安全的),最近Linux在syscalls上得到了一整套*,以防止大多数其他竞争条件 – 但不是这个特定的一个(renameat存在),但可以防止完全不同的问题).
它有解决方案吗?
解决方法
从Linux内核3.15(2014年6月发布)开始,可以使用syscall(__ NR_renameat2,AT_FDCWD,“source-file”,“dest-file”,RENAME_NOREPLACE)(包括< syscall.h>,< fcntl.h>和< linux / fs.h>).
这比link()更好,因为永远不会同时存在两个文件名(特别是使用link(),精确定时的断电可能会导致两个名称永远存在).
glibc 2.28(2018年8月发布)添加了一个renameat2()包装器,因此您可以使用它而不是syscall.h和linux / fs.h(尽管您很可能需要< stdio.h>和#define __GNU_SOURCE而不是).
有关更多详细信息,请参阅http://man7.org/linux/man-pages/man2/rename.2.html(尽管确实如此,但在编写时,不知道glibc现在有一个renameat2包装器).