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$");
28 #if ARCHIVE_VERSION_NUMBER >= 1009000
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
38 #define MODE_MASK 0777777
40 static void create(struct archive_entry *ae, const char *msg)
45 /* Write the entry to disk. */
46 assert((ad = archive_write_disk_new()) != NULL);
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);
53 assertEqualInt(0, archive_write_finish(ad));
55 /* Test the entries on disk. */
56 assert(0 == stat(archive_entry_pathname(ae), &st));
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);
69 static void create_reg_file(struct archive_entry *ae, const char *msg)
71 static const char data[]="abcdefghijklmnopqrstuvwxyz";
74 /* Write the entry to disk. */
75 assert((ad = archive_write_disk_new()) != NULL);
76 archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_TIME);
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.
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);
103 assertEqualInt(0, archive_write_finish(ad));
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));
114 static void create_reg_file2(struct archive_entry *ae, const char *msg)
116 const int datasize = 100000;
121 data = malloc(datasize);
122 for (i = 0; i < datasize; i++)
123 data[i] = (char)(i % 256);
125 /* Write the entry to disk. */
126 assert((ad = archive_write_disk_new()) != NULL);
129 * See above for an explanation why this next call
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));
138 assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
139 assertEqualInt(0, archive_write_finish(ad));
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));
148 static void create_reg_file3(struct archive_entry *ae, const char *msg)
150 static const char data[]="abcdefghijklmnopqrstuvwxyz";
154 /* Write the entry to disk. */
155 assert((ad = archive_write_disk_new()) != NULL);
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);
165 assertEqualInt(0, archive_write_finish(ad));
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));
174 assertEqualInt(st.st_size, 5);
178 static void create_reg_file4(struct archive_entry *ae, const char *msg)
180 static const char data[]="abcdefghijklmnopqrstuvwxyz";
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);
194 assertEqualInt(0, archive_write_finish(ad));
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));
204 assertEqualInt(st.st_size, sizeof(data));
207 #if defined(_WIN32) && !defined(__CYGWIN__)
208 static void create_reg_file_win(struct archive_entry *ae, const char *msg)
210 static const char data[]="abcdefghijklmnopqrstuvwxyz";
216 /* Write the entry to disk. */
217 assert((ad = archive_write_disk_new()) != NULL);
218 archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_TIME);
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);
228 assertEqualInt(0, archive_write_finish(ad));
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 == '|')
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));
245 #endif /* _WIN32 && !__CYGWIN__ */
248 DEFINE_TEST(test_write_disk)
250 #if ARCHIVE_VERSION_NUMBER < 1009000
251 skipping("archive_write_disk interface");
253 struct archive_entry *ae;
255 /* Force the umask to something predictable. */
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);
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);
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);
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);
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);
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);
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);
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);
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);
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__ */