]>
Commit | Line | Data |
---|---|---|
937356ff A |
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 | ||
23896e53 A |
18 | bool verify_st_flags(struct stat *sb, uint32_t flags_to_expect) { |
19 | // Verify that sb's flags include flags_to_expect. | |
20 | if (((sb->st_flags & flags_to_expect)) != flags_to_expect) { | |
21 | printf("st_flags (%u) do not include expected flags (%u)\n", | |
22 | sb->st_flags, flags_to_expect); | |
23 | return false; | |
24 | } | |
25 | ||
26 | return true; | |
27 | } | |
28 | ||
937356ff A |
29 | bool verify_fd_contents(int orig_fd, off_t orig_pos, int copy_fd, off_t copy_pos, size_t length) { |
30 | // Read *length* contents of the two fds and make sure they compare as equal. | |
31 | // Don't alter the position of either fd. | |
32 | char orig_contents[length], copy_contents[length]; | |
33 | bool equal; | |
34 | ||
35 | assert(orig_fd > 0 && copy_fd > 0); | |
36 | memset(orig_contents, 0, length); | |
37 | memset(copy_contents, 0, length); | |
38 | ||
39 | // Read the contents into our temporary buffers, and call memcmp(). | |
40 | errno = 0; | |
41 | ssize_t pread_res = pread(orig_fd, orig_contents, length, 0); | |
42 | assert_with_errno(pread_res == (off_t) length); | |
43 | assert_with_errno(pread(copy_fd, copy_contents, length, copy_pos) >= 0); | |
44 | equal = (memcmp(orig_contents, copy_contents, length) == 0); | |
45 | if (!equal) { | |
46 | printf("original fd (%lld - %lld) did not match copy (%lld - %lld)\n", | |
47 | orig_pos, orig_pos + length, copy_pos, copy_pos + length); | |
48 | ||
49 | // Find the first non-matching byte and print it out. | |
50 | for (size_t bad_off = 0; bad_off < length; bad_off++) { | |
51 | if (orig_contents[bad_off] != copy_contents[bad_off]) { | |
52 | printf("first mismatch is at offset %zu, original 0x%llx COPY 0x%llx\n", | |
23896e53 A |
53 | bad_off, (unsigned long long)orig_contents[bad_off], |
54 | (unsigned long long)copy_contents[bad_off]); | |
937356ff A |
55 | break; |
56 | } | |
57 | } | |
58 | } | |
59 | ||
60 | return equal; | |
61 | } | |
62 | ||
63 | bool verify_copy_contents(const char *orig_name, const char *copy_name) { | |
64 | // Verify that the copy and the source have identical contents. | |
65 | // Here, we just call out to 'diff' to do the work for us. | |
66 | int rc = systemx(DIFF_PATH, orig_name, copy_name, SYSTEMX_QUIET, SYSTEMX_QUIET_STDERR, NULL); | |
67 | if (rc != 0) { | |
68 | printf("%s and %s are not identical: diff returned %d\n", orig_name, copy_name, rc); | |
69 | exit(1); | |
70 | } | |
71 | ||
72 | return !rc; | |
73 | } | |
74 | ||
75 | bool verify_copy_sizes(struct stat *orig_sb, struct stat *copy_sb, copyfile_state_t cpf_state, | |
76 | bool do_sparse, off_t src_start) { | |
77 | off_t cpf_bytes_copied, blocks_offset; | |
78 | bool result = true; | |
79 | ||
80 | // If requested, verify that the copy is a sparse file. | |
81 | if (do_sparse) { | |
82 | if (orig_sb->st_size - src_start != copy_sb->st_size) { | |
23896e53 | 83 | printf("original size - offset (%lld) != copy size (%lld)\n", |
937356ff A |
84 | orig_sb->st_size - src_start, copy_sb->st_size); |
85 | result = false; | |
86 | } | |
87 | ||
23896e53 | 88 | blocks_offset = src_start / S_BLKSIZE; |
937356ff | 89 | if (orig_sb->st_blocks - blocks_offset < copy_sb->st_blocks) { |
23896e53 | 90 | printf("original blocks - offset (%lld) < copy blocks (%lld)\n", |
937356ff A |
91 | orig_sb->st_blocks - blocks_offset, copy_sb->st_blocks); |
92 | result = false; | |
93 | } | |
94 | } | |
95 | ||
96 | // Verify that the copyfile_state_t for the copy returns that all bytes were copied. | |
97 | if (cpf_state) { | |
98 | assert_no_err(copyfile_state_get(cpf_state, COPYFILE_STATE_COPIED, &cpf_bytes_copied)); | |
99 | if (orig_sb->st_size - src_start != cpf_bytes_copied) { | |
23896e53 | 100 | printf("original size - start (%lld) != copied bytes (%lld)\n", |
937356ff A |
101 | orig_sb->st_size - src_start, cpf_bytes_copied); |
102 | result = false; | |
103 | } | |
104 | } | |
105 | ||
106 | return result; | |
107 | } | |
108 | ||
109 | int create_hole_in_fd(int fd, off_t offset, off_t length) { | |
110 | struct fpunchhole punchhole_args = { | |
111 | .fp_flags = 0, | |
112 | .reserved = 0, | |
113 | .fp_offset = offset, | |
114 | .fp_length = length | |
115 | }; | |
116 | ||
117 | return fcntl(fd, F_PUNCHHOLE, &punchhole_args); | |
118 | } | |
119 | ||
120 | ||
121 | void create_test_file_name(const char *dir, const char *postfix, int id, char *string_out) { | |
122 | // Make a name for this new file and put it in out_name, which should be BSIZE_B bytes. | |
123 | assert_with_errno(snprintf(string_out, BSIZE_B, "%s/testfile-%d.%s", dir, id, postfix) > 0); | |
124 | } | |
125 | ||
126 | void disk_image_create(const char *fstype, size_t size_in_mb) { | |
127 | char size[BSIZE_B]; | |
128 | ||
129 | // Set up good default values. | |
130 | if (!fstype) { | |
131 | fstype = DEFAULT_FSTYPE; | |
132 | } | |
133 | if (size_in_mb > MAX_DISK_IMAGE_SIZE_MB) { | |
134 | size_in_mb = MAX_DISK_IMAGE_SIZE_MB; | |
135 | } | |
136 | assert_with_errno(snprintf(size, BSIZE_B, "%zum", size_in_mb) >= 3); | |
137 | ||
138 | // Unmount and remove the sparseimage if it already exists. | |
139 | disk_image_destroy(true); | |
140 | if (removefile(DISK_IMAGE_PATH, NULL, REMOVEFILE_RECURSIVE) < 0) { | |
141 | assert_with_errno(errno == ENOENT); | |
142 | } | |
143 | ||
144 | // Make the disk image. | |
145 | assert_no_err(systemx(HDIUTIL_PATH, SYSTEMX_QUIET, "create", "-fs", fstype, | |
146 | "-size", size, "-type", "SPARSE", "-volname", "apfs_sparse", | |
147 | DISK_IMAGE_PATH, NULL)); | |
148 | ||
149 | // Attach the disk image. | |
150 | assert_no_err(systemx(HDIUTIL_PATH, SYSTEMX_QUIET, "attach", DISK_IMAGE_PATH, NULL)); | |
151 | } | |
152 | ||
153 | void disk_image_destroy(bool allow_failure) { | |
154 | // If the caller allows, ignore any failures (also silence stderr). | |
155 | if (allow_failure) { | |
156 | systemx(HDIUTIL_PATH, "eject", MOUNT_PATH, SYSTEMX_QUIET, SYSTEMX_QUIET_STDERR, NULL); | |
157 | } else { | |
158 | assert_no_err(systemx(HDIUTIL_PATH, "eject", MOUNT_PATH, SYSTEMX_QUIET, NULL)); | |
159 | } | |
160 | } |