I'm working on a Perl-based file synchronization tool. It downloads files into a temporary directory (which is guaranteed to be on the same filesystem as the real file) and then moves the temporary files into place over the old ones, preserving metadata like permissions, ownership, and ACLs. I'm wondering how to achieve that last step on Linux.
On Mac OS X, at least in C, I would use the exchangedata
function. This takes two filenames as arguments and swaps their contents, leaving all metadata (besides mtime) intact. It guarantees that the operation is atomic—all readers will see either the old file or the new one, never something in between. Unfortunately, I don't think it's available on Linux.
I know that rename
moves atomically, but it doesn't preserve metadata. On the other hand, I could open the file and overwrite the data with the contents of the new one, which would preserve all metadata but would not be an atomic operation. Any suggestions on tackling this problem?
Sadly, fsync() is not atomic itself.
mv is most definitely not atomic when the move that it performs is from one filesystem to another, or when a remote filesystem cannot implement the mv operation locally. In these instances mv could be said to be implemented by the equivalent of a cp followed by rm .
An atomic operation is one that changes a system from one state to another without visibly passing through any intermediate states. Atomicity is desirable when altering the content of a file because: The process performing the alteration may fail or be stopped, leaving the file in an incomplete or inconsistent state.
Atomic file guarantees file integrity by ensuring that a file has been completely written and sync'd to disk before renaming it to the original file.
The only approach I see here is to read the metadata from the file you are replacing, apply that to the temporary file, and then rename the temporary file over the old file. (rename
preserves the source file attributes, obviously.)
Filesystem-specific, but...
The XFS_IOC_SWAPEXT
ioctl swaps the extents of two file descriptors on XFS.
#include <xfs/xfs.h>
#include <xfs/xfs_dfrag.h>
xfs_swapext_t sx = {
...,
.sx_fdtarget = fd1,
.sx_fdtmp = fd2,
...
};
xfs_swapext(fd1, &sx);
See the sources to xfs_fsr for example usage.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With