A pathname rename changes directory entries while open file descriptors continue to refer to the same underlying objects. Linux renameat2() adds policy to that namespace update: a caller can reject replacement, exchange two existing names, or request a whiteout for union-filesystem operation. These policies are executed as part of the rename operation rather than as checks performed separately in userspace.
The interface is Linux-specific. A zero flags argument gives renameat() behavior, while nonzero flags add Linux semantics that also depend on support from the mounted filesystem.
Rename changes names rather than open object references
A successful rename moves a name from one directory entry to another location, subject to filesystem rules. Existing hard links to the same inode remain links to that object. File descriptors already opened through the old pathname also remain valid; the descriptor refers to an open file description and underlying file, not to a promise that the original pathname stays present.
That distinction makes rename useful as a namespace commit point. A process can prepare an object under one name and then publish it under another. Atomic namespace replacement does not imply that prior readers switch objects: a process that already opened the old target can continue using its existing descriptor.
Ordinary rename replacement also has a precise visibility property. If the destination exists and replacement is permitted, the destination is replaced atomically, so concurrent pathname lookup does not observe an interval in which the destination name is absent. This property concerns the directory-entry operation. It does not by itself guarantee persistence after power loss; storage durability requires the relevant filesystem and synchronization operations to satisfy a separate contract.
RENAME_NOREPLACE removes the check-then-rename race
A userspace sequence that first tests whether a destination exists and then performs an ordinary rename has a race. Another process can create the destination after the test and before the rename. The final rename may then replace an object that the initial check never observed.
RENAME_NOREPLACE moves that condition into the rename operation:
int rc = renameat2(old_dirfd, "staged",
new_dirfd, "current",
RENAME_NOREPLACE);If current already exists, the operation fails with EEXIST instead of replacing it. The existence condition and namespace mutation are therefore one kernel-mediated operation from the caller’s perspective.
This flag does not reserve the destination after a failure. A later retry evaluates the namespace again. It also does not create a general compare-and-swap over file contents or inode metadata; its condition is specifically that the destination pathname must not already exist.
Filesystem support is part of the contract. Linux added RENAME_NOREPLACE support to filesystems over time, so software targeting varied kernels and filesystems must treat support as an environment property rather than a universal property of every Linux mount.
RENAME_EXCHANGE swaps two existing names
RENAME_EXCHANGE atomically exchanges the objects named by the source and destination pathnames. Both names must already exist. Unlike a sequence built from three ordinary renames and a temporary name, the exchange does not expose the intermediate namespace states created by that sequence.
The two entries may name different object types, subject to the documented operation semantics. The useful guarantee is about the pair of directory entries: after success, each name refers to the object previously reached through the other name.
The exchange does not merge object state and does not alter already-open descriptors. A descriptor opened through name A before the exchange still refers to its original object after name A has been rebound to the object formerly at name B. Code that combines pathname lookups with long-lived descriptors must keep those two forms of identity separate.
RENAME_EXCHANGE cannot be combined with RENAME_NOREPLACE. The policies express incompatible destination conditions: exchange requires both names to exist, while no-replace requires the destination not to exist.
Directory file descriptors stabilize the lookup anchor
Like renameat(), renameat2() accepts separate directory file descriptors for relative source and destination paths. Relative oldpath is resolved from olddirfd, and relative newpath is resolved from newdirfd. An absolute path ignores the corresponding directory descriptor.
This removes dependence on the process current working directory for those relative lookups. It does not provide the stronger resolution controls offered by openat2(): renameat2() has no RESOLVE_BENEATH, RESOLVE_NO_SYMLINKS, or equivalent resolution-policy argument. Directory-relative naming and constrained path traversal are separate mechanisms.
Applications that need a trusted directory boundary must therefore account for path components and symbolic-link behavior independently. A stable directory descriptor anchors relative resolution, but the rename API does not transform arbitrary relative path strings into capability-confined traversal.
Mount boundaries remain a hard constraint
Rename operates within a mounted filesystem. If source and destination are on different mounted filesystems, Linux reports EXDEV. This remains true even when the same underlying filesystem is mounted at multiple mount points.
As a result, rename cannot serve as an atomic publication primitive across arbitrary storage locations. A fallback that copies data to the destination filesystem and then removes the source is a different protocol with different failure states. During such a fallback, both copies may exist, only one may exist, or metadata may differ depending on the sequence and failures.
The atomic property of rename must therefore be attached to the actual successful rename operation, not generalized to commands or libraries that emulate a move across mount boundaries.
RENAME_WHITEOUT couples rename with overlay namespace state
RENAME_WHITEOUT exists for union and overlay filesystem implementations. A whiteout marks a source-layer name as hidden while the renamed object is made visible at its destination in the writable layer. Linux performs the whiteout creation and rename atomically when the operation succeeds.
Outside a union or overlay context, the Linux whiteout representation appears as a character device with device number {0,0}. Requesting this flag requires CAP_MKNOD, and filesystem support is required. These conditions make the flag an infrastructure mechanism rather than a portable file-management option.
RENAME_WHITEOUT cannot be combined with RENAME_EXCHANGE. Its semantics describe source replacement by a whiteout during a directional rename, which differs from swapping two existing entries.
Atomic namespace change is narrower than durable publication
renameat2() can make a namespace condition and its mutation indivisible at the system-call interface: reject an existing target, exchange two names, or couple a rename with whiteout creation. That closes races that appear when those policies are assembled from separate pathname operations.
The boundary remains deliberately narrow. Open descriptors preserve object references across renames, cross-mount moves are excluded, flag support can depend on the filesystem, and successful namespace mutation is not itself a durability guarantee. Designs that use rename as a commit point need separate contracts for data synchronization, directory persistence, path-resolution trust, and recovery after remote-filesystem failures.