]> git.saurik.com Git - apple/copyfile.git/blob - copyfile_test/test_utils.c
copyfile-146.250.1.tar.gz
[apple/copyfile.git] / copyfile_test / test_utils.c
1 //
2 // test_utils.c
3 // copyfile_test
4 //
5
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <removefile.h>
11 #include <unistd.h>
12 #include <sys/fcntl.h>
13 #include <sys/stat.h>
14
15 #include "test_utils.h"
16 #include "systemx.h"
17
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];
22 bool equal;
23
24 assert(orig_fd > 0 && copy_fd > 0);
25 memset(orig_contents, 0, length);
26 memset(copy_contents, 0, length);
27
28 // Read the contents into our temporary buffers, and call memcmp().
29 errno = 0;
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);
34 if (!equal) {
35 printf("original fd (%lld - %lld) did not match copy (%lld - %lld)\n",
36 orig_pos, orig_pos + length, copy_pos, copy_pos + length);
37
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]);
43 break;
44 }
45 }
46 }
47
48 return equal;
49 }
50
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);
55 if (rc != 0) {
56 printf("%s and %s are not identical: diff returned %d\n", orig_name, copy_name, rc);
57 exit(1);
58 }
59
60 return !rc;
61 }
62
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;
66 bool result = true;
67
68 // If requested, verify that the copy is a sparse file.
69 if (do_sparse) {
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);
73 result = false;
74 }
75
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);
80 result = false;
81 }
82 }
83
84 // Verify that the copyfile_state_t for the copy returns that all bytes were copied.
85 if (cpf_state) {
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);
90 result = false;
91 }
92 }
93
94 return result;
95 }
96
97 int create_hole_in_fd(int fd, off_t offset, off_t length) {
98 struct fpunchhole punchhole_args = {
99 .fp_flags = 0,
100 .reserved = 0,
101 .fp_offset = offset,
102 .fp_length = length
103 };
104
105 return fcntl(fd, F_PUNCHHOLE, &punchhole_args);
106 }
107
108
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);
112 }
113
114 void disk_image_create(const char *fstype, size_t size_in_mb) {
115 char size[BSIZE_B];
116
117 // Set up good default values.
118 if (!fstype) {
119 fstype = DEFAULT_FSTYPE;
120 }
121 if (size_in_mb > MAX_DISK_IMAGE_SIZE_MB) {
122 size_in_mb = MAX_DISK_IMAGE_SIZE_MB;
123 }
124 assert_with_errno(snprintf(size, BSIZE_B, "%zum", size_in_mb) >= 3);
125
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);
130 }
131
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));
136
137 // Attach the disk image.
138 assert_no_err(systemx(HDIUTIL_PATH, SYSTEMX_QUIET, "attach", DISK_IMAGE_PATH, NULL));
139 }
140
141 void disk_image_destroy(bool allow_failure) {
142 // If the caller allows, ignore any failures (also silence stderr).
143 if (allow_failure) {
144 systemx(HDIUTIL_PATH, "eject", MOUNT_PATH, SYSTEMX_QUIET, SYSTEMX_QUIET_STDERR, NULL);
145 } else {
146 assert_no_err(systemx(HDIUTIL_PATH, "eject", MOUNT_PATH, SYSTEMX_QUIET, NULL));
147 }
148 }