Skip to content

Commit

Permalink
copy: check if the source file still exists
Browse files Browse the repository at this point in the history
If the source file is removed during copying it, then the result file may
be broken. Let's check if the file still exists during and after copying.

This is important when archiving a journal file on btrfs. Archiving
journal files is done asynchronously. So, a journal file may be removed
by the main thread of journald by journal_directory_vacuum(), while
another thread is copying the file. If that happens, a broken journal
file is created.

Fixes systemd#24150 and systemd#31222.
  • Loading branch information
yuwata committed Feb 15, 2024
1 parent cd82f8f commit 7f1ce31
Showing 1 changed file with 22 additions and 2 deletions.
24 changes: 22 additions & 2 deletions src/shared/copy.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ int copy_bytes_full(
for (;;) {
ssize_t n;

r = fd_verify_regular_full(fdf, /* check_removed = */ true);
if (r < 0)
return r;

if (max_bytes <= 0)
break;

Expand Down Expand Up @@ -484,6 +488,10 @@ int copy_bytes_full(
copied_something = true;
}

r = fd_verify_regular_full(fdf, /* check_removed = */ true);
if (r < 0)
return r;

if (copy_flags & COPY_TRUNCATE) {
off_t off = lseek(fdt, 0, SEEK_CUR);
if (off < 0)
Expand Down Expand Up @@ -798,6 +806,10 @@ static int fd_copy_regular(
(void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim });
(void) copy_xattr(fdf, NULL, fdt, NULL, copy_flags);

r = fd_verify_regular_full(fdf, /* check_removed = */ true);
if (r < 0)
return r;

if (copy_flags & COPY_FSYNC) {
if (fsync(fdt) < 0) {
r = -errno;
Expand Down Expand Up @@ -1314,7 +1326,7 @@ int copy_file_fd_at_full(
if (fdf < 0)
return -errno;

r = fd_verify_regular(fdf);
r = fd_verify_regular_full(fdf, /* check_removed = */ true);
if (r < 0)
return r;

Expand All @@ -1333,6 +1345,10 @@ int copy_file_fd_at_full(
(void) copy_xattr(fdf, NULL, fdt, NULL, copy_flags);
}

r = fd_verify_regular_full(fdf, /* check_removed = */ true);
if (r < 0)
return r;

if (copy_flags & COPY_FSYNC_FULL) {
r = fsync_full(fdt);
if (r < 0)
Expand Down Expand Up @@ -1374,7 +1390,7 @@ int copy_file_at_full(
if (fstat(fdf, &st) < 0)
return -errno;

r = stat_verify_regular(&st);
r = stat_verify_regular_full(&st, /* check_removed = */ true);
if (r < 0)
return r;

Expand Down Expand Up @@ -1404,6 +1420,10 @@ int copy_file_at_full(
(void) copy_times(fdf, fdt, copy_flags);
(void) copy_xattr(fdf, NULL, fdt, NULL, copy_flags);

r = fd_verify_regular_full(fdf, /* check_removed = */ true);
if (r < 0)
return r;

if (chattr_mask != 0)
(void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);

Expand Down

0 comments on commit 7f1ce31

Please sign in to comment.