From 7f1ce3134722b830e3ed9517baeb902cdd32ac80 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 15 Feb 2024 09:34:16 +0900 Subject: [PATCH] copy: check if the source file still exists 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 #24150 and #31222. --- src/shared/copy.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/shared/copy.c b/src/shared/copy.c index a23c7e990f6c8..128f06031c023 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -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; @@ -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) @@ -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; @@ -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; @@ -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) @@ -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; @@ -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);