Florian Weimer wrote:
Without kernel support, a non-zero argument returns EINVAL, not ENOSYS. This mirrors what the kernel does for invalid renameat2 flags.
The Gnulib renameat2 function <https://www.gnu.org/software/gnulib/MODULES.html#module=renameat2> has different semantics with non-zero flags. On GNU/Linux if flags==RENAME_NOREPLACE and the Linux syscall fails due to EINVAL/ENOSYS/ENOTSUP, Gnulib renameat2 falls back on fstatatting the destination, failing if fstatat succeeds, and using ordinary renameat otherwise. Of course this implementation has a race condition, but Gnulib-using applications like GNU 'mv' prefer this implementation since if the kernel doesn't support RENAME_NOREPLACE they'd just fall back on fstatat themselves anyway, if renameat2 didn't do that for them.
It strikes me that this will be a common use case for RENAME_NOREPLACE in other glibc applications too, perhaps the most common one. In that case, perhaps glibc should support the Gnulib semantics, by falling back on a non-atomic implementation of RENAME_NOREPLACE if the kernel doesn't support the atomic one. If that's too drastic, how about having glibc support a new flag RENAME_NOREPLACE_NONATOMIC that works on all platforms? We could of course add such a flag to Gnulib, but I expect it'd be better if the functionality were available to all Glibc programs, not just to Gnulib-using programs.
PS. In Gnulib-using apps we've found no need for RENAME_EXCHANGE or RENAME_WHITEOUT and so Gnulib does not implement them on older GNU/Linux kernels. Gnulib renameat2 does support RENAME_EXCHANGE on macOS since it's easy there.
[CC:ing this to bug-gnulib; for those joining in, a recent email in this thread is here:
https://sourceware.org/ml/libc-alpha/2018-07/msg00003.html ]