]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libarchive/test/test_write_disk.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / lib / libarchive / test / test_write_disk.c
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 __FBSDID("$FreeBSD$");
27
28 #if ARCHIVE_VERSION_NUMBER >= 1009000
29
30 #define UMASK 022
31
32 static void create(struct archive_entry *ae, const char *msg)
33 {
34         struct archive *ad;
35         struct stat st;
36
37         /* Write the entry to disk. */
38         assert((ad = archive_write_disk_new()) != NULL);
39         failure("%s", msg);
40         assertEqualIntA(ad, 0, archive_write_header(ad, ae));
41         assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
42 #if ARCHIVE_VERSION_NUMBER < 2000000
43         archive_write_finish(ad);
44 #else
45         assertEqualInt(0, archive_write_finish(ad));
46 #endif
47         /* Test the entries on disk. */
48         assert(0 == stat(archive_entry_pathname(ae), &st));
49         failure("st.st_mode=%o archive_entry_mode(ae)=%o",
50             st.st_mode, archive_entry_mode(ae));
51         /* When verifying a dir, ignore the S_ISGID bit, as some systems set
52          * that automatically. */
53         if (archive_entry_filetype(ae) == AE_IFDIR)
54                 st.st_mode &= ~S_ISGID;
55 #if !defined(_WIN32) || defined(__CYGWIN__)
56         assertEqualInt(st.st_mode, archive_entry_mode(ae) & ~UMASK);
57 #endif
58 }
59
60 static void create_reg_file(struct archive_entry *ae, const char *msg)
61 {
62         static const char data[]="abcdefghijklmnopqrstuvwxyz";
63         struct archive *ad;
64         struct stat st;
65         time_t now;
66
67         /* Write the entry to disk. */
68         assert((ad = archive_write_disk_new()) != NULL);
69         archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_TIME);
70         failure("%s", msg);
71         /*
72          * A touchy API design issue: archive_write_data() does (as of
73          * 2.4.12) enforce the entry size as a limit on the data
74          * written to the file.  This was not enforced prior to
75          * 2.4.12.  The change was prompted by the refined
76          * hardlink-restore semantics introduced at that time.  In
77          * short, libarchive needs to know whether a "hardlink entry"
78          * is going to overwrite the contents so that it can know
79          * whether or not to open the file for writing.  This implies
80          * that there is a fundamental semantic difference between an
81          * entry with a zero size and one with a non-zero size in the
82          * case of hardlinks and treating the hardlink case
83          * differently from the regular file case is just asking for
84          * trouble.  So, a zero size must always mean that no data
85          * will be accepted, which is consistent with the file size in
86          * the entry being a maximum size.
87          */
88         archive_entry_set_size(ae, sizeof(data));
89         archive_entry_set_mtime(ae, 123456789, 0);
90         assertEqualIntA(ad, 0, archive_write_header(ad, ae));
91         assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data)));
92         assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
93 #if ARCHIVE_VERSION_NUMBER < 2000000
94         archive_write_finish(ad);
95 #else
96         assertEqualInt(0, archive_write_finish(ad));
97 #endif
98         /* Test the entries on disk. */
99         assert(0 == stat(archive_entry_pathname(ae), &st));
100         failure("st.st_mode=%o archive_entry_mode(ae)=%o",
101             st.st_mode, archive_entry_mode(ae));
102 #if !defined(_WIN32) || defined(__CYGWIN__)
103         assertEqualInt(st.st_mode, (archive_entry_mode(ae) & ~UMASK));
104 #endif
105         assertEqualInt(st.st_size, sizeof(data));
106         /* test_write_disk_times has more detailed tests of this area. */
107         assertEqualInt(st.st_mtime, 123456789);
108         failure("No atime was specified, so atime should get set to current time");
109         now = time(NULL);
110         assert(st.st_atime <= now && st.st_atime > now - 5);
111 }
112
113 static void create_reg_file2(struct archive_entry *ae, const char *msg)
114 {
115         const int datasize = 100000;
116         char *data;
117         char *compare;
118         struct archive *ad;
119         struct stat st;
120         int i, fd;
121
122         data = malloc(datasize);
123         for (i = 0; i < datasize; i++)
124                 data[i] = (char)(i % 256);
125
126         /* Write the entry to disk. */
127         assert((ad = archive_write_disk_new()) != NULL);
128         failure("%s", msg);
129         /*
130          * See above for an explanation why this next call
131          * is necessary.
132          */
133         archive_entry_set_size(ae, datasize);
134         assertEqualIntA(ad, 0, archive_write_header(ad, ae));
135         for (i = 0; i < datasize - 999; i += 1000) {
136                 assertEqualIntA(ad, ARCHIVE_OK,
137                     archive_write_data_block(ad, data + i, 1000, i));
138         }
139         assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
140 #if ARCHIVE_VERSION_NUMBER < 2000000
141         archive_write_finish(ad);
142 #else
143         assertEqualInt(0, archive_write_finish(ad));
144 #endif
145         /* Test the entries on disk. */
146         assert(0 == stat(archive_entry_pathname(ae), &st));
147         failure("st.st_mode=%o archive_entry_mode(ae)=%o",
148             st.st_mode, archive_entry_mode(ae));
149 #if !defined(_WIN32) || defined(__CYGWIN__)
150         assertEqualInt(st.st_mode, (archive_entry_mode(ae) & ~UMASK));
151 #endif
152         assertEqualInt(st.st_size, i);
153
154         compare = malloc(datasize);
155         fd = open(archive_entry_pathname(ae), O_RDONLY);
156         assertEqualInt(datasize, read(fd, compare, datasize));
157         close(fd);
158         assert(memcmp(compare, data, datasize) == 0);
159         free(compare);
160         free(data);
161 }
162
163 static void create_reg_file3(struct archive_entry *ae, const char *msg)
164 {
165         static const char data[]="abcdefghijklmnopqrstuvwxyz";
166         struct archive *ad;
167         struct stat st;
168
169         /* Write the entry to disk. */
170         assert((ad = archive_write_disk_new()) != NULL);
171         failure("%s", msg);
172         /* Set the size smaller than the data and verify the truncation. */
173         archive_entry_set_size(ae, 5);
174         assertEqualIntA(ad, 0, archive_write_header(ad, ae));
175         assertEqualInt(5, archive_write_data(ad, data, sizeof(data)));
176         assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
177 #if ARCHIVE_VERSION_NUMBER < 2000000
178         archive_write_finish(ad);
179 #else
180         assertEqualInt(0, archive_write_finish(ad));
181 #endif
182         /* Test the entry on disk. */
183         assert(0 == stat(archive_entry_pathname(ae), &st));
184         failure("st.st_mode=%o archive_entry_mode(ae)=%o",
185             st.st_mode, archive_entry_mode(ae));
186 #if !defined(_WIN32) || defined(__CYGWIN__)
187         assertEqualInt(st.st_mode, (archive_entry_mode(ae) & ~UMASK));
188 #endif
189         assertEqualInt(st.st_size, 5);
190 }
191
192
193 static void create_reg_file4(struct archive_entry *ae, const char *msg)
194 {
195         static const char data[]="abcdefghijklmnopqrstuvwxyz";
196         struct archive *ad;
197         struct stat st;
198
199         /* Write the entry to disk. */
200         assert((ad = archive_write_disk_new()) != NULL);
201         /* Leave the size unset.  The data should not be truncated. */
202         assertEqualIntA(ad, 0, archive_write_header(ad, ae));
203         assertEqualInt(ARCHIVE_OK,
204             archive_write_data_block(ad, data, sizeof(data), 0));
205         assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
206 #if ARCHIVE_VERSION_NUMBER < 2000000
207         archive_write_finish(ad);
208 #else
209         assertEqualInt(0, archive_write_finish(ad));
210 #endif
211         /* Test the entry on disk. */
212         assert(0 == stat(archive_entry_pathname(ae), &st));
213         failure("st.st_mode=%o archive_entry_mode(ae)=%o",
214             st.st_mode, archive_entry_mode(ae));
215 #if !defined(_WIN32) || defined(__CYGWIN__)
216         assertEqualInt(st.st_mode, (archive_entry_mode(ae) & ~UMASK));
217 #endif
218         failure(msg);
219         assertEqualInt(st.st_size, sizeof(data));
220 }
221
222 #if defined(_WIN32) && !defined(__CYGWIN__)
223 static void create_reg_file_win(struct archive_entry *ae, const char *msg)
224 {
225         static const char data[]="abcdefghijklmnopqrstuvwxyz";
226         struct archive *ad;
227         struct stat st;
228         char *p, *fname;
229         size_t l;
230
231         /* Write the entry to disk. */
232         assert((ad = archive_write_disk_new()) != NULL);
233         archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_TIME);
234         failure("%s", msg);
235         archive_entry_set_size(ae, sizeof(data));
236         archive_entry_set_mtime(ae, 123456789, 0);
237         assertEqualIntA(ad, 0, archive_write_header(ad, ae));
238         assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data)));
239         assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
240 #if ARCHIVE_VERSION_NUMBER < 2000000
241         archive_write_finish(ad);
242 #else
243         assertEqualInt(0, archive_write_finish(ad));
244 #endif
245         /* Test the entries on disk. */
246         l = strlen(archive_entry_pathname(ae));
247         fname = malloc(l + 1);
248         assert(NULL != fname);
249         strcpy(fname, archive_entry_pathname(ae));
250         /* Replace unusable characters in Windows to '_' */
251         for (p = fname; *p != '\0'; p++)
252                 if (*p == ':' || *p == '*' || *p == '?' ||
253                     *p == '"' || *p == '<' || *p == '>' || *p == '|')
254                         *p = '_';
255         assert(0 == stat(fname, &st));
256         failure("st.st_mode=%o archive_entry_mode(ae)=%o",
257             st.st_mode, archive_entry_mode(ae));
258         assertEqualInt(st.st_size, sizeof(data));
259 }
260 #endif /* _WIN32 && !__CYGWIN__ */
261 #endif
262
263 DEFINE_TEST(test_write_disk)
264 {
265 #if ARCHIVE_VERSION_NUMBER < 1009000
266         skipping("archive_write_disk interface");
267 #else
268         struct archive_entry *ae;
269
270         /* Force the umask to something predictable. */
271         umask(UMASK);
272
273         /* A regular file. */
274         assert((ae = archive_entry_new()) != NULL);
275         archive_entry_copy_pathname(ae, "file");
276         archive_entry_set_mode(ae, S_IFREG | 0755);
277         create_reg_file(ae, "Test creating a regular file");
278         archive_entry_free(ae);
279
280         /* Another regular file. */
281         assert((ae = archive_entry_new()) != NULL);
282         archive_entry_copy_pathname(ae, "file2");
283         archive_entry_set_mode(ae, S_IFREG | 0755);
284         create_reg_file2(ae, "Test creating another regular file");
285         archive_entry_free(ae);
286
287         /* A regular file with a size restriction */
288         assert((ae = archive_entry_new()) != NULL);
289         archive_entry_copy_pathname(ae, "file3");
290         archive_entry_set_mode(ae, S_IFREG | 0755);
291         create_reg_file3(ae, "Regular file with size restriction");
292         archive_entry_free(ae);
293
294         /* A regular file with an unspecified size */
295         assert((ae = archive_entry_new()) != NULL);
296         archive_entry_copy_pathname(ae, "file3");
297         archive_entry_set_mode(ae, S_IFREG | 0755);
298         create_reg_file4(ae, "Regular file with unspecified size");
299         archive_entry_free(ae);
300
301         /* A regular file over an existing file */
302         assert((ae = archive_entry_new()) != NULL);
303         archive_entry_copy_pathname(ae, "file");
304         archive_entry_set_mode(ae, S_IFREG | 0724);
305         create(ae, "Test creating a file over an existing file.");
306         archive_entry_free(ae);
307
308         /* A directory. */
309         assert((ae = archive_entry_new()) != NULL);
310         archive_entry_copy_pathname(ae, "dir");
311         archive_entry_set_mode(ae, S_IFDIR | 0555);
312         create(ae, "Test creating a regular dir.");
313         archive_entry_free(ae);
314
315         /* A directory over an existing file. */
316         assert((ae = archive_entry_new()) != NULL);
317         archive_entry_copy_pathname(ae, "file");
318         archive_entry_set_mode(ae, S_IFDIR | 0742);
319         create(ae, "Test creating a dir over an existing file.");
320         archive_entry_free(ae);
321
322         /* A file over an existing dir. */
323         assert((ae = archive_entry_new()) != NULL);
324         archive_entry_copy_pathname(ae, "file");
325         archive_entry_set_mode(ae, S_IFREG | 0744);
326         create(ae, "Test creating a file over an existing dir.");
327         archive_entry_free(ae);
328
329 #if defined(_WIN32) && !defined(__CYGWIN__)
330         /* A file with unusable characters in its file name. */
331         assert((ae = archive_entry_new()) != NULL);
332         archive_entry_copy_pathname(ae, "f:i*l?e\"f<i>l|e");
333         archive_entry_set_mode(ae, S_IFREG | 0755);
334         create_reg_file_win(ae, "Test creating a regular file"
335             " with unusable characters in its file name");
336         archive_entry_free(ae);
337
338         /* A file with unusable characters in its directory name. */
339         assert((ae = archive_entry_new()) != NULL);
340         archive_entry_copy_pathname(ae, "d:i*r?e\"c<t>o|ry/file1");
341         archive_entry_set_mode(ae, S_IFREG | 0755);
342         create_reg_file_win(ae, "Test creating a regular file"
343             " with unusable characters in its file name");
344         archive_entry_free(ae);
345 #endif /* _WIN32 && !__CYGWIN__ */
346 #endif
347 }