copy: optionally fsync() files after copying them
As a safety precaution it makes sense to fsync() files after copying them, and maybe even the directories they are contained in. Let's add a flag for these two cases.
This commit is contained in:
+107
-7
@@ -641,6 +641,13 @@ static int fd_copy_regular(
|
||||
(void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim });
|
||||
(void) copy_xattr(fdf, fdt);
|
||||
|
||||
if (copy_flags & COPY_FSYNC) {
|
||||
if (fsync(fdt) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
q = close_nointr(TAKE_FD(fdt)); /* even if this fails, the fd is now invalidated */
|
||||
if (q < 0) {
|
||||
r = q;
|
||||
@@ -933,6 +940,11 @@ static int fd_copy_directory(
|
||||
(void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim });
|
||||
}
|
||||
|
||||
if (copy_flags & COPY_FSYNC_FULL) {
|
||||
if (fsync(fdt) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -949,6 +961,7 @@ int copy_tree_at_full(
|
||||
void *userdata) {
|
||||
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
assert(from);
|
||||
assert(to);
|
||||
@@ -957,17 +970,27 @@ int copy_tree_at_full(
|
||||
return -errno;
|
||||
|
||||
if (S_ISREG(st.st_mode))
|
||||
return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL, progress_bytes, userdata);
|
||||
r = fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL, progress_bytes, userdata);
|
||||
else if (S_ISDIR(st.st_mode))
|
||||
return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
|
||||
r = fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
|
||||
else if (S_ISLNK(st.st_mode))
|
||||
return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
|
||||
r = fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
|
||||
else if (S_ISFIFO(st.st_mode))
|
||||
return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
|
||||
r = fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
|
||||
else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
|
||||
return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
|
||||
r = fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (copy_flags & COPY_FSYNC_FULL) {
|
||||
r = fsync_parent_at(fdt, to);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copy_directory_fd_full(
|
||||
@@ -991,7 +1014,28 @@ int copy_directory_fd_full(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
|
||||
r = fd_copy_directory(
|
||||
dirfd, NULL,
|
||||
&st,
|
||||
AT_FDCWD, to,
|
||||
st.st_dev,
|
||||
COPY_DEPTH_MAX,
|
||||
UID_INVALID, GID_INVALID,
|
||||
copy_flags,
|
||||
NULL, NULL,
|
||||
progress_path,
|
||||
progress_bytes,
|
||||
userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (copy_flags & COPY_FSYNC_FULL) {
|
||||
r = fsync_parent_at(AT_FDCWD, to);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copy_directory_full(
|
||||
@@ -1015,7 +1059,28 @@ int copy_directory_full(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
|
||||
r = fd_copy_directory(
|
||||
AT_FDCWD, from,
|
||||
&st,
|
||||
AT_FDCWD, to,
|
||||
st.st_dev,
|
||||
COPY_DEPTH_MAX,
|
||||
UID_INVALID, GID_INVALID,
|
||||
copy_flags,
|
||||
NULL, NULL,
|
||||
progress_path,
|
||||
progress_bytes,
|
||||
userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (copy_flags & COPY_FSYNC_FULL) {
|
||||
r = fsync_parent_at(AT_FDCWD, to);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copy_file_fd_full(
|
||||
@@ -1052,6 +1117,15 @@ int copy_file_fd_full(
|
||||
(void) copy_xattr(fdf, fdt);
|
||||
}
|
||||
|
||||
if (copy_flags & COPY_FSYNC_FULL) {
|
||||
r = fsync_full(fdt);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (copy_flags & COPY_FSYNC) {
|
||||
if (fsync(fdt) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1117,10 +1191,23 @@ int copy_file_full(
|
||||
if (chattr_mask != 0)
|
||||
(void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);
|
||||
|
||||
if (copy_flags & (COPY_FSYNC|COPY_FSYNC_FULL)) {
|
||||
if (fsync(fdt) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
r = close_nointr(TAKE_FD(fdt)); /* even if this fails, the fd is now invalidated */
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (copy_flags & COPY_FSYNC_FULL) {
|
||||
r = fsync_parent_at(AT_FDCWD, to);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@@ -1196,6 +1283,12 @@ int copy_file_atomic_full(
|
||||
if (fchmod(fdt, mode) < 0)
|
||||
return -errno;
|
||||
|
||||
if ((copy_flags & (COPY_FSYNC|COPY_FSYNC_FULL))) {
|
||||
/* Sync the file */
|
||||
if (fsync(fdt) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (copy_flags & COPY_REPLACE) {
|
||||
if (renameat(AT_FDCWD, t, AT_FDCWD, to) < 0)
|
||||
return -errno;
|
||||
@@ -1214,6 +1307,13 @@ int copy_file_atomic_full(
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (copy_flags & COPY_FSYNC_FULL) {
|
||||
/* Sync the parent directory */
|
||||
r = fsync_parent_at(AT_FDCWD, to);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
||||
+11
-9
@@ -10,15 +10,17 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef enum CopyFlags {
|
||||
COPY_REFLINK = 1 << 0, /* Try to reflink */
|
||||
COPY_MERGE = 1 << 1, /* Merge existing trees with our new one to copy */
|
||||
COPY_REPLACE = 1 << 2, /* Replace an existing file if there's one */
|
||||
COPY_SAME_MOUNT = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */
|
||||
COPY_MERGE_EMPTY = 1 << 4, /* Merge an existing, empty directory with our new tree to copy */
|
||||
COPY_CRTIME = 1 << 5, /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */
|
||||
COPY_SIGINT = 1 << 6, /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */
|
||||
COPY_MAC_CREATE = 1 << 7, /* Create files with the correct MAC label (currently SELinux only) */
|
||||
COPY_HARDLINKS = 1 << 8, /* Try to reproduce hard links */
|
||||
COPY_REFLINK = 1 << 0, /* Try to reflink */
|
||||
COPY_MERGE = 1 << 1, /* Merge existing trees with our new one to copy */
|
||||
COPY_REPLACE = 1 << 2, /* Replace an existing file if there's one */
|
||||
COPY_SAME_MOUNT = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */
|
||||
COPY_MERGE_EMPTY = 1 << 4, /* Merge an existing, empty directory with our new tree to copy */
|
||||
COPY_CRTIME = 1 << 5, /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */
|
||||
COPY_SIGINT = 1 << 6, /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */
|
||||
COPY_MAC_CREATE = 1 << 7, /* Create files with the correct MAC label (currently SELinux only) */
|
||||
COPY_HARDLINKS = 1 << 8, /* Try to reproduce hard links */
|
||||
COPY_FSYNC = 1 << 9, /* fsync() after we are done */
|
||||
COPY_FSYNC_FULL = 1 << 10, /* fsync_full() after we are done */
|
||||
} CopyFlags;
|
||||
|
||||
typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);
|
||||
|
||||
Reference in New Issue
Block a user