1228753Smm/*-
2228753Smm * Copyright (c) 2003-2007 Tim Kientzle
3228753Smm * All rights reserved.
4228753Smm *
5228753Smm * Redistribution and use in source and binary forms, with or without
6228753Smm * modification, are permitted provided that the following conditions
7228753Smm * are met:
8228753Smm * 1. Redistributions of source code must retain the above copyright
9228753Smm *    notice, this list of conditions and the following disclaimer.
10228753Smm * 2. Redistributions in binary form must reproduce the above copyright
11228753Smm *    notice, this list of conditions and the following disclaimer in the
12228753Smm *    documentation and/or other materials provided with the distribution.
13228753Smm *
14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24228753Smm */
25228753Smm#include "test.h"
26228763Smm__FBSDID("$FreeBSD$");
27228753Smm
28228753Smmstatic void
29228753Smmtest_format(int	(*set_format)(struct archive *))
30228753Smm{
31228753Smm	char filedata[64];
32228753Smm	struct archive_entry *ae;
33228753Smm	struct archive *a;
34228753Smm	char *p;
35228753Smm	size_t used;
36228753Smm	size_t buffsize = 1000000;
37228753Smm	char *buff;
38228753Smm	int damaged = 0;
39228753Smm
40228753Smm	buff = malloc(buffsize);
41228753Smm
42228753Smm	/* Create a new archive in memory. */
43228753Smm	assert((a = archive_write_new()) != NULL);
44228753Smm	assertA(0 == (*set_format)(a));
45248616Smm	assertA(0 == archive_write_add_filter_none(a));
46228753Smm	assertA(0 == archive_write_open_memory(a, buff, buffsize, &used));
47228753Smm
48228753Smm	/*
49228753Smm	 * Write a file to it.
50228753Smm	 */
51228753Smm	assert((ae = archive_entry_new()) != NULL);
52228753Smm	archive_entry_set_mtime(ae, 1, 10);
53228753Smm	assert(1 == archive_entry_mtime(ae));
54228753Smm	assert(10 == archive_entry_mtime_nsec(ae));
55228753Smm	p = strdup("file");
56228753Smm	archive_entry_copy_pathname(ae, p);
57228753Smm	strcpy(p, "XXXX");
58228753Smm	free(p);
59228753Smm	assertEqualString("file", archive_entry_pathname(ae));
60228753Smm	archive_entry_set_mode(ae, S_IFREG | 0755);
61228753Smm	assert((S_IFREG | 0755) == archive_entry_mode(ae));
62228753Smm	archive_entry_set_size(ae, 8);
63228753Smm
64228753Smm	assertA(0 == archive_write_header(a, ae));
65228753Smm	archive_entry_free(ae);
66228753Smm	assertA(8 == archive_write_data(a, "12345678", 9));
67228753Smm
68228753Smm	/*
69228753Smm	 * Write another file to it.
70228753Smm	 */
71228753Smm	assert((ae = archive_entry_new()) != NULL);
72228753Smm	archive_entry_set_mtime(ae, 1, 10);
73228753Smm	assert(1 == archive_entry_mtime(ae));
74228753Smm	assert(10 == archive_entry_mtime_nsec(ae));
75228753Smm	p = strdup("file2");
76228753Smm	archive_entry_copy_pathname(ae, p);
77228753Smm	strcpy(p, "XXXX");
78228753Smm	free(p);
79228753Smm	assertEqualString("file2", archive_entry_pathname(ae));
80228753Smm	archive_entry_set_mode(ae, S_IFREG | 0755);
81228753Smm	assert((S_IFREG | 0755) == archive_entry_mode(ae));
82228753Smm	archive_entry_set_size(ae, 4);
83228753Smm
84228753Smm	assertA(0 == archive_write_header(a, ae));
85228753Smm	archive_entry_free(ae);
86228753Smm	assertA(4 == archive_write_data(a, "1234", 5));
87228753Smm
88228753Smm	/*
89232153Smm	 * Write a file with a name, filetype, and size.
90232153Smm	 */
91232153Smm	assert((ae = archive_entry_new()) != NULL);
92232153Smm	archive_entry_copy_pathname(ae, "name");
93232153Smm	archive_entry_set_size(ae, 0);
94232153Smm	archive_entry_set_filetype(ae, AE_IFREG);
95232153Smm	assertEqualInt(ARCHIVE_OK, archive_write_header(a, ae));
96232153Smm	assert(archive_error_string(a) == NULL);
97232153Smm	archive_entry_free(ae);
98232153Smm
99232153Smm	/*
100232153Smm	 * Write a file with a name and filetype but no size.
101232153Smm	 */
102232153Smm	assert((ae = archive_entry_new()) != NULL);
103232153Smm	archive_entry_copy_pathname(ae, "name");
104232153Smm	archive_entry_unset_size(ae);
105232153Smm	archive_entry_set_filetype(ae, AE_IFREG);
106232153Smm	assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
107232153Smm	assert(archive_error_string(a) != NULL);
108232153Smm	archive_entry_free(ae);
109232153Smm
110232153Smm	/*
111232153Smm	 * Write a file with a name and size but no filetype.
112232153Smm	 */
113232153Smm	assert((ae = archive_entry_new()) != NULL);
114232153Smm	archive_entry_copy_pathname(ae, "name");
115232153Smm	archive_entry_set_size(ae, 0);
116232153Smm	assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
117232153Smm	assert(archive_error_string(a) != NULL);
118232153Smm	archive_entry_free(ae);
119232153Smm
120232153Smm	/*
121232153Smm	 * Write a file with a size and filetype but no name.
122232153Smm	 */
123232153Smm	assert((ae = archive_entry_new()) != NULL);
124232153Smm	archive_entry_set_size(ae, 0);
125232153Smm	archive_entry_set_filetype(ae, AE_IFREG);
126232153Smm	assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
127232153Smm	assert(archive_error_string(a) != NULL);
128232153Smm	archive_entry_free(ae);
129232153Smm
130232153Smm	/*
131228753Smm	 * Write a directory to it.
132228753Smm	 */
133228753Smm	assert((ae = archive_entry_new()) != NULL);
134228753Smm	archive_entry_set_mtime(ae, 11, 110);
135228753Smm	archive_entry_copy_pathname(ae, "dir");
136228753Smm	archive_entry_set_mode(ae, S_IFDIR | 0755);
137228753Smm	archive_entry_set_size(ae, 512);
138228753Smm
139228753Smm	assertA(0 == archive_write_header(a, ae));
140228753Smm	assertEqualInt(0, archive_entry_size(ae));
141228753Smm	archive_entry_free(ae);
142228753Smm	assertEqualIntA(a, 0, archive_write_data(a, "12345678", 9));
143228753Smm
144228753Smm
145228753Smm	/* Close out the archive. */
146232153Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
147232153Smm	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
148228753Smm
149228753Smm	/*
150228753Smm	 * Damage the second entry to test the search-ahead recovery.
151228753Smm	 * TODO: Move the damage-recovery checking to a separate test;
152228753Smm	 * it doesn't really belong in this write test.
153228753Smm	 */
154228753Smm	{
155228753Smm		int i;
156228753Smm		for (i = 80; i < 150; i++) {
157228753Smm			if (memcmp(buff + i, "07070", 5) == 0) {
158228753Smm				damaged = 1;
159228753Smm				buff[i] = 'X';
160228753Smm				break;
161228753Smm			}
162228753Smm		}
163228753Smm	}
164228753Smm	failure("Unable to locate the second header for damage-recovery test.");
165228753Smm	assert(damaged == 1);
166228753Smm
167228753Smm	/*
168228753Smm	 * Now, read the data back.
169228753Smm	 */
170228753Smm	assert((a = archive_read_new()) != NULL);
171228753Smm	assertA(0 == archive_read_support_format_all(a));
172232153Smm	assertA(0 == archive_read_support_filter_all(a));
173228753Smm	assertA(0 == archive_read_open_memory(a, buff, used));
174228753Smm
175228753Smm	if (!assertEqualIntA(a, 0, archive_read_next_header(a, &ae))) {
176232153Smm		archive_read_free(a);
177228753Smm		return;
178228753Smm	}
179228753Smm
180228753Smm	assertEqualInt(1, archive_entry_mtime(ae));
181228753Smm	/* Not the same as above: cpio doesn't store hi-res times. */
182228753Smm	assert(0 == archive_entry_mtime_nsec(ae));
183228753Smm	assert(0 == archive_entry_atime(ae));
184228753Smm	assert(0 == archive_entry_ctime(ae));
185228753Smm	assertEqualString("file", archive_entry_pathname(ae));
186228753Smm	assertEqualInt((S_IFREG | 0755), archive_entry_mode(ae));
187228753Smm	assertEqualInt(8, archive_entry_size(ae));
188228753Smm	assertA(8 == archive_read_data(a, filedata, 10));
189232153Smm	assertEqualMem(filedata, "12345678", 8);
190228753Smm
191228753Smm	/*
192228753Smm	 * The second file can't be read because we damaged its header.
193228753Smm	 */
194228753Smm
195228753Smm	/*
196232153Smm	 * Read the third file back.
197228753Smm	 * ARCHIVE_WARN here because the damaged entry was skipped.
198228753Smm	 */
199228753Smm	assertEqualIntA(a, ARCHIVE_WARN, archive_read_next_header(a, &ae));
200232153Smm	assertEqualString("name", archive_entry_pathname(ae));
201232153Smm
202232153Smm	/*
203232153Smm	 * Read the dir entry back.
204232153Smm	 */
205232153Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
206228753Smm	assertEqualInt(11, archive_entry_mtime(ae));
207228753Smm	assert(0 == archive_entry_mtime_nsec(ae));
208228753Smm	assert(0 == archive_entry_atime(ae));
209228753Smm	assert(0 == archive_entry_ctime(ae));
210228753Smm	assertEqualString("dir", archive_entry_pathname(ae));
211228753Smm	assertEqualInt((S_IFDIR | 0755), archive_entry_mode(ae));
212228753Smm	assertEqualInt(0, archive_entry_size(ae));
213228753Smm	assertEqualIntA(a, 0, archive_read_data(a, filedata, 10));
214228753Smm
215228753Smm	/* Verify the end of the archive. */
216228753Smm	assertEqualIntA(a, 1, archive_read_next_header(a, &ae));
217232153Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
218232153Smm	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
219228753Smm
220228753Smm	free(buff);
221228753Smm}
222228753Smm
223232153Smmstatic void
224232153Smmtest_big_entries(int (*set_format)(struct archive *), int64_t size, int expected)
225232153Smm{
226232153Smm	struct archive_entry *ae;
227232153Smm	struct archive *a;
228232153Smm	size_t buffsize = 1000000;
229232153Smm	size_t used;
230232153Smm	char *buff;
231232153Smm
232232153Smm	buff = malloc(buffsize);
233232153Smm
234232153Smm	/* Create a new archive in memory. */
235232153Smm	assert((a = archive_write_new()) != NULL);
236232153Smm	assertA(0 == (*set_format)(a));
237248616Smm	assertA(0 == archive_write_add_filter_none(a));
238232153Smm	assertA(0 == archive_write_open_memory(a, buff, buffsize, &used));
239232153Smm
240232153Smm	assert((ae = archive_entry_new()) != NULL);
241232153Smm	archive_entry_copy_pathname(ae, "file");
242232153Smm	archive_entry_set_size(ae, size);
243232153Smm	archive_entry_set_filetype(ae, AE_IFREG);
244232153Smm	assertEqualInt(expected, archive_write_header(a, ae));
245232153Smm	if (expected != ARCHIVE_OK)
246232153Smm		assert(archive_error_string(a) != NULL);
247232153Smm
248232153Smm	archive_entry_free(ae);
249232153Smm	archive_write_free(a);
250232153Smm	free(buff);
251232153Smm}
252232153Smm
253232153Smm
254228753SmmDEFINE_TEST(test_write_format_cpio)
255228753Smm{
256232153Smm	int64_t size_4g = ((int64_t)1) << 32;
257232153Smm	int64_t size_8g = ((int64_t)1) << 33;
258232153Smm
259228753Smm	test_format(archive_write_set_format_cpio);
260228753Smm	test_format(archive_write_set_format_cpio_newc);
261232153Smm
262232153Smm	test_big_entries(archive_write_set_format_cpio,
263232153Smm	    size_8g - 1, ARCHIVE_OK);
264232153Smm	test_big_entries(archive_write_set_format_cpio,
265232153Smm	    size_8g, ARCHIVE_FAILED);
266232153Smm	test_big_entries(archive_write_set_format_cpio_newc,
267232153Smm	    size_4g - 1, ARCHIVE_OK);
268232153Smm	test_big_entries(archive_write_set_format_cpio_newc,
269232153Smm	    size_4g, ARCHIVE_FAILED);
270228753Smm}
271