test_acl_platform_nfs4.c revision 328828
1/*-
2 * Copyright (c) 2003-2010 Tim Kientzle
3 * Copyright (c) 2017 Martin Matuska
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26#include "test.h"
27__FBSDID("$FreeBSD$");
28
29#if ARCHIVE_ACL_NFS4
30#if HAVE_SYS_ACL_H
31#define _ACL_PRIVATE
32#include <sys/acl.h>
33#endif
34#if HAVE_SYS_RICHACL_H
35#include <sys/richacl.h>
36#endif
37#if HAVE_MEMBERSHIP_H
38#include <membership.h>
39#endif
40
41struct myacl_t {
42	int type;
43	int permset;
44	int tag;
45	int qual; /* GID or UID of user/group, depending on tag. */
46	const char *name; /* Name of user/group, depending on tag. */
47};
48
49static struct myacl_t acls_reg[] = {
50#if !ARCHIVE_ACL_DARWIN
51	/* For this test, we need the file owner to be able to read and write the ACL. */
52	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
53	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL | ARCHIVE_ENTRY_ACL_WRITE_ACL | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
54	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
55#endif
56	/* An entry for each type. */
57	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
58	  ARCHIVE_ENTRY_ACL_USER, 108, "user108" },
59	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
60	  ARCHIVE_ENTRY_ACL_USER, 109, "user109" },
61
62	/* An entry for each permission. */
63	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
64	  ARCHIVE_ENTRY_ACL_USER, 112, "user112" },
65	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA,
66	  ARCHIVE_ENTRY_ACL_USER, 113, "user113" },
67	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_DATA,
68	  ARCHIVE_ENTRY_ACL_USER, 115, "user115" },
69	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_APPEND_DATA,
70	  ARCHIVE_ENTRY_ACL_USER, 117, "user117" },
71	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS,
72	  ARCHIVE_ENTRY_ACL_USER, 119, "user119" },
73	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS,
74	  ARCHIVE_ENTRY_ACL_USER, 120, "user120" },
75	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
76	  ARCHIVE_ENTRY_ACL_USER, 122, "user122" },
77	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES,
78	  ARCHIVE_ENTRY_ACL_USER, 123, "user123" },
79	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE,
80	  ARCHIVE_ENTRY_ACL_USER, 124, "user124" },
81	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
82	  ARCHIVE_ENTRY_ACL_USER, 125, "user125" },
83	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL,
84	  ARCHIVE_ENTRY_ACL_USER, 126, "user126" },
85	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER,
86	  ARCHIVE_ENTRY_ACL_USER, 127, "user127" },
87	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
88	  ARCHIVE_ENTRY_ACL_USER, 128, "user128" },
89
90	/* One entry for each qualifier. */
91	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
92	  ARCHIVE_ENTRY_ACL_USER, 135, "user135" },
93//	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
94//	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
95	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
96	  ARCHIVE_ENTRY_ACL_GROUP, 136, "group136" },
97#if !ARCHIVE_ACL_DARWIN
98	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
99	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
100	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
101	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
102#else	/* MacOS - mode 0654 */
103	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
104	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
105	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
106	    ARCHIVE_ENTRY_ACL_READ_DATA |
107	    ARCHIVE_ENTRY_ACL_WRITE_DATA |
108	    ARCHIVE_ENTRY_ACL_APPEND_DATA |
109	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
110	    ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
111	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
112	    ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
113	    ARCHIVE_ENTRY_ACL_READ_ACL |
114	    ARCHIVE_ENTRY_ACL_WRITE_ACL |
115	    ARCHIVE_ENTRY_ACL_WRITE_OWNER |
116	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
117	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
118	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
119	    ARCHIVE_ENTRY_ACL_READ_DATA |
120	    ARCHIVE_ENTRY_ACL_EXECUTE |
121	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
122	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
123	    ARCHIVE_ENTRY_ACL_READ_ACL |
124	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
125	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
126	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
127	    ARCHIVE_ENTRY_ACL_READ_DATA |
128	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
129	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
130	    ARCHIVE_ENTRY_ACL_READ_ACL |
131	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
132	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
133#endif
134};
135
136static const int acls_reg_cnt = (int)(sizeof(acls_reg)/sizeof(acls_reg[0]));
137
138static struct myacl_t acls_dir[] = {
139	/* For this test, we need to be able to read and write the ACL. */
140#if !ARCHIVE_ACL_DARWIN
141	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL,
142	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
143#endif
144
145	/* An entry for each type. */
146	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
147	  ARCHIVE_ENTRY_ACL_USER, 101, "user101" },
148	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
149	  ARCHIVE_ENTRY_ACL_USER, 102, "user102" },
150
151	/* An entry for each permission. */
152	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
153	  ARCHIVE_ENTRY_ACL_USER, 201, "user201" },
154	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_FILE,
155	  ARCHIVE_ENTRY_ACL_USER, 202, "user202" },
156	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY,
157	  ARCHIVE_ENTRY_ACL_USER, 203, "user203" },
158	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS,
159	  ARCHIVE_ENTRY_ACL_USER, 204, "user204" },
160	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS,
161	  ARCHIVE_ENTRY_ACL_USER, 205, "user205" },
162	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE_CHILD,
163	  ARCHIVE_ENTRY_ACL_USER, 206, "user206" },
164	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
165	  ARCHIVE_ENTRY_ACL_USER, 207, "user207" },
166	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES,
167	  ARCHIVE_ENTRY_ACL_USER, 208, "user208" },
168	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE,
169	  ARCHIVE_ENTRY_ACL_USER, 209, "user209" },
170	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
171	  ARCHIVE_ENTRY_ACL_USER, 210, "user210" },
172	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL,
173	  ARCHIVE_ENTRY_ACL_USER, 211, "user211" },
174	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER,
175	  ARCHIVE_ENTRY_ACL_USER, 212, "user212" },
176	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
177	  ARCHIVE_ENTRY_ACL_USER, 213, "user213" },
178
179	/* One entry with each inheritance value. */
180	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
181	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT,
182	  ARCHIVE_ENTRY_ACL_USER, 301, "user301" },
183	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
184	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT,
185	  ARCHIVE_ENTRY_ACL_USER, 302, "user302" },
186	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
187	  ARCHIVE_ENTRY_ACL_READ_DATA |
188	  ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT |
189	  ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT,
190	  ARCHIVE_ENTRY_ACL_USER, 303, "user303" },
191	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
192	  ARCHIVE_ENTRY_ACL_READ_DATA |
193	  ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT |
194	  ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY,
195	  ARCHIVE_ENTRY_ACL_USER, 304, "user304" },
196#if !defined(ARCHIVE_ACL_SUNOS_NFS4) || defined(ACE_INHERITED_ACE)
197	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
198	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED,
199	  ARCHIVE_ENTRY_ACL_USER, 305, "user305" },
200#endif
201
202#if 0
203	/* FreeBSD does not support audit entries. */
204	{ ARCHIVE_ENTRY_ACL_TYPE_AUDIT,
205	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS,
206	  ARCHIVE_ENTRY_ACL_USER, 401, "user401" },
207	{ ARCHIVE_ENTRY_ACL_TYPE_AUDIT,
208	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS,
209	  ARCHIVE_ENTRY_ACL_USER, 402, "user402" },
210#endif
211
212	/* One entry for each qualifier. */
213	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
214	  ARCHIVE_ENTRY_ACL_USER, 501, "user501" },
215	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
216	  ARCHIVE_ENTRY_ACL_GROUP, 502, "group502" },
217#if !ARCHIVE_ACL_DARWIN
218	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
219	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
220	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
221	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
222#else	/* MacOS - mode 0654 */
223	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
224	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
225	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
226	    ARCHIVE_ENTRY_ACL_READ_DATA |
227	    ARCHIVE_ENTRY_ACL_WRITE_DATA |
228	    ARCHIVE_ENTRY_ACL_APPEND_DATA |
229	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
230	    ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
231	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
232	    ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
233	    ARCHIVE_ENTRY_ACL_READ_ACL |
234	    ARCHIVE_ENTRY_ACL_WRITE_ACL |
235	    ARCHIVE_ENTRY_ACL_WRITE_OWNER |
236	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
237	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
238	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
239	    ARCHIVE_ENTRY_ACL_READ_DATA |
240	    ARCHIVE_ENTRY_ACL_EXECUTE |
241	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
242	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
243	    ARCHIVE_ENTRY_ACL_READ_ACL |
244	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
245	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
246	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
247	    ARCHIVE_ENTRY_ACL_READ_DATA |
248	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
249	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
250	    ARCHIVE_ENTRY_ACL_READ_ACL |
251	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
252	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
253#endif
254};
255
256static const int acls_dir_cnt = (int)(sizeof(acls_dir)/sizeof(acls_dir[0]));
257
258static void
259set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end)
260{
261	int i;
262
263	archive_entry_acl_clear(ae);
264#if !ARCHIVE_ACL_DARWIN
265	if (start > 0) {
266		assertEqualInt(ARCHIVE_OK,
267			archive_entry_acl_add_entry(ae,
268			    acls[0].type, acls[0].permset, acls[0].tag,
269			    acls[0].qual, acls[0].name));
270	}
271#endif
272	for (i = start; i < end; i++) {
273		assertEqualInt(ARCHIVE_OK,
274		    archive_entry_acl_add_entry(ae,
275			acls[i].type, acls[i].permset, acls[i].tag,
276			acls[i].qual, acls[i].name));
277	}
278}
279
280static int
281#if ARCHIVE_ACL_SUNOS_NFS4
282acl_permset_to_bitmap(uint32_t mask)
283#elif ARCHIVE_ACL_LIBRICHACL
284acl_permset_to_bitmap(unsigned int mask)
285#else
286acl_permset_to_bitmap(acl_permset_t opaque_ps)
287#endif
288{
289	static struct { int portable; int machine; } perms[] = {
290#ifdef ARCHIVE_ACL_SUNOS_NFS4	/* Solaris NFSv4 ACL permissions */
291		{ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},
292		{ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},
293		{ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},
294		{ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
295		{ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
296		{ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
297		{ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
298		{ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
299		{ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
300		{ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
301		{ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
302		{ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
303		{ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
304		{ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
305		{ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
306		{ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
307		{ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
308#elif ARCHIVE_ACL_DARWIN	/* MacOS NFSv4 ACL permissions */
309		{ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
310		{ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
311		{ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
312		{ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
313		{ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
314		{ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
315		{ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
316		{ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
317		{ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
318		{ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
319		{ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
320		{ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
321		{ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
322		{ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
323		{ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
324		{ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
325#if HAVE_DECL_ACL_SYNCHRONIZE
326		{ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
327#endif
328#elif ARCHIVE_ACL_LIBRICHACL
329		{ARCHIVE_ENTRY_ACL_EXECUTE, RICHACE_EXECUTE},
330		{ARCHIVE_ENTRY_ACL_READ_DATA, RICHACE_READ_DATA},
331		{ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, RICHACE_LIST_DIRECTORY},
332		{ARCHIVE_ENTRY_ACL_WRITE_DATA, RICHACE_WRITE_DATA},
333		{ARCHIVE_ENTRY_ACL_ADD_FILE, RICHACE_ADD_FILE},
334		{ARCHIVE_ENTRY_ACL_APPEND_DATA, RICHACE_APPEND_DATA},
335		{ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, RICHACE_ADD_SUBDIRECTORY},
336		{ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, RICHACE_READ_NAMED_ATTRS},
337		{ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, RICHACE_WRITE_NAMED_ATTRS},
338		{ARCHIVE_ENTRY_ACL_DELETE_CHILD, RICHACE_DELETE_CHILD},
339		{ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, RICHACE_READ_ATTRIBUTES},
340		{ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, RICHACE_WRITE_ATTRIBUTES},
341		{ARCHIVE_ENTRY_ACL_DELETE, RICHACE_DELETE},
342		{ARCHIVE_ENTRY_ACL_READ_ACL, RICHACE_READ_ACL},
343		{ARCHIVE_ENTRY_ACL_WRITE_ACL, RICHACE_WRITE_ACL},
344		{ARCHIVE_ENTRY_ACL_WRITE_OWNER, RICHACE_WRITE_OWNER},
345		{ARCHIVE_ENTRY_ACL_SYNCHRONIZE, RICHACE_SYNCHRONIZE}
346#else	/* FreeBSD NFSv4 ACL permissions */
347		{ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
348		{ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
349		{ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
350		{ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
351		{ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
352		{ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
353		{ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
354		{ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
355		{ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
356		{ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
357		{ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
358		{ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
359		{ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
360		{ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
361		{ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
362		{ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
363		{ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
364#endif
365	};
366	int i, permset = 0;
367
368	for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
369#if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
370		if (mask & perms[i].machine)
371#else
372		if (acl_get_perm_np(opaque_ps, perms[i].machine))
373#endif
374			permset |= perms[i].portable;
375	return permset;
376}
377
378static int
379#if ARCHIVE_ACL_SUNOS_NFS4
380acl_flagset_to_bitmap(uint16_t flags)
381#elif ARCHIVE_ACL_LIBRICHACL
382acl_flagset_to_bitmap(int flags)
383#else
384acl_flagset_to_bitmap(acl_flagset_t opaque_fs)
385#endif
386{
387	static struct { int portable; int machine; } perms[] = {
388#if ARCHIVE_ACL_SUNOS_NFS4	/* Solaris NFSv4 ACL inheritance flags */
389		{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},
390		{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},
391		{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},
392		{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},
393		{ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
394		{ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},
395#ifdef ACE_INHERITED_ACE
396		{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
397#endif
398#elif ARCHIVE_ACL_DARWIN	/* MacOS NFSv4 ACL inheritance flags */
399		{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
400		{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
401		{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
402		{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
403		{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
404#elif ARCHIVE_ACL_LIBRICHACL
405		{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, RICHACE_FILE_INHERIT_ACE},
406		{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, RICHACE_DIRECTORY_INHERIT_ACE},
407		{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, RICHACE_NO_PROPAGATE_INHERIT_ACE},
408		{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, RICHACE_INHERIT_ONLY_ACE},
409		{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, RICHACE_INHERITED_ACE}
410#else	/* FreeBSD NFSv4 ACL inheritance flags */
411#ifdef ACL_ENTRY_INHERITED
412		{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
413#endif
414		{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
415		{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
416		{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
417		{ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
418		{ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
419		{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
420#endif
421	};
422	int i, flagset = 0;
423
424	for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
425#if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
426		if (flags & perms[i].machine)
427#else
428		if (acl_get_flag_np(opaque_fs, perms[i].machine))
429#endif
430			flagset |= perms[i].portable;
431	return flagset;
432}
433
434#if ARCHIVE_ACL_SUNOS_NFS4
435static int
436acl_match(ace_t *ace, struct myacl_t *myacl)
437{
438	int perms;
439
440	perms = acl_permset_to_bitmap(ace->a_access_mask) | acl_flagset_to_bitmap(ace->a_flags);
441
442	if (perms != myacl->permset)
443		return (0);
444
445	switch (ace->a_type) {
446	case ACE_ACCESS_ALLOWED_ACE_TYPE:
447		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
448			return (0);
449		break;
450	case ACE_ACCESS_DENIED_ACE_TYPE:
451		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
452			return (0);
453		break;
454	case ACE_SYSTEM_AUDIT_ACE_TYPE:
455		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_AUDIT)
456			return (0);
457		break;
458	case ACE_SYSTEM_ALARM_ACE_TYPE:
459		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM)
460			return (0);
461		break;
462	default:
463		return (0);
464	}
465
466	if (ace->a_flags & ACE_OWNER) {
467		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ)
468			return (0);
469	} else if (ace->a_flags & ACE_GROUP) {
470		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ)
471			return (0);
472	} else if (ace->a_flags & ACE_EVERYONE) {
473		if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE)
474			return (0);
475	} else if (ace->a_flags & ACE_IDENTIFIER_GROUP) {
476		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
477			return (0);
478		if ((gid_t)myacl->qual != ace->a_who)
479			return (0);
480	} else {
481		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
482			return (0);
483		if ((uid_t)myacl->qual != ace->a_who)
484			return (0);
485	}
486	return (1);
487}
488#elif ARCHIVE_ACL_LIBRICHACL
489static int
490acl_match(struct richace *richace, struct myacl_t *myacl)
491{
492	int perms;
493
494	perms = acl_permset_to_bitmap(richace->e_mask) |
495	    acl_flagset_to_bitmap(richace->e_flags);
496
497	if (perms != myacl->permset)
498		return (0);
499
500	switch (richace->e_type) {
501	case RICHACE_ACCESS_ALLOWED_ACE_TYPE:
502		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
503			return (0);
504		break;
505	case RICHACE_ACCESS_DENIED_ACE_TYPE:
506		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
507			return (0);
508		break;
509	default:
510		return (0);
511	}
512
513	if (richace->e_flags & RICHACE_SPECIAL_WHO) {
514		switch (richace->e_id) {
515		case RICHACE_OWNER_SPECIAL_ID:
516			if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ)
517				return (0);
518			break;
519		case RICHACE_GROUP_SPECIAL_ID:
520			if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ)
521				return (0);
522			break;
523		case RICHACE_EVERYONE_SPECIAL_ID:
524			if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE)
525				return (0);
526			break;
527		default:
528			/* Invalid e_id */
529			return (0);
530		}
531	} else if (richace->e_flags & RICHACE_IDENTIFIER_GROUP) {
532		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
533			return (0);
534		if ((gid_t)myacl->qual != richace->e_id)
535			return (0);
536	} else {
537		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
538			return (0);
539		if ((uid_t)myacl->qual != richace->e_id)
540			return (0);
541	}
542	return (1);
543}
544#elif ARCHIVE_ACL_DARWIN
545static int
546acl_match(acl_entry_t aclent, struct myacl_t *myacl)
547{
548	void *q;
549	uid_t ugid;
550	int r, idtype;
551	acl_tag_t tag_type;
552	acl_permset_t opaque_ps;
553	acl_flagset_t opaque_fs;
554	int perms;
555
556	acl_get_tag_type(aclent, &tag_type);
557
558	/* translate the silly opaque permset to a bitmap */
559	acl_get_permset(aclent, &opaque_ps);
560	acl_get_flagset_np(aclent, &opaque_fs);
561	perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs);
562	if (perms != myacl->permset)
563		return (0);
564
565	r = 0;
566	switch (tag_type) {
567	case ACL_EXTENDED_ALLOW:
568		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
569			return (0);
570		break;
571	case ACL_EXTENDED_DENY:
572		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
573			return (0);
574		break;
575	default:
576		return (0);
577	}
578	q = acl_get_qualifier(aclent);
579	if (q == NULL)
580		return (0);
581	r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
582	acl_free(q);
583	if (r != 0)
584		return (0);
585	switch (idtype) {
586		case ID_TYPE_UID:
587			if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
588				return (0);
589			if ((uid_t)myacl->qual != ugid)
590				return (0);
591			break;
592		case ID_TYPE_GID:
593			if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
594				return (0);
595			if ((gid_t)myacl->qual != ugid)
596				return (0);
597			break;
598		default:
599			return (0);
600	}
601	return (1);
602}
603#else /* ARCHIVE_ACL_FREEBSD_NFS4 */
604static int
605acl_match(acl_entry_t aclent, struct myacl_t *myacl)
606{
607	gid_t g, *gp;
608	uid_t u, *up;
609	acl_entry_type_t entry_type;
610	acl_tag_t tag_type;
611	acl_permset_t opaque_ps;
612	acl_flagset_t opaque_fs;
613	int perms;
614
615	acl_get_tag_type(aclent, &tag_type);
616	acl_get_entry_type_np(aclent, &entry_type);
617
618	/* translate the silly opaque permset to a bitmap */
619	acl_get_permset(aclent, &opaque_ps);
620	acl_get_flagset_np(aclent, &opaque_fs);
621	perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs);
622	if (perms != myacl->permset)
623		return (0);
624
625	switch (entry_type) {
626	case ACL_ENTRY_TYPE_ALLOW:
627		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
628			return (0);
629		break;
630	case ACL_ENTRY_TYPE_DENY:
631		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
632			return (0);
633		break;
634	case ACL_ENTRY_TYPE_AUDIT:
635		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_AUDIT)
636			return (0);
637	case ACL_ENTRY_TYPE_ALARM:
638		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM)
639			return (0);
640	default:
641		return (0);
642	}
643
644	switch (tag_type) {
645	case ACL_USER_OBJ:
646		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0);
647		break;
648	case ACL_USER:
649		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
650			return (0);
651		up = acl_get_qualifier(aclent);
652		u = *up;
653		acl_free(up);
654		if ((uid_t)myacl->qual != u)
655			return (0);
656		break;
657	case ACL_GROUP_OBJ:
658		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0);
659		break;
660	case ACL_GROUP:
661		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
662			return (0);
663		gp = acl_get_qualifier(aclent);
664		g = *gp;
665		acl_free(gp);
666		if ((gid_t)myacl->qual != g)
667			return (0);
668		break;
669	case ACL_MASK:
670		if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0);
671		break;
672	case ACL_EVERYONE:
673		if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0);
674		break;
675	}
676	return (1);
677}
678#endif	/* various ARCHIVE_ACL_NFS4 implementations */
679
680static void
681compare_acls(
682#if ARCHIVE_ACL_SUNOS_NFS4
683    void *aclp,
684    int aclcnt,
685#elif ARCHIVE_ACL_LIBRICHACL
686    struct richacl *richacl,
687#else
688    acl_t acl,
689#endif
690    struct myacl_t *myacls, const char *filename, int start, int end)
691{
692	int *marker;
693	int matched;
694	int i, n;
695#if ARCHIVE_ACL_SUNOS_NFS4
696	int e;
697	ace_t *acl_entry;
698#elif ARCHIVE_ACL_LIBRICHACL
699	int e;
700	struct richace *acl_entry;
701	int aclcnt;
702#else
703	int entry_id = ACL_FIRST_ENTRY;
704	acl_entry_t acl_entry;
705#if ARCHIVE_ACL_DARWIN
706	const int acl_get_entry_ret = 0;
707#else
708	const int acl_get_entry_ret = 1;
709#endif
710#endif
711
712#if ARCHIVE_ACL_SUNOS_NFS4
713	if (aclp == NULL)
714		return;
715#elif ARCHIVE_ACL_LIBRICHACL
716	if (richacl == NULL)
717		return;
718	aclcnt = richacl->a_count;
719#else
720	if (acl == NULL)
721		return;
722#endif
723
724	n = end - start;
725	marker = malloc(sizeof(marker[0]) * (n + 1));
726	for (i = 0; i < n; i++)
727		marker[i] = i + start;
728#if !ARCHIVE_ACL_DARWIN
729	/* Always include the first ACE. */
730	if (start > 0) {
731	  marker[n] = 0;
732	  ++n;
733	}
734#endif
735
736	/*
737	 * Iterate over acls in system acl object, try to match each
738	 * one with an item in the myacls array.
739	 */
740#if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
741	for (e = 0; e < aclcnt; e++)
742#else
743	while (acl_get_entry_ret == acl_get_entry(acl, entry_id, &acl_entry))
744#endif
745	{
746#if ARCHIVE_ACL_SUNOS_NFS4
747		acl_entry = &((ace_t *)aclp)[e];
748#elif ARCHIVE_ACL_LIBRICHACL
749		acl_entry = &(richacl->a_entries[e]);
750#else
751		/* After the first time... */
752		entry_id = ACL_NEXT_ENTRY;
753#endif
754		/* Search for a matching entry (tag and qualifier) */
755		for (i = 0, matched = 0; i < n && !matched; i++) {
756			if (acl_match(acl_entry, &myacls[marker[i]])) {
757				/* We found a match; remove it. */
758				marker[i] = marker[n - 1];
759				n--;
760				matched = 1;
761			}
762		}
763
764		failure("ACL entry on file %s that shouldn't be there",
765		    filename);
766		assert(matched == 1);
767	}
768
769	/* Dump entries in the myacls array that weren't in the system acl. */
770	for (i = 0; i < n; ++i) {
771		failure(" ACL entry %d missing from %s: "
772		    "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
773		    marker[i], filename,
774		    myacls[marker[i]].type, myacls[marker[i]].permset,
775		    myacls[marker[i]].tag, myacls[marker[i]].qual,
776		    myacls[marker[i]].name);
777		assert(0); /* Record this as a failure. */
778	}
779	free(marker);
780}
781
782static void
783compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char *filename, int start, int end)
784{
785	int *marker;
786	int matched;
787	int i, n;
788	int type, permset, tag, qual;
789	const char *name;
790
791	/* Count ACL entries in myacls array and allocate an indirect array. */
792	n = end - start;
793	marker = malloc(sizeof(marker[0]) * (n + 1));
794	for (i = 0; i < n; i++)
795		marker[i] = i + start;
796	/* Always include the first ACE. */
797	if (start > 0) {
798	  marker[n] = 0;
799	  ++n;
800	}
801
802	/*
803	 * Iterate over acls in entry, try to match each
804	 * one with an item in the myacls array.
805	 */
806	assertEqualInt(n, archive_entry_acl_reset(ae,
807	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
808	while (ARCHIVE_OK == archive_entry_acl_next(ae,
809	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, &type, &permset, &tag, &qual, &name)) {
810
811		/* Search for a matching entry (tag and qualifier) */
812		for (i = 0, matched = 0; i < n && !matched; i++) {
813			if (tag == myacls[marker[i]].tag
814			    && qual == myacls[marker[i]].qual
815			    && permset == myacls[marker[i]].permset
816			    && type == myacls[marker[i]].type) {
817				/* We found a match; remove it. */
818				marker[i] = marker[n - 1];
819				n--;
820				matched = 1;
821			}
822		}
823
824		failure("ACL entry on file that shouldn't be there: "
825			"type=%#010x,permset=%#010x,tag=%d,qual=%d",
826			type,permset,tag,qual);
827		assert(matched == 1);
828	}
829
830	/* Dump entries in the myacls array that weren't in the system acl. */
831	for (i = 0; i < n; ++i) {
832		failure(" ACL entry %d missing from %s: "
833		    "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
834		    marker[i], filename,
835		    myacls[marker[i]].type, myacls[marker[i]].permset,
836		    myacls[marker[i]].tag, myacls[marker[i]].qual,
837		    myacls[marker[i]].name);
838		assert(0); /* Record this as a failure. */
839	}
840	free(marker);
841}
842#endif	/* ARCHIVE_ACL_NFS4 */
843
844/*
845 * Verify ACL restore-to-disk.  This test is Platform-specific.
846 */
847
848DEFINE_TEST(test_acl_platform_nfs4)
849{
850#if !ARCHIVE_ACL_NFS4
851	skipping("NFS4 ACLs are not supported on this platform");
852#else /* ARCHIVE_ACL_NFS4 */
853	char buff[64];
854	int i;
855	struct stat st;
856	struct archive *a;
857	struct archive_entry *ae;
858#if ARCHIVE_ACL_DARWIN /* On MacOS we skip trivial ACLs in some tests */
859	const int regcnt = acls_reg_cnt - 4;
860	const int dircnt = acls_dir_cnt - 4;
861#else
862	const int regcnt = acls_reg_cnt;
863	const int dircnt = acls_dir_cnt;
864#endif
865#if ARCHIVE_ACL_SUNOS_NFS4
866	void *aclp;
867	int aclcnt;
868#elif ARCHIVE_ACL_LIBRICHACL
869	struct richacl *richacl;
870#else	/* !ARCHIVE_ACL_SUNOS_NFS4 */
871	acl_t acl;
872#endif
873
874	assertMakeFile("pretest", 0644, "a");
875
876	if (setTestAcl("pretest") != ARCHIVE_TEST_ACL_TYPE_NFS4) {
877		skipping("NFS4 ACLs are not writable on this filesystem");
878		return;
879	}
880
881	/* Create a write-to-disk object. */
882	assert(NULL != (a = archive_write_disk_new()));
883	archive_write_disk_set_options(a,
884	    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL);
885
886	/* Populate an archive entry with some metadata, including ACL info */
887	ae = archive_entry_new();
888	assert(ae != NULL);
889	archive_entry_set_pathname(ae, "testall");
890	archive_entry_set_filetype(ae, AE_IFREG);
891	archive_entry_set_perm(ae, 0654);
892	archive_entry_set_mtime(ae, 123456, 7890);
893	archive_entry_set_size(ae, 0);
894	set_acls(ae, acls_reg, 0, acls_reg_cnt);
895
896	/* Write the entry to disk, including ACLs. */
897	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
898
899	/* Likewise for a dir. */
900	archive_entry_set_pathname(ae, "dirall");
901	archive_entry_set_filetype(ae, AE_IFDIR);
902	archive_entry_set_perm(ae, 0654);
903	archive_entry_set_mtime(ae, 123456, 7890);
904	set_acls(ae, acls_dir, 0, acls_dir_cnt);
905	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
906
907	for (i = 0; i < acls_dir_cnt; ++i) {
908	  sprintf(buff, "dir%d", i);
909	  archive_entry_set_pathname(ae, buff);
910	  archive_entry_set_filetype(ae, AE_IFDIR);
911	  archive_entry_set_perm(ae, 0654);
912	  archive_entry_set_mtime(ae, 123456 + i, 7891 + i);
913	  set_acls(ae, acls_dir, i, i + 1);
914	  assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
915	}
916
917	archive_entry_free(ae);
918
919	/* Close the archive. */
920	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
921	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
922
923	/* Verify the data on disk. */
924	assertEqualInt(0, stat("testall", &st));
925	assertEqualInt(st.st_mtime, 123456);
926#if ARCHIVE_ACL_SUNOS_NFS4
927	aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "testall");
928	failure("acl(\"%s\"): errno = %d (%s)", "testall", errno,
929	    strerror(errno));
930	assert(aclp != NULL);
931#elif ARCHIVE_ACL_LIBRICHACL
932	richacl = richacl_get_file("testall");
933	failure("richacl_get_file(\"%s\"): errno = %d (%s)", "testall", errno,
934	    strerror(errno));
935	assert(richacl != NULL);
936#else
937#if ARCHIVE_ACL_DARWIN
938	acl = acl_get_file("testall", ACL_TYPE_EXTENDED);
939#else
940	acl = acl_get_file("testall", ACL_TYPE_NFS4);
941#endif
942	failure("acl_get_file(\"%s\"): errno = %d (%s)", "testall", errno,
943	    strerror(errno));
944	assert(acl != (acl_t)NULL);
945#endif
946#if ARCHIVE_ACL_SUNOS_NFS4
947	compare_acls(aclp, aclcnt, acls_reg, "testall", 0, regcnt);
948	free(aclp);
949	aclp = NULL;
950#elif ARCHIVE_ACL_LIBRICHACL
951	compare_acls(richacl, acls_reg, "testall", 0, regcnt);
952	richacl_free(richacl);
953#else
954	compare_acls(acl, acls_reg, "testall", 0, regcnt);
955	acl_free(acl);
956#endif
957
958
959	/* Verify single-permission dirs on disk. */
960	for (i = 0; i < dircnt; ++i) {
961		sprintf(buff, "dir%d", i);
962		assertEqualInt(0, stat(buff, &st));
963		assertEqualInt(st.st_mtime, 123456 + i);
964#if ARCHIVE_ACL_SUNOS_NFS4
965		aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, buff);
966		failure("acl(\"%s\"): errno = %d (%s)", buff, errno,
967		    strerror(errno));
968		assert(aclp != NULL);
969#elif ARCHIVE_ACL_LIBRICHACL
970		richacl = richacl_get_file(buff);
971		/* First and last two dir do not return a richacl */
972		if ((i == 0 || i >= dircnt - 2) && richacl == NULL &&
973		    errno == ENODATA)
974			continue;
975		failure("richacl_get_file(\"%s\"): errno = %d (%s)", buff,
976		    errno, strerror(errno));
977		assert(richacl != NULL);
978#else
979#if ARCHIVE_ACL_DARWIN
980		acl = acl_get_file(buff, ACL_TYPE_EXTENDED);
981#else
982		acl = acl_get_file(buff, ACL_TYPE_NFS4);
983#endif
984		failure("acl_get_file(\"%s\"): errno = %d (%s)", buff, errno,
985		    strerror(errno));
986		assert(acl != (acl_t)NULL);
987#endif
988#if ARCHIVE_ACL_SUNOS_NFS4
989		compare_acls(aclp, aclcnt, acls_dir, buff, i, i + 1);
990		free(aclp);
991		aclp = NULL;
992#elif ARCHIVE_ACL_LIBRICHACL
993		compare_acls(richacl, acls_dir, buff, i, i + 1);
994		richacl_free(richacl);
995#else
996		compare_acls(acl, acls_dir, buff, i, i + 1);
997		acl_free(acl);
998#endif
999	}
1000
1001	/* Verify "dirall" on disk. */
1002	assertEqualInt(0, stat("dirall", &st));
1003	assertEqualInt(st.st_mtime, 123456);
1004#if ARCHIVE_ACL_SUNOS_NFS4
1005	aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "dirall");
1006	failure("acl(\"%s\"): errno = %d (%s)", "dirall", errno,
1007	    strerror(errno));
1008	assert(aclp != NULL);
1009#elif ARCHIVE_ACL_LIBRICHACL
1010	richacl = richacl_get_file("dirall");
1011	failure("richacl_get_file(\"%s\"): errno = %d (%s)", "dirall",
1012	    errno, strerror(errno));
1013	assert(richacl != NULL);
1014#else
1015#if ARCHIVE_ACL_DARWIN
1016	acl = acl_get_file("dirall", ACL_TYPE_EXTENDED);
1017#else
1018	acl = acl_get_file("dirall", ACL_TYPE_NFS4);
1019#endif
1020	failure("acl_get_file(\"%s\"): errno = %d (%s)", "dirall", errno,
1021	    strerror(errno));
1022	assert(acl != (acl_t)NULL);
1023#endif
1024#if ARCHIVE_ACL_SUNOS_NFS4
1025	compare_acls(aclp, aclcnt, acls_dir, "dirall", 0, dircnt);
1026	free(aclp);
1027	aclp = NULL;
1028#elif ARCHIVE_ACL_LIBRICHACL
1029	compare_acls(richacl, acls_dir, "dirall", 0, dircnt);
1030	richacl_free(richacl);
1031#else
1032	compare_acls(acl, acls_dir, "dirall", 0, dircnt);
1033	acl_free(acl);
1034#endif
1035
1036	/* Read and compare ACL via archive_read_disk */
1037	a = archive_read_disk_new();
1038	assert(a != NULL);
1039	ae = archive_entry_new();
1040	assert(ae != NULL);
1041	archive_entry_set_pathname(ae, "testall");
1042	assertEqualInt(ARCHIVE_OK,
1043		       archive_read_disk_entry_from_file(a, ae, -1, NULL));
1044	compare_entry_acls(ae, acls_reg, "testall", 0, acls_reg_cnt);
1045	archive_entry_free(ae);
1046	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1047
1048	/* Read and compare ACL via archive_read_disk */
1049	a = archive_read_disk_new();
1050	assert(a != NULL);
1051	ae = archive_entry_new();
1052	assert(ae != NULL);
1053	archive_entry_set_pathname(ae, "dirall");
1054	assertEqualInt(ARCHIVE_OK,
1055	archive_read_disk_entry_from_file(a, ae, -1, NULL));
1056	compare_entry_acls(ae, acls_dir, "dirall", 0, acls_dir_cnt);
1057	archive_entry_free(ae);
1058	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1059#endif /* ARCHIVE_ACL_NFS4 */
1060}
1061