r = reflink_range(fdf, foffset, fdt, toffset, max_bytes == UINT64_MAX ? 0 : max_bytes); /* partial reflink */
if (r >= 0) {
off_t t;
+ int ret;
/* This worked, yay! Now — to be fully correct — let's adjust the file pointers */
if (max_bytes == UINT64_MAX) {
if (t < 0)
return -errno;
- return 0; /* we copied the whole thing, hence hit EOF, return 0 */
+ if (FLAGS_SET(copy_flags, COPY_VERIFY_LINKED)) {
+ r = fd_verify_linked(fdf);
+ if (r < 0)
+ return r;
+ }
+
+ /* We copied the whole thing, hence hit EOF, return 0. */
+ ret = 0;
} else {
t = lseek(fdf, foffset + max_bytes, SEEK_SET);
if (t < 0)
if (t < 0)
return -errno;
- return 1; /* we copied only some number of bytes, which worked, but this means we didn't hit EOF, return 1 */
+ /* We copied only some number of bytes, which worked, but
+ * this means we didn't hit EOF, return 1. */
+ ret = 1;
+ }
+
+ if (FLAGS_SET(copy_flags, COPY_VERIFY_LINKED)) {
+ r = fd_verify_linked(fdf);
+ if (r < 0)
+ return r;
}
+
+ return ret;
}
}
}
copied_something = true;
}
+ if (FLAGS_SET(copy_flags, COPY_VERIFY_LINKED)) {
+ r = fd_verify_linked(fdf);
+ if (r < 0)
+ return r;
+ }
+
if (copy_flags & COPY_TRUNCATE) {
off_t off = lseek(fdt, 0, SEEK_CUR);
if (off < 0)
(void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim });
(void) copy_xattr(fdf, NULL, fdt, NULL, copy_flags);
+ if (FLAGS_SET(copy_flags, COPY_VERIFY_LINKED)) {
+ r = fd_verify_linked(fdf);
+ if (r < 0)
+ return r;
+ }
+
if (copy_flags & COPY_FSYNC) {
if (fsync(fdt) < 0) {
r = -errno;
(void) copy_xattr(fdf, NULL, fdt, NULL, copy_flags);
}
+ if (FLAGS_SET(copy_flags, COPY_VERIFY_LINKED)) {
+ r = fd_verify_linked(fdf);
+ if (r < 0)
+ return r;
+ }
+
if (copy_flags & COPY_FSYNC_FULL) {
r = fsync_full(fdt);
if (r < 0)
(void) copy_times(fdf, fdt, copy_flags);
(void) copy_xattr(fdf, NULL, fdt, NULL, copy_flags);
+ if (FLAGS_SET(copy_flags, COPY_VERIFY_LINKED)) {
+ r = fd_verify_linked(fdf);
+ if (r < 0)
+ goto fail;
+ }
+
if (chattr_mask != 0)
(void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);
fd = safe_close(fd);
}
+TEST(copy_verify_linked) {
+ _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
+ _cleanup_close_ int tfd = -EBADF, fd_1 = -EBADF, fd_2 = -EBADF;
+
+ tfd = mkdtemp_open(NULL, O_PATH, &t);
+ assert_se(tfd >= 0);
+
+ assert_se(write_string_file_at(tfd, "hoge", "bar bar", WRITE_STRING_FILE_CREATE) >= 0);
+
+ fd_1 = openat(tfd, "hoge", O_CLOEXEC | O_NOCTTY | O_RDONLY);
+ assert_se(fd_1 >= 0);
+ fd_2 = openat(tfd, "hoge", O_CLOEXEC | O_NOCTTY | O_RDONLY);
+ assert_se(fd_2 >= 0);
+ assert_se(unlinkat(tfd, "hoge", 0) >= 0);
+
+ assert_se(copy_file_at(fd_1, NULL, tfd, "to_1", 0, 0644, 0) >= 0);
+ assert_se(read_file_at_and_streq(tfd, "to_1", "bar bar\n"));
+
+ assert_se(copy_file_at(fd_2, NULL, tfd, "to_2", O_EXCL, 0644, COPY_VERIFY_LINKED) == -EIDRM);
+ assert_se(faccessat(tfd, "to_2", F_OK, AT_SYMLINK_NOFOLLOW) < 0 && errno == ENOENT);
+}
+
DEFINE_TEST_MAIN(LOG_DEBUG);