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