(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;
(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;
}
void *userdata) {
struct stat st;
+ int r;
assert(from);
assert(to);
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(
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(
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(
(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;
}
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:
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;
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:
#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);