#include "stat-util.h"
#include "stdio-util.h"
#include "string-util.h"
+#include "sync-util.h"
#include "tmpfile-util.h"
#include "umask-util.h"
* an fd created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE
* is not supported on the directory, and renameat2() is used instead. */
+ if (FLAGS_SET(flags, LINK_TMPFILE_SYNC) && fsync(fd) < 0)
+ return -errno;
+
if (path) {
if (FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
- return RET_NERRNO(renameat(dir_fd, path, dir_fd, target));
+ r = RET_NERRNO(renameat(dir_fd, path, dir_fd, target));
+ else
+ r = rename_noreplace(dir_fd, path, dir_fd, target);
+ if (r < 0)
+ return r;
+ } else {
- return rename_noreplace(dir_fd, path, dir_fd, target);
- }
+ r = link_fd(fd, dir_fd, target);
+ if (r != -EEXIST || !FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
+ return r;
- r = link_fd(fd, dir_fd, target);
- if (r != -EEXIST || !FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
- return r;
+ /* So the target already exists and we were asked to replace it. That sucks a bit, since the kernel's
+ * linkat() logic does not allow that. We work-around this by linking the file to a random name
+ * first, and then renaming that to the final name. This reintroduces the race O_TMPFILE kinda is
+ * trying to fix, but at least the vulnerability window (i.e. where the file is linked into the file
+ * system under a temporary name) is very short. */
- /* So the target already exists and we were asked to replace it. That sucks a bit, since the kernel's
- * linkat() logic does not allow that. We work-around this by linking the file to a random name
- * first, and then renaming that to the final name. This reintroduces the race O_TMPFILE kinda is
- * trying to fix, but at least the vulnerability window (i.e. where the file is linked into the file
- * system under a temporary name) is very short. */
+ r = tempfn_random(target, NULL, &tmp);
+ if (r < 0)
+ return r;
- r = tempfn_random(target, NULL, &tmp);
- if (r < 0)
- return r;
+ if (link_fd(fd, dir_fd, tmp) < 0)
+ return -EEXIST; /* propagate original error */
- if (link_fd(fd, dir_fd, tmp) < 0)
- return -EEXIST; /* propagate original error */
+ r = RET_NERRNO(renameat(dir_fd, tmp, dir_fd, target));
+ if (r < 0) {
+ (void) unlinkat(dir_fd, tmp, 0);
+ return r;
+ }
+ }
- r = RET_NERRNO(renameat(dir_fd, tmp, dir_fd, target));
- if (r < 0) {
- (void) unlinkat(dir_fd, tmp, 0);
- return r;
+ if (FLAGS_SET(flags, LINK_TMPFILE_SYNC)) {
+ r = fsync_full(fd);
+ if (r < 0)
+ return r;
}
return 0;
if (fd < 0) /* Not all FILE* objects encapsulate fds */
return -EBADF;
- r = fflush_sync_and_check(f);
+ r = fflush_and_check(f);
if (r < 0)
return r;