1248590Smm/*-
2248590Smm * Copyright (c) 2003-2007 Tim Kientzle
3248590Smm * Copyright (c) 2012 Michihiro NAKAJIMA
4248590Smm * All rights reserved.
5248590Smm *
6248590Smm * Redistribution and use in source and binary forms, with or without
7248590Smm * modification, are permitted provided that the following conditions
8248590Smm * are met:
9248590Smm * 1. Redistributions of source code must retain the above copyright
10248590Smm *    notice, this list of conditions and the following disclaimer.
11248590Smm * 2. Redistributions in binary form must reproduce the above copyright
12248590Smm *    notice, this list of conditions and the following disclaimer in the
13248590Smm *    documentation and/or other materials provided with the distribution.
14248590Smm *
15248590Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16248590Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17248590Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18248590Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19248590Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20248590Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21248590Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22248590Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23248590Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24248590Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25248590Smm */
26248590Smm#include "test.h"
27248590Smm__FBSDID("$FreeBSD$");
28248590Smm
29248590Smm#ifdef HAVE_SYS_XATTR_H
30248590Smm#include <sys/xattr.h>
31248590Smm#endif
32248590Smm
33248590Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\
34248590Smm	&& defined(HAVE_ZLIB_H)
35248590Smmstatic int
36248590Smmhas_xattr(const char *filename, const char *xattrname)
37248590Smm{
38248590Smm	char *nl, *nlp;
39248590Smm	ssize_t r;
40248590Smm	int exisiting;
41248590Smm
42248590Smm	r = listxattr(filename, NULL, 0, XATTR_SHOWCOMPRESSION);
43248590Smm	if (r < 0)
44248590Smm		return (0);
45248590Smm	if (r == 0)
46248590Smm		return (0);
47248590Smm
48248590Smm	nl = malloc(r);
49248590Smm	if (!assert(nl != NULL))
50248590Smm		return (0);
51248590Smm
52248590Smm	r = listxattr(filename, nl, r, XATTR_SHOWCOMPRESSION);
53248590Smm	if (r < 0) {
54248590Smm		free(nl);
55248590Smm		return (0);
56248590Smm	}
57248590Smm
58248590Smm	exisiting = 0;
59248590Smm	for (nlp = nl; nlp < nl + r; nlp += strlen(nlp) + 1) {
60248590Smm		if (strcmp(nlp, xattrname) == 0) {
61248590Smm			exisiting = 1;
62248590Smm			break;
63248590Smm		}
64248590Smm	}
65248590Smm	free(nl);
66248590Smm	return (exisiting);
67248590Smm}
68248590Smmstatic int
69248590Smmget_rsrc_footer(const char *filename, char *buff, size_t s)
70248590Smm{
71248590Smm	ssize_t r;
72248590Smm
73248590Smm	r = getxattr(filename, "com.apple.ResourceFork", NULL, 0, 0,
74248590Smm	    XATTR_SHOWCOMPRESSION);
75248590Smm	if (r < (ssize_t)s)
76248590Smm		return (-1);
77248590Smm	r = getxattr(filename, "com.apple.ResourceFork", buff, s,
78248590Smm	    r - s, XATTR_SHOWCOMPRESSION);
79248590Smm	if (r < (ssize_t)s)
80248590Smm		return (-1);
81248590Smm	return (0);
82248590Smm}
83248590Smm
84248590Smm#endif
85248590Smm
86248590Smm/*
87248590Smm * Exercise HFS+ Compression.
88248590Smm */
89248590SmmDEFINE_TEST(test_write_disk_hfs_compression)
90248590Smm{
91248590Smm#if !defined(__APPLE__) || !defined(UF_COMPRESSED) || !defined(HAVE_SYS_XATTR_H)\
92248590Smm	|| !defined(HAVE_ZLIB_H)
93248590Smm	skipping("MacOS-specific HFS+ Compression test");
94248590Smm#else
95248590Smm	const char *refname = "test_write_disk_hfs_compression.tgz";
96248590Smm	struct archive *ad, *a;
97248590Smm	struct archive_entry *ae;
98248590Smm	struct stat st;
99248590Smm	char rsrc[50];
100248590Smm	static const char rsrc_footer[50] = {
101248590Smm		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102248590Smm		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103248590Smm		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104248590Smm		0x00, 0x1c, 0x00, 0x32, 0x00, 0x00, 'c',  'm',
105248590Smm		'p', 'f',   0x00, 0x00, 0x00, 0x0a, 0x00, 0x01,
106248590Smm		0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107248590Smm		0x00, 0x00
108248590Smm	};
109248590Smm
110248590Smm	extract_reference_file(refname);
111248590Smm
112248590Smm	/*
113248590Smm	 * Extract an archive to disk with HFS+ Compression.
114248590Smm	 */
115248590Smm	assert((ad = archive_write_disk_new()) != NULL);
116248590Smm	assertEqualIntA(ad, ARCHIVE_OK,
117248590Smm	    archive_write_disk_set_standard_lookup(ad));
118248590Smm	assertEqualIntA(ad, ARCHIVE_OK,
119248590Smm	    archive_write_disk_set_options(ad,
120248590Smm		ARCHIVE_EXTRACT_TIME |
121248590Smm		ARCHIVE_EXTRACT_SECURE_SYMLINKS |
122248590Smm		ARCHIVE_EXTRACT_SECURE_NODOTDOT |
123248590Smm		ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED));
124248590Smm
125248590Smm	assert((a = archive_read_new()) != NULL);
126248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
127248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
128248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a,
129248590Smm	    refname, 512 * 20));
130248590Smm
131248590Smm	assertMakeDir("hfscmp", 0755);
132248590Smm	assertChdir("hfscmp");
133248590Smm
134248590Smm	/* Extract file1. */
135248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
136248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
137248590Smm	/* Extract README. */
138248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
139248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
140248590Smm	/* Extract NEWS. */
141248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
142248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
143248590Smm	/* Extract Makefile. */
144248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
145248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
146248590Smm
147248590Smm	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
148248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
149248590Smm	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
150248590Smm	assertEqualIntA(ad, ARCHIVE_OK, archive_write_free(ad));
151248590Smm
152248590Smm	/* Test file1. */
153248590Smm	assertEqualInt(0, stat("file1", &st));
154248590Smm	assertEqualInt(UF_COMPRESSED, st.st_flags & UF_COMPRESSED);
155248590Smm	assertFileSize("file1", 8);
156248590Smm	failure("'%s' should not have Resource Fork", "file1");
157248590Smm	assertEqualInt(0, has_xattr("file1", "com.apple.ResourceFork"));
158248590Smm	failure("'%s' should have decompfs xattr", "file1");
159248590Smm	assertEqualInt(1, has_xattr("file1", "com.apple.decmpfs"));
160248590Smm
161248590Smm	/* Test README. */
162248590Smm	assertEqualInt(0, stat("README", &st));
163248590Smm	assertEqualInt(UF_COMPRESSED, st.st_flags & UF_COMPRESSED);
164248590Smm	assertFileSize("README", 6586);
165248590Smm	failure("'%s' should not have Resource Fork", "README");
166248590Smm	assertEqualInt(0, has_xattr("README", "com.apple.ResourceFork"));
167248590Smm	failure("'%s' should have decompfs xattr", "README");
168248590Smm	assertEqualInt(1, has_xattr("README", "com.apple.decmpfs"));
169248590Smm
170248590Smm	/* Test NEWS. */
171248590Smm	assertEqualInt(0, stat("NEWS", &st));
172248590Smm	assertEqualInt(UF_COMPRESSED, st.st_flags & UF_COMPRESSED);
173248590Smm	assertFileSize("NEWS", 28438);
174248590Smm	failure("'%s' should have Resource Fork", "NEWS");
175248590Smm	assertEqualInt(1, has_xattr("NEWS", "com.apple.ResourceFork"));
176248590Smm	failure("'%s' should have decompfs xattr", "NEWS");
177248590Smm	assertEqualInt(1, has_xattr("NEWS", "com.apple.decmpfs"));
178248590Smm	assertEqualInt(0, get_rsrc_footer("NEWS", rsrc, sizeof(rsrc)));
179248590Smm	failure("Resource Fork should have consistent 50 bytes data");
180248590Smm	assertEqualMem(rsrc_footer, rsrc, sizeof(rsrc));
181248590Smm
182248590Smm	/* Test Makefile. */
183248590Smm	assertEqualInt(0, stat("Makefile", &st));
184248590Smm	assertEqualInt(UF_COMPRESSED, st.st_flags & UF_COMPRESSED);
185248590Smm	assertFileSize("Makefile", 1264000);
186248590Smm	failure("'%s' should have Resource Fork", "Makefile");
187248590Smm	assertEqualInt(1, has_xattr("Makefile", "com.apple.ResourceFork"));
188248590Smm	failure("'%s' should have decompfs xattr", "Makefile");
189248590Smm	assertEqualInt(1, has_xattr("Makefile", "com.apple.decmpfs"));
190248590Smm	assertEqualInt(0, get_rsrc_footer("Makefile", rsrc, sizeof(rsrc)));
191248590Smm	failure("Resource Fork should have consistent 50 bytes data");
192248590Smm	assertEqualMem(rsrc_footer, rsrc, sizeof(rsrc));
193248590Smm
194248590Smm	assertChdir("..");
195248590Smm
196248590Smm	/*
197248590Smm	 * Extract an archive to disk without HFS+ Compression.
198248590Smm	 */
199248590Smm	assert((ad = archive_write_disk_new()) != NULL);
200248590Smm	assertEqualIntA(ad, ARCHIVE_OK,
201248590Smm	    archive_write_disk_set_standard_lookup(ad));
202248590Smm	assertEqualIntA(ad, ARCHIVE_OK,
203248590Smm	    archive_write_disk_set_options(ad,
204248590Smm		ARCHIVE_EXTRACT_TIME |
205248590Smm		ARCHIVE_EXTRACT_SECURE_SYMLINKS |
206248590Smm		ARCHIVE_EXTRACT_SECURE_NODOTDOT));
207248590Smm
208248590Smm	assert((a = archive_read_new()) != NULL);
209248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
210248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
211248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a,
212248590Smm	    refname, 512 * 20));
213248590Smm
214248590Smm	assertMakeDir("nocmp", 0755);
215248590Smm	assertChdir("nocmp");
216248590Smm
217248590Smm	/* Extract file1. */
218248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
219248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
220248590Smm	/* Extract README. */
221248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
222248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
223248590Smm	/* Extract NEWS. */
224248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
225248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
226248590Smm	/* Extract Makefile. */
227248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
228248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
229248590Smm
230248590Smm	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
231248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
232248590Smm	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
233248590Smm	assertEqualIntA(ad, ARCHIVE_OK, archive_write_free(ad));
234248590Smm
235248590Smm	/* Test file1. */
236248590Smm	assertEqualInt(0, stat("file1", &st));
237248590Smm	assertEqualInt(0, st.st_flags & UF_COMPRESSED);
238248590Smm	assertFileSize("file1", 8);
239248590Smm	failure("'%s' should not have Resource Fork", "file1");
240248590Smm	assertEqualInt(0, has_xattr("file1", "com.apple.ResourceFork"));
241248590Smm	failure("'%s' should not have decmpfs", "file1");
242248590Smm	assertEqualInt(0, has_xattr("file1", "com.apple.decmpfs"));
243248590Smm
244248590Smm	/* Test README. */
245248590Smm	assertEqualInt(0, stat("README", &st));
246248590Smm	assertEqualInt(0, st.st_flags & UF_COMPRESSED);
247248590Smm	assertFileSize("README", 6586);
248248590Smm	failure("'%s' should not have Resource Fork", "README");
249248590Smm	assertEqualInt(0, has_xattr("README", "com.apple.ResourceFork"));
250248590Smm	failure("'%s' should not have decmpfs", "README");
251248590Smm	assertEqualInt(0, has_xattr("README", "com.apple.decmpfs"));
252248590Smm
253248590Smm	/* Test NEWS. */
254248590Smm	assertEqualInt(0, stat("NEWS", &st));
255248590Smm	assertEqualInt(0, st.st_flags & UF_COMPRESSED);
256248590Smm	assertFileSize("NEWS", 28438);
257248590Smm	failure("'%s' should not have Resource Fork", "NEWS");
258248590Smm	assertEqualInt(0, has_xattr("NEWS", "com.apple.ResourceFork"));
259248590Smm	failure("'%s' should not have decmpfs", "NEWS");
260248590Smm	assertEqualInt(0, has_xattr("NEWS", "com.apple.decmpfs"));
261248590Smm
262248590Smm	/* Test Makefile. */
263248590Smm	assertEqualInt(0, stat("Makefile", &st));
264248590Smm	assertEqualInt(0, st.st_flags & UF_COMPRESSED);
265248590Smm	assertFileSize("Makefile", 1264000);
266248590Smm	failure("'%s' should not have Resource Fork", "Makefile");
267248590Smm	assertEqualInt(0, has_xattr("Makefile", "com.apple.ResourceFork"));
268248590Smm	failure("'%s' should not have decmpfs", "Makefile");
269248590Smm	assertEqualInt(0, has_xattr("Makefile", "com.apple.decmpfs"));
270248590Smm
271248590Smm	assertChdir("..");
272248590Smm
273248590Smm	assertEqualFile("hfscmp/file1", "nocmp/file1");
274248590Smm	assertEqualFile("hfscmp/README", "nocmp/README");
275248590Smm	assertEqualFile("hfscmp/NEWS", "nocmp/NEWS");
276248590Smm	assertEqualFile("hfscmp/Makefile", "nocmp/Makefile");
277248590Smm#endif
278248590Smm}
279