1231200Smm/*-
2231200Smm * Copyright (c) 2009 Michihiro NAKAJIMA
3231200Smm * All rights reserved.
4231200Smm *
5231200Smm * Redistribution and use in source and binary forms, with or without
6231200Smm * modification, are permitted provided that the following conditions
7231200Smm * are met:
8231200Smm * 1. Redistributions of source code must retain the above copyright
9231200Smm *    notice, this list of conditions and the following disclaimer.
10231200Smm * 2. Redistributions in binary form must reproduce the above copyright
11231200Smm *    notice, this list of conditions and the following disclaimer in the
12231200Smm *    documentation and/or other materials provided with the distribution.
13231200Smm *
14231200Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15231200Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16231200Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17231200Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18231200Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19231200Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20231200Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21231200Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22231200Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23231200Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24231200Smm */
25231200Smm#include "test.h"
26231200Smm
27231200Smm/*
28231200Smm * Check that a "bootable CD" ISO 9660 image is correctly created.
29231200Smm */
30231200Smm
31231200Smmstatic const unsigned char primary_id[] = {
32231200Smm    0x01, 0x43, 0x44, 0x30, 0x30, 0x31, 0x01, 0x00
33231200Smm};
34231200Smmstatic const unsigned char volumesize[] = {
35231200Smm    0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26
36231200Smm};
37231200Smmstatic const unsigned char volumeidu16[] = {
38231200Smm    0x00, 0x43, 0x00, 0x44, 0x00, 0x52, 0x00, 0x4f,
39231200Smm    0x00, 0x4d, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
40231200Smm    0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
41231200Smm    0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20
42231200Smm};
43231200Smmstatic const unsigned char boot_id[] = {
44231200Smm    0x00, 0x43, 0x44, 0x30, 0x30, 0x31, 0x01, 0x45,
45231200Smm    0x4c, 0x20, 0x54, 0x4f, 0x52, 0x49, 0x54, 0x4f,
46231200Smm    0x20, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49,
47231200Smm    0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00,
48231200Smm    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49231200Smm};
50231200Smm
51231200Smmstatic const unsigned char supplementary_id[] = {
52231200Smm    0x02, 0x43, 0x44, 0x30, 0x30, 0x31, 0x01, 0x00
53231200Smm};
54231200Smmstatic const unsigned char terminator_id[] = {
55231200Smm    0xff, 0x43, 0x44, 0x30, 0x30, 0x31, 0x01, 0x00
56231200Smm};
57231200Smm
58231200Smmstatic const unsigned char boot_catalog[] = {
59231200Smm    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60231200Smm    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61231200Smm    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62231200Smm    0x00, 0x00, 0x00, 0x00, 0xaa, 0x55, 0x55, 0xaa,
63231200Smm    0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
64231200Smm    0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65231200Smm    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66231200Smm    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
67231200Smm};
68231200Smm
69231200Smmstatic const unsigned char info_table[] = {
70231200Smm    0x10, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
71231200Smm    0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72231200Smm    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73231200Smm    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74231200Smm    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75231200Smm    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76231200Smm    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
77231200Smm};
78231200Smm
79231200Smmstatic const unsigned char el_torito_signature[] = {
80231200Smm    "ER\355\001\012T\207\001RRIP_1991ATHE ROCK RIDGE "
81231200Smm    "INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX "
82231200Smm    "FILE SYSTEM SEMANTICSPLEASE CONTACT DISC PUBLISHER "
83231200Smm    "FOR SPECIFICATION SOURCE.  SEE PUBLISHER IDENTIFIER "
84231200Smm    "IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION."
85231200Smm};
86231200Smm
87231200Smmchar buff2[1024];
88231200Smm
89231200Smmstatic void
90231200Smm_test_write_format_iso9660_boot(int write_info_tbl)
91231200Smm{
92231200Smm	unsigned char nullb[2048];
93231200Smm	struct archive *a;
94231200Smm	struct archive_entry *ae;
95231200Smm	unsigned char *buff;
96231200Smm	size_t buffsize = 39 * 2048;
97231200Smm	size_t used;
98231200Smm	unsigned int i;
99231200Smm
100231200Smm	memset(nullb, 0, sizeof(nullb));
101231200Smm	buff = malloc(buffsize);
102231200Smm	assert(buff != NULL);
103231200Smm
104231200Smm	/* ISO9660 format: Create a new archive in memory. */
105231200Smm	assert((a = archive_write_new()) != NULL);
106231200Smm	assertA(0 == archive_write_set_format_iso9660(a));
107248616Smm	assertA(0 == archive_write_add_filter_none(a));
108231200Smm	assertA(0 == archive_write_set_option(a, NULL, "boot", "boot.img"));
109231200Smm	if (write_info_tbl)
110231200Smm		assertA(0 == archive_write_set_option(a, NULL, "boot-info-table", "1"));
111231200Smm	assertA(0 == archive_write_set_option(a, NULL, "pad", NULL));
112231200Smm	assertA(0 == archive_write_open_memory(a, buff, buffsize, &used));
113231200Smm
114231200Smm	/*
115231200Smm	 * "boot.img" has a bunch of attributes and 10K bytes of null data.
116231200Smm	 */
117231200Smm	assert((ae = archive_entry_new()) != NULL);
118231200Smm	archive_entry_set_atime(ae, 2, 20);
119231200Smm	archive_entry_set_birthtime(ae, 3, 30);
120231200Smm	archive_entry_set_ctime(ae, 4, 40);
121231200Smm	archive_entry_set_mtime(ae, 5, 50);
122231200Smm	archive_entry_copy_pathname(ae, "boot.img");
123231200Smm	archive_entry_set_mode(ae, S_IFREG | 0755);
124231200Smm	archive_entry_set_nlink(ae, 1);
125231200Smm	archive_entry_set_size(ae, 10*1024);
126231200Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
127231200Smm	archive_entry_free(ae);
128231200Smm	for (i = 0; i < 10; i++)
129231200Smm		assertEqualIntA(a, 1024, archive_write_data(a, nullb, 1024));
130231200Smm
131231200Smm	/* Close out the archive. */
132231200Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
133231200Smm	assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
134231200Smm
135231200Smm	assert(used == 2048 * 38);
136231200Smm	/* Check System Area. */
137231200Smm	for (i = 0; i < 2048 * 16; i += 2048) {
138231200Smm		assertEqualMem(buff+i, nullb, 2048);
139231200Smm	}
140231200Smm
141231200Smm	/* Primary Volume. */
142231200Smm	failure("Primary Volume Descriptor should be in 16 Logical Sector.");
143231200Smm	assertEqualMem(buff+2048*16, primary_id, 8);
144231200Smm	assertEqualMem(buff+2048*16+0x28,
145231200Smm	    "CDROM                           ", 32);
146231200Smm	assertEqualMem(buff+2048*16+0x50, volumesize, 8);
147231200Smm
148231200Smm	/* Boot Volume. */
149231200Smm	failure("Boot Volume Descriptor should be in 17 Logical Sector.");
150231200Smm	assertEqualMem(buff+2048*17, boot_id, sizeof(boot_id));
151231200Smm	for (i = 0x27; i <= 0x46; i++) {
152231200Smm		failure("Unused area must be all nulls.");
153231200Smm		assert(buff[2048*17+i] == 0);
154231200Smm	}
155231200Smm	/* First sector of Boot Catalog. */
156231200Smm	assert(buff[2048*17+0x47] == 0x20);
157231200Smm	assert(buff[2048*17+0x48] == 0x00);
158231200Smm	assert(buff[2048*17+0x49] == 0x00);
159231200Smm	assert(buff[2048*17+0x4a] == 0x00);
160231200Smm	for (i = 0x4a; i <= 0x7ff; i++) {
161231200Smm		failure("Unused area must be all nulls.");
162231200Smm		assert(buff[2048*17+i] == 0);
163231200Smm	}
164231200Smm
165231200Smm	/* Supplementary Volume. */
166231200Smm	failure("Supplementary Volume(Joliet) Descriptor "
167231200Smm	    "should be in 18 Logical Sector.");
168231200Smm	assertEqualMem(buff+2048*18, supplementary_id, 8);
169231200Smm	assertEqualMem(buff+2048*18+0x28, volumeidu16, 32);
170231200Smm	assertEqualMem(buff+2048*18+0x50, volumesize, 8);
171231200Smm	failure("Date and Time of Primary Volume and "
172231200Smm	    "Date and Time of Supplementary Volume "
173231200Smm	    "must be the same.");
174231200Smm	assertEqualMem(buff+2048*16+0x32d, buff+2048*18+0x32d, 0x44);
175231200Smm
176231200Smm	/* Terminator. */
177231200Smm	failure("Volume Descriptor Set Terminator "
178231200Smm	    "should be in 19 Logical Sector.");
179231200Smm	assertEqualMem(buff+2048*19, terminator_id, 8);
180231200Smm	for (i = 8; i < 2048; i++) {
181231200Smm		failure("Body of Volume Descriptor Set Terminator "
182231200Smm		    "should be all nulls.");
183231200Smm		assert(buff[2048*19+i] == 0);
184231200Smm	}
185231200Smm
186231200Smm	/* Check signature of El-Torito. */
187231200Smm	assertEqualMem(buff+2048*31, el_torito_signature, 237);
188231200Smm	assertEqualMem(buff+2048*31+237, nullb, 2048-237);
189231200Smm
190231200Smm	/* Check contents of "boot.catalog". */
191231200Smm	assertEqualMem(buff+2048*32, boot_catalog, 64);
192231200Smm	assertEqualMem(buff+2048*32+64, nullb, 2048-64);
193231200Smm
194231200Smm	/* Check contents of "boot.img". */
195231200Smm	if (write_info_tbl) {
196231200Smm		assertEqualMem(buff+2048*33, nullb, 8);
197231200Smm		assertEqualMem(buff+2048*33+8, info_table, 56);
198231200Smm		assertEqualMem(buff+2048*33+64, nullb, 2048-64);
199231200Smm	} else {
200231200Smm		assertEqualMem(buff+2048*33, nullb, 2048);
201231200Smm	}
202231200Smm	for (i = 2048*34; i < 2048*38; i += 2048) {
203231200Smm		assertEqualMem(buff+i, nullb, 2048);
204231200Smm	}
205231200Smm
206231200Smm	/*
207231200Smm	 * Read ISO image.
208231200Smm	 */
209231200Smm	assert((a = archive_read_new()) != NULL);
210231200Smm	assertEqualIntA(a, 0, archive_read_support_format_all(a));
211231200Smm	assertEqualIntA(a, 0, archive_read_support_filter_all(a));
212231200Smm	assertEqualIntA(a, 0, archive_read_open_memory(a, buff, used));
213231200Smm
214231200Smm	/*
215231200Smm	 * Read Root Directory
216231200Smm	 * Root Directory entry must be in ISO image.
217231200Smm	 */
218231200Smm	assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
219231200Smm	assertEqualInt(archive_entry_atime(ae), archive_entry_ctime(ae));
220231200Smm	assertEqualInt(archive_entry_atime(ae), archive_entry_mtime(ae));
221231200Smm	assertEqualString(".", archive_entry_pathname(ae));
222231200Smm	assert((S_IFDIR | 0555) == archive_entry_mode(ae));
223231200Smm	assertEqualInt(2048, archive_entry_size(ae));
224231200Smm
225231200Smm	/*
226231200Smm	 * Read "boot.catalog".
227231200Smm	 */
228231200Smm	assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
229231200Smm	assertEqualString("boot.catalog", archive_entry_pathname(ae));
230231200Smm#if !defined(_WIN32) && !defined(__CYGWIN__)
231231200Smm	assert((S_IFREG | 0444) == archive_entry_mode(ae));
232231200Smm#else
233231200Smm	/* On Windows and CYGWIN, always set all exec bit ON by default. */
234231200Smm	assert((S_IFREG | 0555) == archive_entry_mode(ae));
235231200Smm#endif
236231200Smm	assertEqualInt(1, archive_entry_nlink(ae));
237231200Smm	assertEqualInt(2*1024, archive_entry_size(ae));
238231200Smm	assertEqualIntA(a, 1024, archive_read_data(a, buff2, 1024));
239231200Smm	assertEqualMem(buff2, boot_catalog, 64);
240231200Smm
241231200Smm	/*
242231200Smm	 * Read "boot.img".
243231200Smm	 */
244231200Smm	assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
245231200Smm	assertEqualInt(2, archive_entry_atime(ae));
246231200Smm	assertEqualInt(3, archive_entry_birthtime(ae));
247231200Smm	assertEqualInt(4, archive_entry_ctime(ae));
248231200Smm	assertEqualInt(5, archive_entry_mtime(ae));
249231200Smm	assertEqualString("boot.img", archive_entry_pathname(ae));
250231200Smm	assert((S_IFREG | 0555) == archive_entry_mode(ae));
251231200Smm	assertEqualInt(1, archive_entry_nlink(ae));
252231200Smm	assertEqualInt(10*1024, archive_entry_size(ae));
253231200Smm	assertEqualIntA(a, 1024, archive_read_data(a, buff2, 1024));
254231200Smm	if (write_info_tbl) {
255231200Smm		assertEqualMem(buff2, nullb, 8);
256231200Smm		assertEqualMem(buff2+8, info_table, 56);
257231200Smm		assertEqualMem(buff2+64, nullb, 1024-64);
258231200Smm	} else
259231200Smm		assertEqualMem(buff2, nullb, 1024);
260231200Smm
261231200Smm	/*
262231200Smm	 * Verify the end of the archive.
263231200Smm	 */
264231200Smm	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
265231200Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
266231200Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
267231200Smm
268231200Smm	free(buff);
269231200Smm}
270231200Smm
271231200SmmDEFINE_TEST(test_write_format_iso9660_boot)
272231200Smm{
273231200Smm	_test_write_format_iso9660_boot(0);
274231200Smm	/* Use 'boot-info-table' option. */
275231200Smm	_test_write_format_iso9660_boot(1);
276231200Smm}
277