mirror of
https://github.com/systemd/systemd.git
synced 2026-08-13 17:08:14 +00:00
copy: add new flags that cause a seek to beginning of files before copying
This is quite useful in various cases where we so far did this manually.
This commit is contained in:
committed by
Luca Boccassi
parent
6fb5ec3dd1
commit
5adfd44c9e
@@ -554,10 +554,7 @@ static int copy_file_with_version_check(
|
||||
* might be left at the end of the file. (Resetting before rather than after a copy attempt is safer
|
||||
* because a previous attempt might have failed half-way, leaving the file offset at some undefined
|
||||
* place.) */
|
||||
if (lseek(source_fd, 0, SEEK_SET) < 0)
|
||||
return log_error_errno(errno, "Failed to seek in \"%s\": %m", source_path);
|
||||
|
||||
r = copy_bytes(source_fd, write_fd, UINT64_MAX, COPY_REFLINK);
|
||||
r = copy_bytes(source_fd, write_fd, UINT64_MAX, COPY_REFLINK|COPY_SEEK0_SOURCE);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to copy data from \"%s\" to \"%s\": %m", source_path, dest_path);
|
||||
|
||||
|
||||
@@ -5061,9 +5061,6 @@ static int partition_target_sync(Context *context, Partition *p, PartitionTarget
|
||||
if (lseek(whole_fd, p->offset, SEEK_SET) < 0)
|
||||
return log_error_errno(errno, "Failed to seek to partition offset: %m");
|
||||
|
||||
if (lseek(t->fd, 0, SEEK_SET) < 0)
|
||||
return log_error_errno(errno, "Failed to seek to start of temporary file: %m");
|
||||
|
||||
if (fstat(t->fd, &st) < 0)
|
||||
return log_error_errno(errno, "Failed to stat temporary file: %m");
|
||||
|
||||
@@ -5072,7 +5069,7 @@ static int partition_target_sync(Context *context, Partition *p, PartitionTarget
|
||||
"Partition %" PRIu64 "'s contents (%s) don't fit in the partition (%s).",
|
||||
p->partno, FORMAT_BYTES(st.st_size), FORMAT_BYTES(p->new_size));
|
||||
|
||||
r = copy_bytes(t->fd, whole_fd, UINT64_MAX, COPY_REFLINK|COPY_HOLES|COPY_FSYNC);
|
||||
r = copy_bytes(t->fd, whole_fd, UINT64_MAX, COPY_REFLINK|COPY_HOLES|COPY_FSYNC|COPY_SEEK0_SOURCE);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to copy bytes to partition: %m");
|
||||
} else {
|
||||
|
||||
@@ -193,16 +193,26 @@ int copy_bytes_full(
|
||||
if (fdt < 0)
|
||||
return fdt;
|
||||
|
||||
if (FLAGS_SET(copy_flags, COPY_SEEK0_SOURCE) &&
|
||||
lseek(fdf, 0, SEEK_SET) < 0)
|
||||
return -errno;
|
||||
|
||||
if (FLAGS_SET(copy_flags, COPY_SEEK0_TARGET) &&
|
||||
lseek(fdt, 0, SEEK_SET) < 0)
|
||||
return -errno;
|
||||
|
||||
/* Try btrfs reflinks first. This only works on regular, seekable files, hence let's check the file offsets of
|
||||
* source and destination first. */
|
||||
if ((copy_flags & COPY_REFLINK)) {
|
||||
off_t foffset;
|
||||
|
||||
foffset = lseek(fdf, 0, SEEK_CUR);
|
||||
/* In reflink mode we need to know where the current file offset is, but if we just seeked to
|
||||
* 0 anyway, we can suppress that. */
|
||||
foffset = FLAGS_SET(copy_flags, COPY_SEEK0_SOURCE) ? 0 : lseek(fdf, 0, SEEK_CUR);
|
||||
if (foffset >= 0) {
|
||||
off_t toffset;
|
||||
|
||||
toffset = lseek(fdt, 0, SEEK_CUR);
|
||||
toffset = FLAGS_SET(copy_flags, COPY_SEEK0_TARGET) ? 0 : lseek(fdt, 0, SEEK_CUR);
|
||||
if (toffset >= 0) {
|
||||
|
||||
if (foffset == 0 && toffset == 0 && max_bytes == UINT64_MAX)
|
||||
|
||||
@@ -34,6 +34,8 @@ typedef enum CopyFlags {
|
||||
COPY_NOCOW_AFTER = 1 << 20,
|
||||
COPY_PRESERVE_FS_VERITY = 1 << 21, /* Preserve fs-verity when copying. */
|
||||
COPY_MERGE_APPLY_STAT = 1 << 22, /* When we reuse an existing directory inode, apply source ownership/mode/xattrs/timestamps */
|
||||
COPY_SEEK0_SOURCE = 1 << 23, /* Seek back to start of source file before copying */
|
||||
COPY_SEEK0_TARGET = 1 << 24, /* Seek back to start of target file before copying */
|
||||
} CopyFlags;
|
||||
|
||||
typedef enum DenyType {
|
||||
|
||||
@@ -364,9 +364,7 @@ static void test_copy_bytes_regular_file_one(const char *src, bool try_reflink,
|
||||
/* Make sure the file is now higher than max_bytes */
|
||||
assert_se(ftruncate(fd2, max_bytes + 1) == 0);
|
||||
|
||||
assert_se(lseek(fd2, 0, SEEK_SET) == 0);
|
||||
|
||||
r = copy_bytes(fd2, fd3, max_bytes, try_reflink ? COPY_REFLINK : 0);
|
||||
r = copy_bytes(fd2, fd3, max_bytes, COPY_SEEK0_SOURCE | (try_reflink ? COPY_REFLINK : 0));
|
||||
if (max_bytes == UINT64_MAX)
|
||||
assert_se(r == 0);
|
||||
else
|
||||
@@ -460,9 +458,8 @@ TEST_RET(copy_holes) {
|
||||
assert_se(lseek(fd, 0, SEEK_END) == 2 * blksz);
|
||||
/* Only ftruncate() can create holes at the end of a file. */
|
||||
assert_se(ftruncate(fd, 3 * blksz) >= 0);
|
||||
assert_se(lseek(fd, 0, SEEK_SET) >= 0);
|
||||
|
||||
assert_se(copy_bytes(fd, fd_copy, UINT64_MAX, COPY_HOLES) >= 0);
|
||||
assert_se(copy_bytes(fd, fd_copy, UINT64_MAX, COPY_SEEK0_SOURCE|COPY_HOLES) >= 0);
|
||||
|
||||
/* Test that the hole starts at the beginning of the file. */
|
||||
assert_se(lseek(fd_copy, 0, SEEK_HOLE) == 0);
|
||||
@@ -526,26 +523,20 @@ TEST_RET(copy_holes_with_gaps) {
|
||||
assert_se(st.st_size == 3 * blksz);
|
||||
|
||||
/* Copy to the middle of the second hole */
|
||||
assert_se(lseek(fd, 0, SEEK_SET) >= 0);
|
||||
assert_se(lseek(fd_copy, 0, SEEK_SET) >= 0);
|
||||
assert_se(ftruncate(fd_copy, 0) >= 0);
|
||||
assert_se(copy_bytes(fd, fd_copy, 4 * blksz, COPY_HOLES) >= 0);
|
||||
assert_se(copy_bytes(fd, fd_copy, 4 * blksz, COPY_SEEK0_SOURCE|COPY_SEEK0_TARGET|COPY_HOLES) >= 0);
|
||||
ASSERT_OK_ERRNO(fstat(fd_copy, &st));
|
||||
assert_se(st.st_size == 4 * blksz);
|
||||
|
||||
/* Copy to the end of the second hole */
|
||||
assert_se(lseek(fd, 0, SEEK_SET) >= 0);
|
||||
assert_se(lseek(fd_copy, 0, SEEK_SET) >= 0);
|
||||
assert_se(ftruncate(fd_copy, 0) >= 0);
|
||||
assert_se(copy_bytes(fd, fd_copy, 5 * blksz, COPY_HOLES) >= 0);
|
||||
assert_se(copy_bytes(fd, fd_copy, 5 * blksz, COPY_SEEK0_SOURCE|COPY_SEEK0_TARGET|COPY_HOLES) >= 0);
|
||||
ASSERT_OK_ERRNO(fstat(fd_copy, &st));
|
||||
assert_se(st.st_size == 5 * blksz);
|
||||
|
||||
/* Copy everything */
|
||||
assert_se(lseek(fd, 0, SEEK_SET) >= 0);
|
||||
assert_se(lseek(fd_copy, 0, SEEK_SET) >= 0);
|
||||
assert_se(ftruncate(fd_copy, 0) >= 0);
|
||||
assert_se(copy_bytes(fd, fd_copy, UINT64_MAX, COPY_HOLES) >= 0);
|
||||
assert_se(copy_bytes(fd, fd_copy, UINT64_MAX, COPY_SEEK0_SOURCE|COPY_SEEK0_TARGET|COPY_HOLES) >= 0);
|
||||
ASSERT_OK_ERRNO(fstat(fd_copy, &st));
|
||||
assert_se(st.st_size == 6 * blksz);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user