.\"
.\" Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
.\"
-.Dd November 2, 2017
+.Dd July 22, 2019
.Dt COPYFILE 3
.Os
.Sh NAME
.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
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);
#define COPYFILE_DATA_SPARSE (1<<27)
+#define COPYFILE_PRESERVE_DST_TRACKED (1<<28)
+
#define COPYFILE_VERBOSE (1<<30)
#define COPYFILE_RECURSE_ERROR 0
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) {
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;
+}
#include <stdlib.h>
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 */