From 62b275d9547c3d23186feb0825fa54e9bb3be954 Mon Sep 17 00:00:00 2001 From: Apple Date: Tue, 23 Jul 2019 02:20:45 +0000 Subject: [PATCH] copyfile-166.40.1.tar.gz --- copyfile.3 | 8 +++++++- copyfile.c | 10 ++++++++++ copyfile.h | 2 ++ copyfile_test/main.c | 1 + copyfile_test/stat_test.c | 40 +++++++++++++++++++++++++++++++++++++++ copyfile_test/stat_test.h | 1 + 6 files changed, 61 insertions(+), 1 deletion(-) diff --git a/copyfile.3 b/copyfile.3 index be1aa31..55d4454 100644 --- a/copyfile.3 +++ b/copyfile.3 @@ -1,7 +1,7 @@ .\" .\" Copyright (c) 2002 Apple Computer, Inc. All rights reserved. .\" -.Dd November 2, 2017 +.Dd July 22, 2019 .Dt COPYFILE 3 .Os .Sh NAME @@ -217,6 +217,12 @@ This is a convenience macro, equivalent to .Dv (COPYFILE_NOFOLLOW_DST | COPYFILE_NOFOLLOW_SRC) . .It Dv COPYFILE_RUN_IN_PLACE If the src file has quarantine information, add the QTN_FLAG_DO_NOT_TRANSLOCATE flag to the quarantine information of the dst file. This allows a bundle to run in place instead of being translocated. +.It Dv COPYFILE_PRESERVE_DST_TRACKED +Preserve the UF_TRACKED flag at +.Va to +when copying metadata, regardless of whether +.Va from +has it set. This flag is used in conjunction with COPYFILE_STAT, or COPYFILE_CLONE (for its fallback case). .El .Pp Copying files into a directory is supported. If diff --git a/copyfile.c b/copyfile.c index 286d0ff..443dbc5 100644 --- a/copyfile.c +++ b/copyfile.c @@ -2744,6 +2744,16 @@ static int copyfile_stat(copyfile_state_t s) return -1; added_flags |= (dst_sb.st_flags & COPYFILE_PRESERVE_FLAGS); + /* + * The caller requested that copyfile attempts to preserve UF_TRACKED + * on the destination. This can be used to avoid dangling docIDs when + * the copy races against a process that sets the flag on newly created + * documents for instance. + */ + if (s->flags & COPYFILE_PRESERVE_DST_TRACKED) { + added_flags |= (dst_sb.st_flags & UF_TRACKED); + } + /* Copy file flags, masking out any we don't want to preserve */ dst_flags = (s->sb.st_flags & ~COPYFILE_OMIT_FLAGS) | added_flags; (void)fchflags(s->dst_fd, dst_flags); diff --git a/copyfile.h b/copyfile.h index 1e98a99..dfe4d08 100644 --- a/copyfile.h +++ b/copyfile.h @@ -108,6 +108,8 @@ typedef int (*copyfile_callback_t)(int, int, copyfile_state_t, const char *, con #define COPYFILE_DATA_SPARSE (1<<27) +#define COPYFILE_PRESERVE_DST_TRACKED (1<<28) + #define COPYFILE_VERBOSE (1<<30) #define COPYFILE_RECURSE_ERROR 0 diff --git a/copyfile_test/main.c b/copyfile_test/main.c index 338b17c..a5384e9 100644 --- a/copyfile_test/main.c +++ b/copyfile_test/main.c @@ -55,6 +55,7 @@ int main(__unused int argc, __unused const char * argv[]) { failed |= do_sparse_recursive_test(TEST_DIR, stb.f_bsize); failed |= do_fcopyfile_offset_test(TEST_DIR, stb.f_bsize); failed |= do_preserve_dst_flags_test(TEST_DIR, stb.f_bsize); + failed |= do_preserve_dst_tracked_test(TEST_DIR, stb.f_bsize); // Cleanup the disk image we ran our tests on. if (USING_DISK_IMAGE) { diff --git a/copyfile_test/stat_test.c b/copyfile_test/stat_test.c index 0890544..0ab2944 100644 --- a/copyfile_test/stat_test.c +++ b/copyfile_test/stat_test.c @@ -147,3 +147,43 @@ bool do_preserve_dst_flags_test(const char *test_directory, __unused size_t bloc return success ? EXIT_SUCCESS : EXIT_FAILURE; } + +bool do_preserve_dst_tracked_test(const char *test_directory, __unused size_t block_size) { + char file_src[BSIZE_B] = {0}, file_dst[BSIZE_B] = {0}; + off_t src_fsize = 0x1000; + int test_file_id; + struct stat dst_stb; + bool success = true; + + printf("START [preserve_dst_tracked]\n"); + + // Create source file + assert_with_errno(snprintf(file_src, BSIZE_B, "%s/" TEST_FILE_NAME, test_directory) > 0); + assert_no_err(close(open(file_src, O_CREAT|O_EXCL, 0644))); + assert_no_err(truncate(file_src, src_fsize)); + + // Create destination file + test_file_id = rand() % DEFAULT_NAME_MOD; + assert_with_errno(snprintf(file_dst, BSIZE_B, "%s/%s.%d", test_directory, TEST_FILE_NAME, test_file_id) > 0); + assert_no_err(close(open(file_dst, O_CREAT|O_EXCL, 0644))); + + // Track destination file + assert_no_err(chflags(file_dst, UF_TRACKED)); + + // Try to copy src onto destination + assert_no_err(copyfile(file_src, file_dst, NULL, COPYFILE_DATA|COPYFILE_STAT|COPYFILE_PRESERVE_DST_TRACKED)); + + assert_no_err(stat(file_dst, &dst_stb)); + success &= (dst_stb.st_size == src_fsize); + success &= (dst_stb.st_flags & UF_TRACKED); + if (success) { + printf("PASS [preserve_dst_tracked]\n"); + } else { + printf("FAIL [preserve_dst_tracked]\n"); + } + + (void)unlink(file_src); + (void)unlink(file_dst); + + return success ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/copyfile_test/stat_test.h b/copyfile_test/stat_test.h index ab5c3c5..719c95c 100644 --- a/copyfile_test/stat_test.h +++ b/copyfile_test/stat_test.h @@ -10,5 +10,6 @@ #include bool do_preserve_dst_flags_test(const char *test_directory, size_t block_size); +bool do_preserve_dst_tracked_test(const char *test_directory, size_t block_size); #endif /* stat_test_h */ -- 2.45.2