renameat2(2)
Rename or atomically swap two filesystem entries, with optional no-overwrite and exchange flags.
- Since
- Linux 3.15check your kernel →
- glibc
- 2.28
- System
- Linux
- Man page
- renameat2(2)
Synopsis
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
/* glibc wrapper since 2.28; use syscall(2) on older systems */
int renameat2(int olddirfd, const char *oldpath,
int newdirfd, const char *newpath,
unsigned int flags);Rod's take
renameat2(2) adds two flags rename(2) never had. RENAME_NOREPLACE fails with EEXIST if the destination exists, eliminating the check-then-rename race. RENAME_EXCHANGE atomically swaps two paths: both keep existing inodes, both remain visible to readers throughout, and the old file lands in the new name after the call. ext4, XFS, btrfs, tmpfs, and overlayfs support both flags; FAT and NFSv3 return EINVAL or ENOSYS. glibc wrapper arrived in 2.28; call syscall(2) directly on older systems.
Flags and arguments that matter
| Name | What it does |
|---|---|
| RENAME_NOREPLACE | Fail with EEXIST if newpath already exists instead of replacing it. |
| RENAME_EXCHANGE | Atomically swap oldpath and newpath. Both must exist. No intermediate state where either path is absent. |
| RENAME_WHITEOUT | Leave a whiteout inode at oldpath for union/overlay mount semantics. Rarely needed outside container runtimes. |
Errors you will actually hit
| errno | Meaning |
|---|---|
| EEXIST | RENAME_NOREPLACE was set and newpath already exists. |
| ENOENT | RENAME_EXCHANGE was set and one or both paths do not exist. |
| EINVAL | Unsupported flags combination, or the filesystem does not support the requested flag. |
| ENOSYS | Kernel older than 3.15, or filesystem (FAT, NFSv3) does not implement renameat2. |
Example
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
/* write new config fully, then swap atomically */
int r = syscall(SYS_renameat2,
AT_FDCWD, "etc/app.conf.new",
AT_FDCWD, "etc/app.conf",
2 /* RENAME_EXCHANGE */);
/* etc/app.conf.new now holds the old config */
if (r == 0) unlink("etc/app.conf.new");Trimmed from the full walkthrough in renameat2(2): atomic file swap without a race window.
BSD equivalent
No equivalent in FreeBSD or OpenBSD. Both support atomic rename(2) for same-directory replace, but neither has an EXCHANGE primitive at the VFS layer.
The long version, from the console
Sources
Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.
