2 * Copyright (c) 2003-2007 Tim Kientzle
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 __FBSDID("$FreeBSD$");
29 * Write a file using archive_write_data call, read the file
30 * back and verify the contents. The data written includes large
31 * blocks of nulls, so it should exercise the sparsification logic
32 * if ARCHIVE_EXTRACT_SPARSE is enabled.
35 verify_write_data(struct archive *a, int sparse)
37 static const char data[]="abcdefghijklmnopqrstuvwxyz";
39 struct archive_entry *ae;
40 size_t buff_size = 64 * 1024;
42 const char *msg = sparse ? "sparse" : "non-sparse";
45 buff = malloc(buff_size);
48 ae = archive_entry_new();
50 archive_entry_set_size(ae, 8 * buff_size);
51 archive_entry_set_pathname(ae, "test_write_data");
52 archive_entry_set_mode(ae, AE_IFREG | 0755);
53 assertEqualIntA(a, 0, archive_write_header(a, ae));
55 /* Use archive_write_data() to write three relatively sparse blocks. */
57 /* First has non-null data at beginning. */
58 memset(buff, 0, buff_size);
59 memcpy(buff, data, sizeof(data));
61 assertEqualInt(buff_size, archive_write_data(a, buff, buff_size));
63 /* Second has non-null data in the middle. */
64 memset(buff, 0, buff_size);
65 memcpy(buff + buff_size / 2 - 3, data, sizeof(data));
67 assertEqualInt(buff_size, archive_write_data(a, buff, buff_size));
69 /* Third has non-null data at the end. */
70 memset(buff, 0, buff_size);
71 memcpy(buff + buff_size - sizeof(data), data, sizeof(data));
73 assertEqualInt(buff_size, archive_write_data(a, buff, buff_size));
76 assertEqualIntA(a, 0, archive_write_finish_entry(a));
78 /* Test the entry on disk. */
79 assert(0 == stat(archive_entry_pathname(ae), &st));
80 assertEqualInt(st.st_size, 8 * buff_size);
81 fd = open(archive_entry_pathname(ae), O_RDONLY);
85 /* Check first block. */
86 assertEqualInt(buff_size, read(fd, buff, buff_size));
88 assertEqualMem(buff, data, sizeof(data));
89 for (p = buff + sizeof(data); p < buff + buff_size; ++p) {
90 failure("offset: %d, %s", (int)(p - buff), msg);
91 if (!assertEqualInt(0, *p))
95 /* Check second block. */
96 assertEqualInt(buff_size, read(fd, buff, buff_size));
97 for (p = buff; p < buff + buff_size; ++p) {
98 failure("offset: %d, %s", (int)(p - buff), msg);
99 if (p == buff + buff_size / 2 - 3) {
100 assertEqualMem(p, data, sizeof(data));
102 } else if (!assertEqualInt(0, *p))
106 /* Check third block. */
107 assertEqualInt(buff_size, read(fd, buff, buff_size));
108 for (p = buff; p < buff + buff_size - sizeof(data); ++p) {
109 failure("offset: %d, %s", (int)(p - buff), msg);
110 if (!assertEqualInt(0, *p))
114 assertEqualMem(buff + buff_size - sizeof(data), data, sizeof(data));
118 assertEqualInt(0, close(fd));
123 * As above, but using the archive_write_data_block() call.
126 verify_write_data_block(struct archive *a, int sparse)
128 static const char data[]="abcdefghijklmnopqrstuvwxyz";
130 struct archive_entry *ae;
131 size_t buff_size = 64 * 1024;
133 const char *msg = sparse ? "sparse" : "non-sparse";
136 buff = malloc(buff_size);
137 assert(buff != NULL);
139 ae = archive_entry_new();
141 archive_entry_set_size(ae, 8 * buff_size);
142 archive_entry_set_pathname(ae, "test_write_data_block");
143 archive_entry_set_mode(ae, AE_IFREG | 0755);
144 assertEqualIntA(a, 0, archive_write_header(a, ae));
146 /* Use archive_write_data_block() to write three
147 relatively sparse blocks. */
149 /* First has non-null data at beginning. */
150 memset(buff, 0, buff_size);
151 memcpy(buff, data, sizeof(data));
153 assertEqualInt(ARCHIVE_OK,
154 archive_write_data_block(a, buff, buff_size, 100));
156 /* Second has non-null data in the middle. */
157 memset(buff, 0, buff_size);
158 memcpy(buff + buff_size / 2 - 3, data, sizeof(data));
160 assertEqualInt(ARCHIVE_OK,
161 archive_write_data_block(a, buff, buff_size, buff_size + 200));
163 /* Third has non-null data at the end. */
164 memset(buff, 0, buff_size);
165 memcpy(buff + buff_size - sizeof(data), data, sizeof(data));
167 assertEqualInt(ARCHIVE_OK,
168 archive_write_data_block(a, buff, buff_size, buff_size * 2 + 300));
171 assertEqualIntA(a, 0, archive_write_finish_entry(a));
173 /* Test the entry on disk. */
174 assert(0 == stat(archive_entry_pathname(ae), &st));
175 assertEqualInt(st.st_size, 8 * buff_size);
176 fd = open(archive_entry_pathname(ae), O_RDONLY);
177 if (!assert(fd >= 0))
180 /* Check 100-byte gap at beginning */
181 assertEqualInt(100, read(fd, buff, 100));
183 for (p = buff; p < buff + 100; ++p) {
184 failure("offset: %d, %s", (int)(p - buff), msg);
185 if (!assertEqualInt(0, *p))
189 /* Check first block. */
190 assertEqualInt(buff_size, read(fd, buff, buff_size));
192 assertEqualMem(buff, data, sizeof(data));
193 for (p = buff + sizeof(data); p < buff + buff_size; ++p) {
194 failure("offset: %d, %s", (int)(p - buff), msg);
195 if (!assertEqualInt(0, *p))
199 /* Check 100-byte gap */
200 assertEqualInt(100, read(fd, buff, 100));
202 for (p = buff; p < buff + 100; ++p) {
203 failure("offset: %d, %s", (int)(p - buff), msg);
204 if (!assertEqualInt(0, *p))
208 /* Check second block. */
209 assertEqualInt(buff_size, read(fd, buff, buff_size));
210 for (p = buff; p < buff + buff_size; ++p) {
211 failure("offset: %d, %s", (int)(p - buff), msg);
212 if (p == buff + buff_size / 2 - 3) {
213 assertEqualMem(p, data, sizeof(data));
215 } else if (!assertEqualInt(0, *p))
219 /* Check 100-byte gap */
220 assertEqualInt(100, read(fd, buff, 100));
222 for (p = buff; p < buff + 100; ++p) {
223 failure("offset: %d, %s", (int)(p - buff), msg);
224 if (!assertEqualInt(0, *p))
228 /* Check third block. */
229 assertEqualInt(buff_size, read(fd, buff, buff_size));
230 for (p = buff; p < buff + buff_size - sizeof(data); ++p) {
231 failure("offset: %d, %s", (int)(p - buff), msg);
232 if (!assertEqualInt(0, *p))
236 assertEqualMem(buff + buff_size - sizeof(data), data, sizeof(data));
238 /* Check another block size beyond last we wrote. */
239 assertEqualInt(buff_size, read(fd, buff, buff_size));
241 for (p = buff; p < buff + buff_size; ++p) {
242 failure("offset: %d, %s", (int)(p - buff), msg);
243 if (!assertEqualInt(0, *p))
250 assertEqualInt(0, close(fd));
254 DEFINE_TEST(test_write_disk_sparse)
260 * The return values, etc, of the write data functions
261 * shouldn't change regardless of whether we've requested
262 * sparsification. (The performance and pattern of actual
263 * write calls to the disk should vary, of course, but the
264 * client program shouldn't see any difference.)
266 assert((ad = archive_write_disk_new()) != NULL);
267 archive_write_disk_set_options(ad, 0);
268 verify_write_data(ad, 0);
269 verify_write_data_block(ad, 0);
270 assertEqualInt(0, archive_write_finish(ad));
272 assert((ad = archive_write_disk_new()) != NULL);
273 archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_SPARSE);
274 verify_write_data(ad, 1);
275 verify_write_data_block(ad, 1);
276 assertEqualInt(0, archive_write_finish(ad));