]> git.saurik.com Git - apple/copyfile.git/blame_incremental - copyfile_test/test_utils.c
copyfile-166.tar.gz
[apple/copyfile.git] / copyfile_test / test_utils.c
... / ...
CommitLineData
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
18bool 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
29bool 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",
53 bad_off, (unsigned long long)orig_contents[bad_off],
54 (unsigned long long)copy_contents[bad_off]);
55 break;
56 }
57 }
58 }
59
60 return equal;
61}
62
63bool 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
75bool 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) {
83 printf("original size - offset (%lld) != copy size (%lld)\n",
84 orig_sb->st_size - src_start, copy_sb->st_size);
85 result = false;
86 }
87
88 blocks_offset = src_start / S_BLKSIZE;
89 if (orig_sb->st_blocks - blocks_offset < copy_sb->st_blocks) {
90 printf("original blocks - offset (%lld) < copy blocks (%lld)\n",
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) {
100 printf("original size - start (%lld) != copied bytes (%lld)\n",
101 orig_sb->st_size - src_start, cpf_bytes_copied);
102 result = false;
103 }
104 }
105
106 return result;
107}
108
109int 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
121void 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
126void 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
153void 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}