1 /*-
2 * Copyright (c) 2003-2007 Tim Kientzle
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
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.
24 */
25 #include "test.h"
26
27 /*
28 * Write a file using archive_write_data call, read the file
29 * back and verify the contents. The data written includes large
30 * blocks of nulls, so it should exercise the sparsification logic
31 * if ARCHIVE_EXTRACT_SPARSE is enabled.
32 */
33 static void
verify_write_data(struct archive * a,int sparse)34 verify_write_data(struct archive *a, int sparse)
35 {
36 static const char data[]="abcdefghijklmnopqrstuvwxyz";
37 struct stat st;
38 struct archive_entry *ae;
39 size_t buff_size = 64 * 1024;
40 char *buff, *p;
41 const char *msg = sparse ? "sparse" : "non-sparse";
42 FILE *f;
43
44 buff = malloc(buff_size);
45 assert(buff != NULL);
46 if (buff == NULL)
47 return;
48
49 ae = archive_entry_new();
50 assert(ae != NULL);
51 archive_entry_set_size(ae, 8 * buff_size);
52 archive_entry_set_pathname(ae, "test_write_data");
53 archive_entry_set_mode(ae, AE_IFREG | 0755);
54 assertEqualIntA(a, 0, archive_write_header(a, ae));
55
56 /* Use archive_write_data() to write three relatively sparse blocks. */
57
58 /* First has non-null data at beginning. */
59 memset(buff, 0, buff_size);
60 memcpy(buff, data, sizeof(data));
61 failure("%s", msg);
62 assertEqualInt(buff_size, archive_write_data(a, buff, buff_size));
63
64 /* Second has non-null data in the middle. */
65 memset(buff, 0, buff_size);
66 memcpy(buff + buff_size / 2 - 3, data, sizeof(data));
67 failure("%s", msg);
68 assertEqualInt(buff_size, archive_write_data(a, buff, buff_size));
69
70 /* Third has non-null data at the end. */
71 memset(buff, 0, buff_size);
72 memcpy(buff + buff_size - sizeof(data), data, sizeof(data));
73 failure("%s", msg);
74 assertEqualInt(buff_size, archive_write_data(a, buff, buff_size));
75
76 failure("%s", msg);
77 assertEqualIntA(a, 0, archive_write_finish_entry(a));
78
79 /* Test the entry on disk. */
80 assert(0 == stat(archive_entry_pathname(ae), &st));
81 assertEqualInt(st.st_size, 8 * buff_size);
82 f = fopen(archive_entry_pathname(ae), "rb");
83 assert(f != NULL);
84 if (f == NULL) {
85 free(buff);
86 return;
87 }
88
89 /* Check first block. */
90 assertEqualInt(buff_size, fread(buff, 1, buff_size, f));
91 failure("%s", msg);
92 assertEqualMem(buff, data, sizeof(data));
93 for (p = buff + sizeof(data); p < buff + buff_size; ++p) {
94 failure("offset: %d, %s", (int)(p - buff), msg);
95 if (!assertEqualInt(0, *p))
96 break;
97 }
98
99 /* Check second block. */
100 assertEqualInt(buff_size, fread(buff, 1, buff_size, f));
101 for (p = buff; p < buff + buff_size; ++p) {
102 failure("offset: %d, %s", (int)(p - buff), msg);
103 if (p == buff + buff_size / 2 - 3) {
104 assertEqualMem(p, data, sizeof(data));
105 p += sizeof(data);
106 } else if (!assertEqualInt(0, *p))
107 break;
108 }
109
110 /* Check third block. */
111 assertEqualInt(buff_size, fread(buff, 1, buff_size, f));
112 for (p = buff; p < buff + buff_size - sizeof(data); ++p) {
113 failure("offset: %d, %s", (int)(p - buff), msg);
114 if (!assertEqualInt(0, *p))
115 break;
116 }
117 failure("%s", msg);
118 assertEqualMem(buff + buff_size - sizeof(data), data, sizeof(data));
119
120 /* XXX more XXX */
121
122 assertEqualInt(0, fclose(f));
123 archive_entry_free(ae);
124 free(buff);
125 }
126
127 /*
128 * As above, but using the archive_write_data_block() call.
129 */
130 static void
verify_write_data_block(struct archive * a,int sparse)131 verify_write_data_block(struct archive *a, int sparse)
132 {
133 static const char data[]="abcdefghijklmnopqrstuvwxyz";
134 struct stat st;
135 struct archive_entry *ae;
136 size_t buff_size = 64 * 1024;
137 char *buff, *p;
138 const char *msg = sparse ? "sparse" : "non-sparse";
139 FILE *f;
140
141 buff = malloc(buff_size);
142 assert(buff != NULL);
143 if (buff == NULL)
144 return;
145
146 ae = archive_entry_new();
147 assert(ae != NULL);
148 archive_entry_set_size(ae, 8 * buff_size);
149 archive_entry_set_pathname(ae, "test_write_data_block");
150 archive_entry_set_mode(ae, AE_IFREG | 0755);
151 assertEqualIntA(a, 0, archive_write_header(a, ae));
152
153 /* Use archive_write_data_block() to write three
154 relatively sparse blocks. */
155
156 /* First has non-null data at beginning. */
157 memset(buff, 0, buff_size);
158 memcpy(buff, data, sizeof(data));
159 failure("%s", msg);
160 assertEqualInt(ARCHIVE_OK,
161 archive_write_data_block(a, buff, buff_size, 100));
162
163 /* Second has non-null data in the middle. */
164 memset(buff, 0, buff_size);
165 memcpy(buff + buff_size / 2 - 3, data, sizeof(data));
166 failure("%s", msg);
167 assertEqualInt(ARCHIVE_OK,
168 archive_write_data_block(a, buff, buff_size, buff_size + 200));
169
170 /* Third has non-null data at the end. */
171 memset(buff, 0, buff_size);
172 memcpy(buff + buff_size - sizeof(data), data, sizeof(data));
173 failure("%s", msg);
174 assertEqualInt(ARCHIVE_OK,
175 archive_write_data_block(a, buff, buff_size, buff_size * 2 + 300));
176
177 failure("%s", msg);
178 assertEqualIntA(a, 0, archive_write_finish_entry(a));
179
180 /* Test the entry on disk. */
181 assert(0 == stat(archive_entry_pathname(ae), &st));
182 assertEqualInt(st.st_size, 8 * buff_size);
183 f = fopen(archive_entry_pathname(ae), "rb");
184 assert(f != NULL);
185 if (f == NULL) {
186 free(buff);
187 return;
188 }
189
190 /* Check 100-byte gap at beginning */
191 assertEqualInt(100, fread(buff, 1, 100, f));
192 failure("%s", msg);
193 for (p = buff; p < buff + 100; ++p) {
194 failure("offset: %d, %s", (int)(p - buff), msg);
195 if (!assertEqualInt(0, *p))
196 break;
197 }
198
199 /* Check first block. */
200 assertEqualInt(buff_size, fread(buff, 1, buff_size, f));
201 failure("%s", msg);
202 assertEqualMem(buff, data, sizeof(data));
203 for (p = buff + sizeof(data); p < buff + buff_size; ++p) {
204 failure("offset: %d, %s", (int)(p - buff), msg);
205 if (!assertEqualInt(0, *p))
206 break;
207 }
208
209 /* Check 100-byte gap */
210 assertEqualInt(100, fread(buff, 1, 100, f));
211 failure("%s", msg);
212 for (p = buff; p < buff + 100; ++p) {
213 failure("offset: %d, %s", (int)(p - buff), msg);
214 if (!assertEqualInt(0, *p))
215 break;
216 }
217
218 /* Check second block. */
219 assertEqualInt(buff_size, fread(buff, 1, buff_size, f));
220 for (p = buff; p < buff + buff_size; ++p) {
221 failure("offset: %d, %s", (int)(p - buff), msg);
222 if (p == buff + buff_size / 2 - 3) {
223 assertEqualMem(p, data, sizeof(data));
224 p += sizeof(data);
225 } else if (!assertEqualInt(0, *p))
226 break;
227 }
228
229 /* Check 100-byte gap */
230 assertEqualInt(100, fread(buff, 1, 100, f));
231 failure("%s", msg);
232 for (p = buff; p < buff + 100; ++p) {
233 failure("offset: %d, %s", (int)(p - buff), msg);
234 if (!assertEqualInt(0, *p))
235 break;
236 }
237
238 /* Check third block. */
239 assertEqualInt(buff_size, fread(buff, 1, buff_size, f));
240 for (p = buff; p < buff + buff_size - sizeof(data); ++p) {
241 failure("offset: %d, %s", (int)(p - buff), msg);
242 if (!assertEqualInt(0, *p))
243 break;
244 }
245 failure("%s", msg);
246 assertEqualMem(buff + buff_size - sizeof(data), data, sizeof(data));
247
248 /* Check another block size beyond last we wrote. */
249 assertEqualInt(buff_size, fread(buff, 1, buff_size, f));
250 failure("%s", msg);
251 for (p = buff; p < buff + buff_size; ++p) {
252 failure("offset: %d, %s", (int)(p - buff), msg);
253 if (!assertEqualInt(0, *p))
254 break;
255 }
256
257
258 /* XXX more XXX */
259
260 assertEqualInt(0, fclose(f));
261 free(buff);
262 archive_entry_free(ae);
263 }
264
DEFINE_TEST(test_write_disk_sparse)265 DEFINE_TEST(test_write_disk_sparse)
266 {
267 struct archive *ad;
268
269
270 /*
271 * The return values, etc, of the write data functions
272 * shouldn't change regardless of whether we've requested
273 * sparsification. (The performance and pattern of actual
274 * write calls to the disk should vary, of course, but the
275 * client program shouldn't see any difference.)
276 */
277 assert((ad = archive_write_disk_new()) != NULL);
278 archive_write_disk_set_options(ad, 0);
279 verify_write_data(ad, 0);
280 verify_write_data_block(ad, 0);
281 assertEqualInt(0, archive_write_free(ad));
282
283 assert((ad = archive_write_disk_new()) != NULL);
284 archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_SPARSE);
285 verify_write_data(ad, 1);
286 verify_write_data_block(ad, 1);
287 assertEqualInt(0, archive_write_free(ad));
288
289 }
290