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