You need to have another file to which to switch the link. However
rename
, renameat
do not need the inode be linked in the same directory; they just require the inode to exist on the same filesystem, or more specifically on the same mount point; otherwise Linux rename
fails with EXDEV
:
EXDEV
oldpath
and newpath
are not on the same mounted filesystem. (Linux permits a filesystem to be mounted at multiple points, but rename() does not work across different
mount points, even if the same filesystem is mounted on both.)
Since Linux 3.11 there is a way to make a new file without linking it to the filesystem: open(2) has a new flag O_TMPFILE
:
O_TMPFILE
(since Linux 3.11)
Create an unnamed temporary file. The pathname argument
specifies a directory; an unnamed inode will be created in
that directory's filesystem. Anything written to the
resulting file will be lost when the last file descriptor is
closed, unless the file is given a name.
O_TMPFILE
must be specified with one of O_RDWR
or O_WRONLY
and, optionally, O_EXCL
. If O_EXCL
is not specified, then
linkat
(2) can be used to link the temporary file into the
filesystem, making it permanent, using code like the
following:
char path[PATH_MAX];
fd = open("/path/to/dir", O_TMPFILE | O_RDWR,
S_IRUSR | S_IWUSR);
/* File I/O on 'fd'... */
snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd);
linkat(AT_FDCWD, path, AT_FDCWD, "/path/for/file",
AT_SYMLINK_FOLLOW);
In this case, the open()
mode argument determines the file
permission mode, as with O_CREAT
.
The manual tells that one of the 2 common use cases for O_TMPFILE
is
Creating a file that is initially invisible, which is then
populated with data and adjusted to have appropriate
filesystem attributes (chown(2), chmod(2), fsetxattr(2),
etc.) before being atomically linked into the filesystem
in a fully formed state (using linkat(2) as described
above).
There are many downsides for this, apart from it being quite new: the file system must also support O_TMPFILE
; ext[234] do support it, and so does XFS in 3.15; btrfs in 3.16; furthermore it might still not be a match for your case, as the linkat
requires the AT_SYMLINK_FOLLOW
which is not available for renameat
; if the target name already exists, `linkat does not replace the the target.