Reputation: 45
I have a hardlink the must always exist on the filesystem. What inode the hardlink points is not constant. I want to update the hardlink without adding a temporary entry to the directory.
(Creating a file without a directory entry can be done using open(2)
with the temp flag.)
The issue I'm facing is with replacing/updating the hardlink. From the documentation on the relevant system calls, It seems that I have only two options, and neither avoids a temporary file:
Using renameat
, it is possible to insure that the hardlink always exists. However, it must consume a hardlink and hence necessitating a temporary files (not to mention its inability to dereference symbolic links).
using linkat
, it is possible to produce a hardlink without sacrificing another file. but it cannot overwrite existing files; requiring the deletion of the original hard link.
Is it at all possible to create a link to an inode that replaces an older link with the same name?
Upvotes: 3
Views: 1996
Reputation: 133929
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
andnewpath
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 ofO_RDWR
orO_WRONLY
and, optionally,O_EXCL
. IfO_EXCL
is not specified, thenlinkat
(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 withO_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.
Upvotes: 3