return 1;
}
+static int prepare_nocow(int fdf, const char *from, int fdt, unsigned *chattr_mask, unsigned *chattr_flags) {
+ unsigned attrs = 0;
+ int r;
+
+ assert(fdf >= 0 || fdf == AT_FDCWD);
+ assert(fdt >= 0);
+ assert(!!chattr_mask == !!chattr_flags);
+
+ /* If caller explicitly requested NOCOW to be set or unset, let's not interfere. */
+ if (chattr_mask && FLAGS_SET(*chattr_mask, FS_NOCOW_FL))
+ return 0;
+
+ r = read_attr_at(fdf, from, &attrs);
+ if (r < 0 && !ERRNO_IS_NOT_SUPPORTED(r) && r != -ELOOP) /* If the source is a symlink we get ELOOP */
+ return r;
+
+ if (FLAGS_SET(attrs, FS_NOCOW_FL)) {
+ if (chattr_mask && chattr_flags) {
+ *chattr_mask |= FS_NOCOW_FL;
+ *chattr_flags |= FS_NOCOW_FL;
+ } else
+ /* If the NOCOW flag is set on the source, make the copy NOCOW as well. If the source
+ * is not NOCOW, don't do anything in particular with the copy. */
+ (void) chattr_fd(fdt, FS_NOCOW_FL, FS_NOCOW_FL, /*previous=*/ NULL);
+ }
+
+ return 0;
+}
+
static int fd_copy_tree_generic(
int df,
const char *from,
if (fdt < 0)
return -errno;
+ r = prepare_nocow(fdf, /*from=*/ NULL, fdt, /*chattr_mask=*/ NULL, /*chattr_flags=*/ NULL);
+ if (r < 0)
+ return r;
+
r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress, userdata);
if (r < 0)
goto fail;
goto fail;
}
+ r = prepare_nocow(fdf, /*from=*/ NULL, fdt, &chattr_mask, &chattr_flags);
+ if (r < 0)
+ return r;
+
if (chattr_mask != 0)
(void) chattr_fd(fdt, chattr_flags, chattr_mask & CHATTR_EARLY_FL, NULL);
if (fdt < 0)
return fdt;
+ r = prepare_nocow(dir_fdf, from, fdt, &chattr_mask, &chattr_flags);
+ if (r < 0)
+ return r;
+
if (chattr_mask != 0)
(void) chattr_fd(fdt, chattr_flags, chattr_mask & CHATTR_EARLY_FL, NULL);