From 11dccc40b5100218157ea0b6c4eaa45850d5d83d Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Thu, 22 Jul 2021 09:33:19 +0200 Subject: [PATCH] fs: link fallback for atomic create Some file systems don't support renameat2's RENAME_NOREPLACE flag (eg. ZFS), at the some time, some other file systems don't support hardlinks via link (eg. vfat, cifs), so we now try both: first the rename (since it's more efficient), then link+unlink for the rest. If both fail, the file system is simply not supported for our purposes anyway... Signed-off-by: Wolfgang Bumiller --- proxmox/src/tools/fs.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/proxmox/src/tools/fs.rs b/proxmox/src/tools/fs.rs index 8087cc8f..1a2a51fc 100644 --- a/proxmox/src/tools/fs.rs +++ b/proxmox/src/tools/fs.rs @@ -236,14 +236,22 @@ pub fn atomic_open_or_create_file>( // the initialization, the first one wins! let rename_result = temp_file_name.with_nix_path(|c_file_name| { path.with_nix_path(|new_path| unsafe { - let rc = libc::renameat2( + // This also works on file systems which don't support hardlinks (eg. vfat) + match Errno::result(libc::renameat2( libc::AT_FDCWD, c_file_name.as_ptr(), libc::AT_FDCWD, new_path.as_ptr(), libc::RENAME_NOREPLACE, - ); - nix::errno::Errno::result(rc) + )) { + Err(nix::Error::Sys(Errno::EINVAL)) => (), // dumb file system, try `link`+`unlink` + other => return other, + }; + // but some file systems don't support `RENAME_NOREPLACE` + // so we just use `link` + `unlink` instead + let result = Errno::result(libc::link(c_file_name.as_ptr(), new_path.as_ptr())); + let _ = libc::unlink(c_file_name.as_ptr()); + result }) });