10 #include <removefile.h>
12 #include <sys/fcntl.h>
15 #include "test_utils.h"
18 bool verify_fd_contents(int orig_fd
, off_t orig_pos
, int copy_fd
, off_t copy_pos
, size_t length
) {
19 // Read *length* contents of the two fds and make sure they compare as equal.
20 // Don't alter the position of either fd.
21 char orig_contents
[length
], copy_contents
[length
];
24 assert(orig_fd
> 0 && copy_fd
> 0);
25 memset(orig_contents
, 0, length
);
26 memset(copy_contents
, 0, length
);
28 // Read the contents into our temporary buffers, and call memcmp().
30 ssize_t pread_res
= pread(orig_fd
, orig_contents
, length
, 0);
31 assert_with_errno(pread_res
== (off_t
) length
);
32 assert_with_errno(pread(copy_fd
, copy_contents
, length
, copy_pos
) >= 0);
33 equal
= (memcmp(orig_contents
, copy_contents
, length
) == 0);
35 printf("original fd (%lld - %lld) did not match copy (%lld - %lld)\n",
36 orig_pos
, orig_pos
+ length
, copy_pos
, copy_pos
+ length
);
38 // Find the first non-matching byte and print it out.
39 for (size_t bad_off
= 0; bad_off
< length
; bad_off
++) {
40 if (orig_contents
[bad_off
] != copy_contents
[bad_off
]) {
41 printf("first mismatch is at offset %zu, original 0x%llx COPY 0x%llx\n",
42 bad_off
, orig_contents
[bad_off
], copy_contents
[bad_off
]);
51 bool verify_copy_contents(const char *orig_name
, const char *copy_name
) {
52 // Verify that the copy and the source have identical contents.
53 // Here, we just call out to 'diff' to do the work for us.
54 int rc
= systemx(DIFF_PATH
, orig_name
, copy_name
, SYSTEMX_QUIET
, SYSTEMX_QUIET_STDERR
, NULL
);
56 printf("%s and %s are not identical: diff returned %d\n", orig_name
, copy_name
, rc
);
63 bool verify_copy_sizes(struct stat
*orig_sb
, struct stat
*copy_sb
, copyfile_state_t cpf_state
,
64 bool do_sparse
, off_t src_start
) {
65 off_t cpf_bytes_copied
, blocks_offset
;
68 // If requested, verify that the copy is a sparse file.
70 if (orig_sb
->st_size
- src_start
!= copy_sb
->st_size
) {
71 printf("original size - offset (%zd) != copy size (%zd)\n",
72 orig_sb
->st_size
- src_start
, copy_sb
->st_size
);
76 blocks_offset
= src_start
/ orig_sb
->st_blksize
;
77 if (orig_sb
->st_blocks
- blocks_offset
< copy_sb
->st_blocks
) {
78 printf("original blocks - offset (%zd) < copy blocks (%zd)\n",
79 orig_sb
->st_blocks
- blocks_offset
, copy_sb
->st_blocks
);
84 // Verify that the copyfile_state_t for the copy returns that all bytes were copied.
86 assert_no_err(copyfile_state_get(cpf_state
, COPYFILE_STATE_COPIED
, &cpf_bytes_copied
));
87 if (orig_sb
->st_size
- src_start
!= cpf_bytes_copied
) {
88 printf("original size - start (%zd) != copied bytes (%zd)\n",
89 orig_sb
->st_size
- src_start
, cpf_bytes_copied
);
97 int create_hole_in_fd(int fd
, off_t offset
, off_t length
) {
98 struct fpunchhole punchhole_args
= {
105 return fcntl(fd
, F_PUNCHHOLE
, &punchhole_args
);
109 void create_test_file_name(const char *dir
, const char *postfix
, int id
, char *string_out
) {
110 // Make a name for this new file and put it in out_name, which should be BSIZE_B bytes.
111 assert_with_errno(snprintf(string_out
, BSIZE_B
, "%s/testfile-%d.%s", dir
, id
, postfix
) > 0);
114 void disk_image_create(const char *fstype
, size_t size_in_mb
) {
117 // Set up good default values.
119 fstype
= DEFAULT_FSTYPE
;
121 if (size_in_mb
> MAX_DISK_IMAGE_SIZE_MB
) {
122 size_in_mb
= MAX_DISK_IMAGE_SIZE_MB
;
124 assert_with_errno(snprintf(size
, BSIZE_B
, "%zum", size_in_mb
) >= 3);
126 // Unmount and remove the sparseimage if it already exists.
127 disk_image_destroy(true);
128 if (removefile(DISK_IMAGE_PATH
, NULL
, REMOVEFILE_RECURSIVE
) < 0) {
129 assert_with_errno(errno
== ENOENT
);
132 // Make the disk image.
133 assert_no_err(systemx(HDIUTIL_PATH
, SYSTEMX_QUIET
, "create", "-fs", fstype
,
134 "-size", size
, "-type", "SPARSE", "-volname", "apfs_sparse",
135 DISK_IMAGE_PATH
, NULL
));
137 // Attach the disk image.
138 assert_no_err(systemx(HDIUTIL_PATH
, SYSTEMX_QUIET
, "attach", DISK_IMAGE_PATH
, NULL
));
141 void disk_image_destroy(bool allow_failure
) {
142 // If the caller allows, ignore any failures (also silence stderr).
144 systemx(HDIUTIL_PATH
, "eject", MOUNT_PATH
, SYSTEMX_QUIET
, SYSTEMX_QUIET_STDERR
, NULL
);
146 assert_no_err(systemx(HDIUTIL_PATH
, "eject", MOUNT_PATH
, SYSTEMX_QUIET
, NULL
));