Reputation:
Is there a non-platform-specific way of doing an atomic "rename File1 to File2 if File2 does not exist, otherwise give an error"? I know I could just check whether File2 exists, then rename the file if it doesn't, but this introduces a potential race condition when some other process creates File2 between the check and the rename()
.
Under Linux there is the renameat2()
function which does exactly this with the RENAME_NOREPLACE
flag set. Unfortunately, the manpage says
renameat2() is Linux-specific.
I don't even know whether all libc implementations support this call, or only glibc.
For my usecase, renaming inside the same directory is enough, I don't need to have support for moving to a whole different path.
This is potentially related to https://stackoverflow.com/a/230581/5562035 and Atomically swap contents of two files on Linux
Upvotes: 3
Views: 734
Reputation: 180201
Is there a non-platform-specific way of doing an atomic "rename File1 to File2 if File2 does not exist, otherwise give an error"?
The C standard library provides only rename()
for changing file names, and the standard says this about that function: "If a file named by the string pointed to by new
exists prior to the call to the rename
function, the behavior is implementation-defined." Therefore, if "non-platform-specific" is interpreted as "specified by the C standard" then no, there is no such mechanism.
If we expand the scope of "non-platform-specific" to allow facilities specified by POSIX, however, then you can rely on link()
, which
shall atomically create a new link for the existing file and the link count of the file shall be incremented by one. [and] shall fail if [... the second argument] resolves to an existing directory entry or refers to a symbolic link.
Thus, you can create a new (hard) link to the file first, failing if the specified pathname designates an existing file or symbolic link, and then remove the original link upon success.
The most prominent non-POSIX platform in which you might be interested would be Windows. I'm uncertain whether there is any way at all to do what you ask on Windows, but if there is, you could consider writing a wrapper function that uses conditional compilation to select either the POSIX or Windows implementation.
Upvotes: 2