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_ACL_H
30248590Smm#include <sys/acl.h>
31248590Smm#endif
32248590Smm#ifdef HAVE_SYS_XATTR_H
33248590Smm#include <sys/xattr.h>
34248590Smm#endif
35248590Smm
36248590Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\
37248590Smm	&& defined(HAVE_ZLIB_H)
38299529Smm
39299529Smm//
40299529Smm// The test ACL used here is sometimes assigned to the 'Guest' user
41299529Smm// This changes the text and breaks the test.  This function simply
42299529Smm// strips the 'Guest' information from the string to help ensure
43299529Smm// consistent results on different machines.
44299529Smm//
45299529Smmstatic char _acl_temp[256];
46299529Smmstatic const char *
47299529Smmclean_acl(const char *acl) {
48299529Smm	char *p, *q;
49299529Smm	if (strlen(acl) >= sizeof(_acl_temp))
50299529Smm		return acl;
51299529Smm
52299529Smm	strcpy(_acl_temp, acl);
53299529Smm	p = strstr(_acl_temp, ":Guest:");
54299529Smm	if (p != NULL) {
55299529Smm		fprintf(stderr, "Shortening: %s\n", p + 1);
56299529Smm		memmove(p + 1, p + 6, strlen(p + 6) + 1);
57299529Smm		q = strstr(p + 2, ":");
58299529Smm		fprintf(stderr, "Shortening: %s\n", q);
59299529Smm		memmove(p + 2, q, strlen(q) + 1);
60299529Smm		return _acl_temp;
61299529Smm	}
62299529Smm	return _acl_temp;
63299529Smm}
64299529Smm
65248590Smmstatic int
66248590Smmhas_xattr(const char *filename, const char *xattrname)
67248590Smm{
68248590Smm	char *nl, *nlp;
69248590Smm	ssize_t r;
70370535Sgit2svn	int existing;
71248590Smm
72248590Smm	r = listxattr(filename, NULL, 0, XATTR_SHOWCOMPRESSION);
73248590Smm	if (r < 0)
74248590Smm		return (0);
75248590Smm	if (r == 0)
76248590Smm		return (0);
77248590Smm
78299529Smm	assert((nl = malloc(r)) != NULL);
79299529Smm	if (nl == NULL)
80248590Smm		return (0);
81248590Smm
82248590Smm	r = listxattr(filename, nl, r, XATTR_SHOWCOMPRESSION);
83248590Smm	if (r < 0) {
84248590Smm		free(nl);
85248590Smm		return (0);
86248590Smm	}
87248590Smm
88370535Sgit2svn	existing = 0;
89248590Smm	for (nlp = nl; nlp < nl + r; nlp += strlen(nlp) + 1) {
90248590Smm		if (strcmp(nlp, xattrname) == 0) {
91370535Sgit2svn			existing = 1;
92248590Smm			break;
93248590Smm		}
94248590Smm	}
95248590Smm	free(nl);
96370535Sgit2svn	return (existing);
97248590Smm}
98248590Smm
99248590Smm#endif
100248590Smm
101248590Smm/*
102248590Smm * Exercise HFS+ Compression.
103248590Smm */
104248590SmmDEFINE_TEST(test_write_disk_appledouble)
105248590Smm{
106248590Smm#if !defined(__APPLE__) || !defined(UF_COMPRESSED) || !defined(HAVE_SYS_XATTR_H)\
107248590Smm	|| !defined(HAVE_ZLIB_H)
108248590Smm	skipping("MacOS-specific AppleDouble test");
109248590Smm#else
110248590Smm	const char *refname = "test_write_disk_appledouble.cpio.gz";
111248590Smm	struct archive *ad, *a;
112248590Smm	struct archive_entry *ae;
113248590Smm	struct stat st;
114248590Smm	acl_t acl;
115248590Smm
116248590Smm	extract_reference_file(refname);
117248590Smm
118248590Smm	/*
119248590Smm	 * Extract an archive to disk with HFS+ Compression.
120248590Smm	 */
121248590Smm	assert((ad = archive_write_disk_new()) != NULL);
122248590Smm	assertEqualIntA(ad, ARCHIVE_OK,
123248590Smm	    archive_write_disk_set_standard_lookup(ad));
124248590Smm	assertEqualIntA(ad, ARCHIVE_OK,
125248590Smm	    archive_write_disk_set_options(ad,
126248590Smm		ARCHIVE_EXTRACT_TIME |
127248590Smm		ARCHIVE_EXTRACT_SECURE_SYMLINKS |
128248590Smm		ARCHIVE_EXTRACT_SECURE_NODOTDOT |
129248590Smm		ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED));
130248590Smm
131248590Smm	assert((a = archive_read_new()) != NULL);
132248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
133248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
134248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a,
135248590Smm	    refname, 512 * 20));
136248590Smm
137248590Smm	assertMakeDir("hfscmp", 0755);
138248590Smm	assertChdir("hfscmp");
139248590Smm
140248590Smm	/* Skip "." */
141248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
142248590Smm	assertEqualString(".", archive_entry_pathname(ae));
143248590Smm	/* Extract file3. */
144248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
145248590Smm	assertEqualString("./file3", archive_entry_pathname(ae));
146248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
147311041Smm	/* Extract ._file3 which will be merged into file3 as metadata. */
148248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
149248590Smm	assertEqualString("./._file3", archive_entry_pathname(ae));
150248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
151248590Smm
152248590Smm	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
153248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
154248590Smm	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
155248590Smm	assertEqualIntA(ad, ARCHIVE_OK, archive_write_free(ad));
156248590Smm
157248590Smm	/* Test file3. */
158248590Smm	assertEqualInt(0, stat("file3", &st));
159248590Smm	assertEqualInt(UF_COMPRESSED, st.st_flags & UF_COMPRESSED);
160248590Smm	assertFileSize("file3", 8);
161248590Smm	failure("'%s' should not have Resource Fork", "file3");
162248590Smm	assertEqualInt(0, has_xattr("file3", "com.apple.ResourceFork"));
163248590Smm	failure("'%s' should have decompfs xattr", "file3");
164248590Smm	assertEqualInt(1, has_xattr("file3", "com.apple.decmpfs"));
165248590Smm	assert(NULL != (acl = acl_get_file("file3", ACL_TYPE_EXTENDED)));
166299529Smm	assertEqualString(clean_acl(acl_to_text(acl, NULL)),
167248590Smm	    "!#acl 1\n"
168299529Smm	    "user:FFFFEEEE-DDDD-CCCC-BBBB-AAAA000000C9:::deny:read\n"
169248590Smm	    "group:ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000050:admin:80:allow:write\n"
170248590Smm	);
171248590Smm	if (acl) acl_free(acl);
172248590Smm	/* Test ._file3. */
173248590Smm	failure("'file3' should be merged and removed");
174248590Smm	assertFileNotExists("._file3");
175248590Smm
176248590Smm	assertChdir("..");
177248590Smm
178248590Smm	/*
179248590Smm	 * Extract an archive to disk without HFS+ Compression.
180248590Smm	 */
181248590Smm	assert((ad = archive_write_disk_new()) != NULL);
182248590Smm	assertEqualIntA(ad, ARCHIVE_OK,
183248590Smm	    archive_write_disk_set_standard_lookup(ad));
184248590Smm	assertEqualIntA(ad, ARCHIVE_OK,
185248590Smm	    archive_write_disk_set_options(ad,
186248590Smm		ARCHIVE_EXTRACT_TIME |
187248590Smm		ARCHIVE_EXTRACT_SECURE_SYMLINKS |
188248590Smm		ARCHIVE_EXTRACT_SECURE_NODOTDOT));
189248590Smm
190248590Smm	assert((a = archive_read_new()) != NULL);
191248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
192248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
193248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a,
194248590Smm	    refname, 512 * 20));
195248590Smm
196248590Smm	assertMakeDir("nocmp", 0755);
197248590Smm	assertChdir("nocmp");
198248590Smm
199248590Smm	/* Skip "." */
200248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
201248590Smm	assertEqualString(".", archive_entry_pathname(ae));
202248590Smm	/* Extract file3. */
203248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
204248590Smm	assertEqualString("./file3", archive_entry_pathname(ae));
205248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
206311041Smm	/* Extract ._file3 which will be merged into file3 as metadata. */
207248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
208248590Smm	assertEqualString("./._file3", archive_entry_pathname(ae));
209248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
210248590Smm
211248590Smm	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
212248590Smm	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
213248590Smm	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
214248590Smm	assertEqualIntA(ad, ARCHIVE_OK, archive_write_free(ad));
215248590Smm
216248590Smm	/* Test file3. */
217248590Smm	assertEqualInt(0, stat("file3", &st));
218248590Smm	assertEqualInt(0, st.st_flags & UF_COMPRESSED);
219248590Smm	assertFileSize("file3", 8);
220248590Smm	failure("'%s' should not have Resource Fork", "file3");
221248590Smm	assertEqualInt(0, has_xattr("file3", "com.apple.ResourceFork"));
222248590Smm	failure("'%s' should not have decmpfs", "file3");
223248590Smm	assertEqualInt(0, has_xattr("file3", "com.apple.decmpfs"));
224248590Smm	assert(NULL != (acl = acl_get_file("file3", ACL_TYPE_EXTENDED)));
225299529Smm	assertEqualString(clean_acl(acl_to_text(acl, NULL)),
226248590Smm	    "!#acl 1\n"
227299529Smm	    "user:FFFFEEEE-DDDD-CCCC-BBBB-AAAA000000C9:::deny:read\n"
228248590Smm	    "group:ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000050:admin:80:allow:write\n"
229248590Smm	);
230248590Smm	if (acl) acl_free(acl);
231248590Smm	/* Test ._file3. */
232248590Smm	failure("'file3' should be merged and removed");
233248590Smm	assertFileNotExists("._file3");
234248590Smm
235248590Smm	assertChdir("..");
236248590Smm
237248590Smm	assertEqualFile("hfscmp/file3", "nocmp/file3");
238248590Smm#endif
239248590Smm}
240