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 HAVE_POSIX_ACL || HAVE_NFS4_ACL
30 #define _ACL_PRIVATE
31 #include <sys/acl.h>
32 #if HAVE_DARWIN_ACL
33 #include <membership.h>
34 #endif
35 #endif
36 
37 #if HAVE_NFS4_ACL
38 struct myacl_t {
39 	int type;
40 	int permset;
41 	int tag;
42 	int qual; /* GID or UID of user/group, depending on tag. */
43 	const char *name; /* Name of user/group, depending on tag. */
44 };
45 
46 static struct myacl_t acls_reg[] = {
47 #if !HAVE_DARWIN_ACL
48 	/* For this test, we need the file owner to be able to read and write the ACL. */
49 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
50 	  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,
51 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
52 #endif
53 	/* An entry for each type. */
54 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
55 	  ARCHIVE_ENTRY_ACL_USER, 108, "user108" },
56 	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
57 	  ARCHIVE_ENTRY_ACL_USER, 109, "user109" },
58 
59 	/* An entry for each permission. */
60 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
61 	  ARCHIVE_ENTRY_ACL_USER, 112, "user112" },
62 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA,
63 	  ARCHIVE_ENTRY_ACL_USER, 113, "user113" },
64 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_DATA,
65 	  ARCHIVE_ENTRY_ACL_USER, 115, "user115" },
66 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_APPEND_DATA,
67 	  ARCHIVE_ENTRY_ACL_USER, 117, "user117" },
68 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS,
69 	  ARCHIVE_ENTRY_ACL_USER, 119, "user119" },
70 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS,
71 	  ARCHIVE_ENTRY_ACL_USER, 120, "user120" },
72 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
73 	  ARCHIVE_ENTRY_ACL_USER, 122, "user122" },
74 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES,
75 	  ARCHIVE_ENTRY_ACL_USER, 123, "user123" },
76 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE,
77 	  ARCHIVE_ENTRY_ACL_USER, 124, "user124" },
78 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
79 	  ARCHIVE_ENTRY_ACL_USER, 125, "user125" },
80 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL,
81 	  ARCHIVE_ENTRY_ACL_USER, 126, "user126" },
82 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER,
83 	  ARCHIVE_ENTRY_ACL_USER, 127, "user127" },
84 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
85 	  ARCHIVE_ENTRY_ACL_USER, 128, "user128" },
86 
87 	/* One entry for each qualifier. */
88 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
89 	  ARCHIVE_ENTRY_ACL_USER, 135, "user135" },
90 //	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
91 //	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
92 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
93 	  ARCHIVE_ENTRY_ACL_GROUP, 136, "group136" },
94 #if !HAVE_DARWIN_ACL
95 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
96 	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
97 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
98 	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
99 #else	/* MacOS - mode 0654 */
100 	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
101 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
102 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
103 	    ARCHIVE_ENTRY_ACL_READ_DATA |
104 	    ARCHIVE_ENTRY_ACL_WRITE_DATA |
105 	    ARCHIVE_ENTRY_ACL_APPEND_DATA |
106 	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
107 	    ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
108 	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
109 	    ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
110 	    ARCHIVE_ENTRY_ACL_READ_ACL |
111 	    ARCHIVE_ENTRY_ACL_WRITE_ACL |
112 	    ARCHIVE_ENTRY_ACL_WRITE_OWNER |
113 	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
114 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
115 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
116 	    ARCHIVE_ENTRY_ACL_READ_DATA |
117 	    ARCHIVE_ENTRY_ACL_EXECUTE |
118 	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
119 	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
120 	    ARCHIVE_ENTRY_ACL_READ_ACL |
121 	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
122 	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
123 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
124 	    ARCHIVE_ENTRY_ACL_READ_DATA |
125 	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
126 	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
127 	    ARCHIVE_ENTRY_ACL_READ_ACL |
128 	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
129 	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
130 #endif
131 };
132 
133 static const int acls_reg_cnt = (int)(sizeof(acls_reg)/sizeof(acls_reg[0]));
134 
135 static struct myacl_t acls_dir[] = {
136 	/* For this test, we need to be able to read and write the ACL. */
137 #if !HAVE_DARWIN_ACL
138 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL,
139 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
140 #endif
141 
142 	/* An entry for each type. */
143 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
144 	  ARCHIVE_ENTRY_ACL_USER, 101, "user101" },
145 	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
146 	  ARCHIVE_ENTRY_ACL_USER, 102, "user102" },
147 
148 	/* An entry for each permission. */
149 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
150 	  ARCHIVE_ENTRY_ACL_USER, 201, "user201" },
151 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_FILE,
152 	  ARCHIVE_ENTRY_ACL_USER, 202, "user202" },
153 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY,
154 	  ARCHIVE_ENTRY_ACL_USER, 203, "user203" },
155 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS,
156 	  ARCHIVE_ENTRY_ACL_USER, 204, "user204" },
157 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS,
158 	  ARCHIVE_ENTRY_ACL_USER, 205, "user205" },
159 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE_CHILD,
160 	  ARCHIVE_ENTRY_ACL_USER, 206, "user206" },
161 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
162 	  ARCHIVE_ENTRY_ACL_USER, 207, "user207" },
163 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES,
164 	  ARCHIVE_ENTRY_ACL_USER, 208, "user208" },
165 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE,
166 	  ARCHIVE_ENTRY_ACL_USER, 209, "user209" },
167 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
168 	  ARCHIVE_ENTRY_ACL_USER, 210, "user210" },
169 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL,
170 	  ARCHIVE_ENTRY_ACL_USER, 211, "user211" },
171 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER,
172 	  ARCHIVE_ENTRY_ACL_USER, 212, "user212" },
173 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
174 	  ARCHIVE_ENTRY_ACL_USER, 213, "user213" },
175 
176 	/* One entry with each inheritance value. */
177 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
178 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT,
179 	  ARCHIVE_ENTRY_ACL_USER, 301, "user301" },
180 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
181 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT,
182 	  ARCHIVE_ENTRY_ACL_USER, 302, "user302" },
183 #if 0
184 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
185 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT,
186 	  ARCHIVE_ENTRY_ACL_USER, 303, "user303" },
187 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
188 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY,
189 	  ARCHIVE_ENTRY_ACL_USER, 304, "user304" },
190 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
191 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED,
192 	  ARCHIVE_ENTRY_ACL_USER, 305, "user305" },
193 #endif
194 
195 #if 0
196 	/* FreeBSD does not support audit entries. */
197 	{ ARCHIVE_ENTRY_ACL_TYPE_AUDIT,
198 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS,
199 	  ARCHIVE_ENTRY_ACL_USER, 401, "user401" },
200 	{ ARCHIVE_ENTRY_ACL_TYPE_AUDIT,
201 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS,
202 	  ARCHIVE_ENTRY_ACL_USER, 402, "user402" },
203 #endif
204 
205 	/* One entry for each qualifier. */
206 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
207 	  ARCHIVE_ENTRY_ACL_USER, 501, "user501" },
208 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
209 	  ARCHIVE_ENTRY_ACL_GROUP, 502, "group502" },
210 #if !HAVE_DARWIN_ACL
211 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
212 	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
213 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
214 	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
215 #else	/* MacOS - mode 0654 */
216 	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
217 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
218 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
219 	    ARCHIVE_ENTRY_ACL_READ_DATA |
220 	    ARCHIVE_ENTRY_ACL_WRITE_DATA |
221 	    ARCHIVE_ENTRY_ACL_APPEND_DATA |
222 	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
223 	    ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
224 	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
225 	    ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
226 	    ARCHIVE_ENTRY_ACL_READ_ACL |
227 	    ARCHIVE_ENTRY_ACL_WRITE_ACL |
228 	    ARCHIVE_ENTRY_ACL_WRITE_OWNER |
229 	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
230 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
231 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
232 	    ARCHIVE_ENTRY_ACL_READ_DATA |
233 	    ARCHIVE_ENTRY_ACL_EXECUTE |
234 	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
235 	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
236 	    ARCHIVE_ENTRY_ACL_READ_ACL |
237 	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
238 	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
239 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
240 	    ARCHIVE_ENTRY_ACL_READ_DATA |
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_EVERYONE, -1, "" }
246 #endif
247 };
248 
249 static const int acls_dir_cnt = (int)(sizeof(acls_dir)/sizeof(acls_dir[0]));
250 
251 static void
252 set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end)
253 {
254 	int i;
255 
256 	archive_entry_acl_clear(ae);
257 #if !HAVE_DARWIN_ACL
258 	if (start > 0) {
259 		assertEqualInt(ARCHIVE_OK,
260 			archive_entry_acl_add_entry(ae,
261 			    acls[0].type, acls[0].permset, acls[0].tag,
262 			    acls[0].qual, acls[0].name));
263 	}
264 #endif
265 	for (i = start; i < end; i++) {
266 		assertEqualInt(ARCHIVE_OK,
267 		    archive_entry_acl_add_entry(ae,
268 			acls[i].type, acls[i].permset, acls[i].tag,
269 			acls[i].qual, acls[i].name));
270 	}
271 }
272 
273 static int
274 #ifdef HAVE_SUN_NFS4_ACL
275 acl_permset_to_bitmap(uint32_t a_access_mask)
276 #else
277 acl_permset_to_bitmap(acl_permset_t opaque_ps)
278 #endif
279 {
280 	static struct { int machine; int portable; } perms[] = {
281 #ifdef HAVE_SUN_NFS4_ACL	/* Solaris NFSv4 ACL permissions */
282 		{ACE_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
283 		{ACE_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
284 		{ACE_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
285 		{ACE_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
286 		{ACE_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
287 		{ACE_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
288 		{ACE_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
289 		{ACE_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
290 		{ACE_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
291 		{ACE_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
292 		{ACE_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
293 		{ACE_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
294 		{ACE_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
295 		{ACE_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL},
296 		{ACE_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL},
297 		{ACE_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
298 		{ACE_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}
299 #elif HAVE_DARWIN_ACL	/* MacOS NFSv4 ACL permissions */
300 		{ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
301 		{ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
302 		{ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
303 		{ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
304 		{ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
305 		{ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
306 		{ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
307 		{ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
308 		{ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
309 		{ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
310 		{ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
311 		{ACL_READ_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
312 		{ACL_WRITE_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
313 		{ACL_READ_SECURITY, ARCHIVE_ENTRY_ACL_READ_ACL},
314 		{ACL_WRITE_SECURITY, ARCHIVE_ENTRY_ACL_WRITE_ACL},
315 		{ACL_CHANGE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
316 #if HAVE_DECL_ACL_SYNCHRONIZE
317 		{ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE},
318 #endif
319 #else	/* FreeBSD NFSv4 ACL permissions */
320 		{ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
321 		{ACL_WRITE, ARCHIVE_ENTRY_ACL_WRITE},
322 		{ACL_READ, ARCHIVE_ENTRY_ACL_READ},
323 		{ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
324 		{ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
325 		{ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
326 		{ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
327 		{ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
328 		{ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
329 		{ACL_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
330 		{ACL_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
331 		{ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
332 		{ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
333 		{ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
334 		{ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
335 		{ACL_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL},
336 		{ACL_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL},
337 		{ACL_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
338 		{ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}
339 #endif
340 	};
341 	int i, permset = 0;
342 
343 	for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
344 #if HAVE_SUN_NFS4_ACL
345 		if (a_access_mask & perms[i].machine)
346 #else
347 		if (acl_get_perm_np(opaque_ps, perms[i].machine))
348 #endif
349 			permset |= perms[i].portable;
350 	return permset;
351 }
352 
353 static int
354 #if HAVE_SUN_NFS4_ACL
355 acl_flagset_to_bitmap(uint16_t a_flags)
356 #else
357 acl_flagset_to_bitmap(acl_flagset_t opaque_fs)
358 #endif
359 {
360 	static struct { int machine; int portable; } flags[] = {
361 #if HAVE_SUN_NFS4_ACL	/* Solaris NFSv4 ACL inheritance flags */
362 		{ACE_FILE_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
363 		{ACE_DIRECTORY_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
364 		{ACE_NO_PROPAGATE_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
365 		{ACE_INHERIT_ONLY_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY},
366 		{ACE_SUCCESSFUL_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS},
367 		{ACE_FAILED_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS},
368 #ifdef ACE_INHERITED_ACE
369 		{ACE_INHERITED_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED}
370 #endif
371 #elif HAVE_DARWIN_ACL	/* MacOS NFSv4 ACL inheritance flags */
372 		{ACL_ENTRY_INHERITED, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED},
373 		{ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
374 		{ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
375 		{ACL_ENTRY_LIMIT_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
376 		{ACL_ENTRY_ONLY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY}
377 #else	/* FreeBSD NFSv4 ACL inheritance flags */
378 		{ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
379 		{ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
380 		{ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
381 		{ACL_ENTRY_SUCCESSFUL_ACCESS, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS},
382 		{ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS},
383 		{ACL_ENTRY_INHERIT_ONLY, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY},
384 #endif
385 	};
386 	int i, flagset = 0;
387 
388 	for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); ++i)
389 #if HAVE_SUN_NFS4_ACL
390 		if (a_flags & flags[i].machine)
391 #else
392 		if (acl_get_flag_np(opaque_fs, flags[i].machine))
393 #endif
394 			flagset |= flags[i].portable;
395 	return flagset;
396 }
397 
398 static int
399 #if HAVE_SUN_NFS4_ACL
400 acl_match(ace_t *ace, struct myacl_t *myacl)
401 #else
402 acl_match(acl_entry_t aclent, struct myacl_t *myacl)
403 #endif
404 {
405 #if !HAVE_SUN_NFS4_ACL
406 #if HAVE_DARWIN_ACL
407 	void *q;
408 	uid_t ugid;
409 	int r, idtype;
410 #else
411 	gid_t g, *gp;
412 	uid_t u, *up;
413 	acl_entry_type_t entry_type;
414 #endif	/* !HAVE_DARWIN_ACL */
415 	acl_tag_t tag_type;
416 	acl_permset_t opaque_ps;
417 	acl_flagset_t opaque_fs;
418 #endif	/* !HAVE_SUN_NFS4_ACL */
419 	int perms;
420 
421 #if HAVE_SUN_NFS4_ACL
422 	perms = acl_permset_to_bitmap(ace->a_access_mask) | acl_flagset_to_bitmap(ace->a_flags);
423 #else
424 	acl_get_tag_type(aclent, &tag_type);
425 #if !HAVE_DARWIN_ACL
426 	acl_get_entry_type_np(aclent, &entry_type);
427 #endif
428 
429 	/* translate the silly opaque permset to a bitmap */
430 	acl_get_permset(aclent, &opaque_ps);
431 	acl_get_flagset_np(aclent, &opaque_fs);
432 	perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs);
433 #endif
434 	if (perms != myacl->permset)
435 		return (0);
436 
437 #if HAVE_SUN_NFS4_ACL
438 	switch (ace->a_type) {
439 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
440 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
441 			return (0);
442 		break;
443 	case ACE_ACCESS_DENIED_ACE_TYPE:
444 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
445 			return (0);
446 		break;
447 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
448 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_AUDIT)
449 			return (0);
450 		break;
451 	case ACE_SYSTEM_ALARM_ACE_TYPE:
452 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM)
453 			return (0);
454 		break;
455 	default:
456 		return (0);
457 	}
458 
459 	if (ace->a_flags & ACE_OWNER) {
460 		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ)
461 			return (0);
462 	} else if (ace->a_flags & ACE_GROUP) {
463 		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ)
464 			return (0);
465 	} else if (ace->a_flags & ACE_EVERYONE) {
466 		if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE)
467 			return (0);
468 	} else if (ace->a_flags & ACE_IDENTIFIER_GROUP) {
469 		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
470 			return (0);
471 		if ((gid_t)myacl->qual != ace->a_who)
472 			return (0);
473 	} else {
474 		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
475 			return (0);
476 		if ((uid_t)myacl->qual != ace->a_who)
477 			return (0);
478 	}
479 #elif HAVE_DARWIN_ACL
480 	r = 0;
481 	switch (tag_type) {
482 	case ACL_EXTENDED_ALLOW:
483 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
484 			return (0);
485 		break;
486 	case ACL_EXTENDED_DENY:
487 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
488 			return (0);
489 		break;
490 	default:
491 		return (0);
492 	}
493 	q = acl_get_qualifier(aclent);
494 	if (q == NULL)
495 		return (0);
496 	r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
497 	acl_free(q);
498 	if (r != 0)
499 		return (0);
500 	switch (idtype) {
501 		case ID_TYPE_UID:
502 			if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
503 				return (0);
504 			if ((uid_t)myacl->qual != ugid)
505 				return (0);
506 			break;
507 		case ID_TYPE_GID:
508 			if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
509 				return (0);
510 			if ((gid_t)myacl->qual != ugid)
511 				return (0);
512 			break;
513 		default:
514 			return (0);
515 	}
516 #else	/* !HAVE_SUN_NFS4_ACL && !HAVE_DARWIN_ACL */
517 	switch (entry_type) {
518 	case ACL_ENTRY_TYPE_ALLOW:
519 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
520 			return (0);
521 		break;
522 	case ACL_ENTRY_TYPE_DENY:
523 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
524 			return (0);
525 		break;
526 	case ACL_ENTRY_TYPE_AUDIT:
527 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_AUDIT)
528 			return (0);
529 	case ACL_ENTRY_TYPE_ALARM:
530 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM)
531 			return (0);
532 	default:
533 		return (0);
534 	}
535 
536 	switch (tag_type) {
537 	case ACL_USER_OBJ:
538 		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0);
539 		break;
540 	case ACL_USER:
541 		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
542 			return (0);
543 		up = acl_get_qualifier(aclent);
544 		u = *up;
545 		acl_free(up);
546 		if ((uid_t)myacl->qual != u)
547 			return (0);
548 		break;
549 	case ACL_GROUP_OBJ:
550 		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0);
551 		break;
552 	case ACL_GROUP:
553 		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
554 			return (0);
555 		gp = acl_get_qualifier(aclent);
556 		g = *gp;
557 		acl_free(gp);
558 		if ((gid_t)myacl->qual != g)
559 			return (0);
560 		break;
561 	case ACL_MASK:
562 		if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0);
563 		break;
564 	case ACL_EVERYONE:
565 		if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0);
566 		break;
567 	}
568 #endif	/* !HAVE_SUN_NFS4_ACL && !HAVE_DARWIN_ACL */
569 	return (1);
570 }
571 
572 static void
573 compare_acls(
574 #if HAVE_SUN_NFS4_ACL
575     void *aclp,
576     int aclcnt,
577 #else
578     acl_t acl,
579 #endif
580     struct myacl_t *myacls, const char *filename, int start, int end)
581 {
582 	int *marker;
583 	int matched;
584 	int i, n;
585 #if HAVE_SUN_NFS4_ACL
586 	int e;
587 	ace_t *acl_entry;
588 #else
589 	int entry_id = ACL_FIRST_ENTRY;
590 	acl_entry_t acl_entry;
591 #endif
592 
593 	n = end - start;
594 	marker = malloc(sizeof(marker[0]) * (n + 1));
595 	for (i = 0; i < n; i++)
596 		marker[i] = i + start;
597 #if !HAVE_DARWIN_ACL
598 	/* Always include the first ACE. */
599 	if (start > 0) {
600 	  marker[n] = 0;
601 	  ++n;
602 	}
603 #endif
604 
605 	/*
606 	 * Iterate over acls in system acl object, try to match each
607 	 * one with an item in the myacls array.
608 	 */
609 #if HAVE_SUN_NFS4_ACL
610 	for (e = 0; e < aclcnt; e++)
611 #elif HAVE_DARWIN_ACL
612 	while (0 == acl_get_entry(acl, entry_id, &acl_entry))
613 #else
614 	while (1 == acl_get_entry(acl, entry_id, &acl_entry))
615 #endif
616 	{
617 #if HAVE_SUN_NFS4_ACL
618 		acl_entry = &((ace_t *)aclp)[e];
619 #else
620 		/* After the first time... */
621 		entry_id = ACL_NEXT_ENTRY;
622 #endif
623 		/* Search for a matching entry (tag and qualifier) */
624 		for (i = 0, matched = 0; i < n && !matched; i++) {
625 			if (acl_match(acl_entry, &myacls[marker[i]])) {
626 				/* We found a match; remove it. */
627 				marker[i] = marker[n - 1];
628 				n--;
629 				matched = 1;
630 			}
631 		}
632 
633 		failure("ACL entry on file %s that shouldn't be there",
634 		    filename);
635 		assert(matched == 1);
636 	}
637 
638 	/* Dump entries in the myacls array that weren't in the system acl. */
639 	for (i = 0; i < n; ++i) {
640 		failure(" ACL entry %d missing from %s: "
641 		    "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
642 		    marker[i], filename,
643 		    myacls[marker[i]].type, myacls[marker[i]].permset,
644 		    myacls[marker[i]].tag, myacls[marker[i]].qual,
645 		    myacls[marker[i]].name);
646 		assert(0); /* Record this as a failure. */
647 	}
648 	free(marker);
649 }
650 
651 static void
652 compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char *filename, int start, int end)
653 {
654 	int *marker;
655 	int matched;
656 	int i, n;
657 	int type, permset, tag, qual;
658 	const char *name;
659 
660 	/* Count ACL entries in myacls array and allocate an indirect array. */
661 	n = end - start;
662 	marker = malloc(sizeof(marker[0]) * (n + 1));
663 	for (i = 0; i < n; i++)
664 		marker[i] = i + start;
665 	/* Always include the first ACE. */
666 	if (start > 0) {
667 	  marker[n] = 0;
668 	  ++n;
669 	}
670 
671 	/*
672 	 * Iterate over acls in entry, try to match each
673 	 * one with an item in the myacls array.
674 	 */
675 	assertEqualInt(n, archive_entry_acl_reset(ae,
676 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
677 	while (ARCHIVE_OK == archive_entry_acl_next(ae,
678 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, &type, &permset, &tag, &qual, &name)) {
679 
680 		/* Search for a matching entry (tag and qualifier) */
681 		for (i = 0, matched = 0; i < n && !matched; i++) {
682 			if (tag == myacls[marker[i]].tag
683 			    && qual == myacls[marker[i]].qual
684 			    && permset == myacls[marker[i]].permset
685 			    && type == myacls[marker[i]].type) {
686 				/* We found a match; remove it. */
687 				marker[i] = marker[n - 1];
688 				n--;
689 				matched = 1;
690 			}
691 		}
692 
693 		failure("ACL entry on file that shouldn't be there: "
694 			"type=%#010x,permset=%#010x,tag=%d,qual=%d",
695 			type,permset,tag,qual);
696 		assert(matched == 1);
697 	}
698 
699 	/* Dump entries in the myacls array that weren't in the system acl. */
700 	for (i = 0; i < n; ++i) {
701 		failure(" ACL entry %d missing from %s: "
702 		    "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
703 		    marker[i], filename,
704 		    myacls[marker[i]].type, myacls[marker[i]].permset,
705 		    myacls[marker[i]].tag, myacls[marker[i]].qual,
706 		    myacls[marker[i]].name);
707 		assert(0); /* Record this as a failure. */
708 	}
709 	free(marker);
710 }
711 #endif	/* HAVE_NFS4_ACL */
712 
713 /*
714  * Verify ACL restore-to-disk.  This test is Platform-specific.
715  */
716 
717 DEFINE_TEST(test_acl_platform_nfs4)
718 {
719 #if !HAVE_NFS4_ACL
720 	skipping("NFS4 ACLs are not supported on this platform");
721 #else
722 	char buff[64];
723 	int i;
724 	struct stat st;
725 	struct archive *a;
726 	struct archive_entry *ae;
727 #if HAVE_DARWIN_ACL /* On MacOS we skip trivial ACLs in some tests */
728 	const int regcnt = acls_reg_cnt - 4;
729 	const int dircnt = acls_dir_cnt - 4;
730 #else
731 	const int regcnt = acls_reg_cnt;
732 	const int dircnt = acls_dir_cnt;
733 #endif
734 #if HAVE_SUN_NFS4_ACL
735 	void *aclp;
736 	int aclcnt;
737 #else	/* !HAVE_SUN_NFS4_ACL */
738 	acl_t acl;
739 #endif
740 
741 	assertMakeFile("pretest", 0644, "a");
742 
743 	if (setTestAcl("pretest") != ARCHIVE_TEST_ACL_TYPE_NFS4) {
744 		skipping("NFS4 ACLs are not writable on this filesystem");
745 		return;
746 	}
747 
748 	/* Create a write-to-disk object. */
749 	assert(NULL != (a = archive_write_disk_new()));
750 	archive_write_disk_set_options(a,
751 	    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL);
752 
753 	/* Populate an archive entry with some metadata, including ACL info */
754 	ae = archive_entry_new();
755 	assert(ae != NULL);
756 	archive_entry_set_pathname(ae, "testall");
757 	archive_entry_set_filetype(ae, AE_IFREG);
758 	archive_entry_set_perm(ae, 0654);
759 	archive_entry_set_mtime(ae, 123456, 7890);
760 	archive_entry_set_size(ae, 0);
761 	set_acls(ae, acls_reg, 0, acls_reg_cnt);
762 
763 	/* Write the entry to disk, including ACLs. */
764 	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
765 
766 	/* Likewise for a dir. */
767 	archive_entry_set_pathname(ae, "dirall");
768 	archive_entry_set_filetype(ae, AE_IFDIR);
769 	archive_entry_set_perm(ae, 0654);
770 	archive_entry_set_mtime(ae, 123456, 7890);
771 	set_acls(ae, acls_dir, 0, acls_dir_cnt);
772 	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
773 
774 	for (i = 0; i < acls_dir_cnt; ++i) {
775 	  sprintf(buff, "dir%d", i);
776 	  archive_entry_set_pathname(ae, buff);
777 	  archive_entry_set_filetype(ae, AE_IFDIR);
778 	  archive_entry_set_perm(ae, 0654);
779 	  archive_entry_set_mtime(ae, 123456 + i, 7891 + i);
780 	  set_acls(ae, acls_dir, i, i + 1);
781 	  assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
782 	}
783 
784 	archive_entry_free(ae);
785 
786 	/* Close the archive. */
787 	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
788 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
789 
790 	/* Verify the data on disk. */
791 	assertEqualInt(0, stat("testall", &st));
792 	assertEqualInt(st.st_mtime, 123456);
793 #if HAVE_SUN_NFS4_ACL
794 	aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "testall");
795 	failure("acl(): errno = %d (%s)", errno, strerror(errno));
796 	assert(aclp != NULL);
797 #else
798 #if HAVE_DARWIN_ACL
799 	acl = acl_get_file("testall", ACL_TYPE_EXTENDED);
800 #else
801 	acl = acl_get_file("testall", ACL_TYPE_NFS4);
802 #endif
803 	failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
804 	assert(acl != (acl_t)NULL);
805 #endif
806 #if HAVE_SUN_NFS4_ACL
807 	compare_acls(aclp, aclcnt, acls_reg, "testall", 0, regcnt);
808 	free(aclp);
809 	aclp = NULL;
810 #else
811 	compare_acls(acl, acls_reg, "testall", 0, regcnt);
812 	acl_free(acl);
813 #endif
814 
815 
816 	/* Verify single-permission dirs on disk. */
817 	for (i = 0; i < dircnt; ++i) {
818 		sprintf(buff, "dir%d", i);
819 		assertEqualInt(0, stat(buff, &st));
820 		assertEqualInt(st.st_mtime, 123456 + i);
821 #if HAVE_SUN_NFS4_ACL
822 		aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, buff);
823 		failure("acl(): errno = %d (%s)", errno, strerror(errno));
824 		assert(aclp != NULL);
825 #else
826 #if HAVE_DARWIN_ACL
827 		acl = acl_get_file(buff, ACL_TYPE_EXTENDED);
828 #else
829 		acl = acl_get_file(buff, ACL_TYPE_NFS4);
830 #endif
831 		failure("acl_get_file(): errno = %d (%s)", errno,
832 		    strerror(errno));
833 		assert(acl != (acl_t)NULL);
834 #endif
835 #if HAVE_SUN_NFS4_ACL
836 		compare_acls(aclp, aclcnt, acls_dir, buff, i, i + 1);
837 		free(aclp);
838 		aclp = NULL;
839 #else
840 		compare_acls(acl, acls_dir, buff, i, i + 1);
841 		acl_free(acl);
842 #endif
843 	}
844 
845 	/* Verify "dirall" on disk. */
846 	assertEqualInt(0, stat("dirall", &st));
847 	assertEqualInt(st.st_mtime, 123456);
848 #if HAVE_SUN_NFS4_ACL
849 	aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "dirall");
850 	failure("acl(): errno = %d (%s)", errno, strerror(errno));
851 	assert(aclp != NULL);
852 #else
853 #if HAVE_DARWIN_ACL
854 	acl = acl_get_file("dirall", ACL_TYPE_EXTENDED);
855 #else
856 	acl = acl_get_file("dirall", ACL_TYPE_NFS4);
857 #endif
858 	failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
859 	assert(acl != (acl_t)NULL);
860 #endif
861 #if HAVE_SUN_NFS4_ACL
862 	compare_acls(aclp, aclcnt, acls_dir, "dirall", 0, dircnt);
863 	free(aclp);
864 	aclp = NULL;
865 #else
866 	compare_acls(acl, acls_dir, "dirall", 0, dircnt);
867 	acl_free(acl);
868 #endif
869 
870 	/* Read and compare ACL via archive_read_disk */
871 	a = archive_read_disk_new();
872 	assert(a != NULL);
873 	ae = archive_entry_new();
874 	assert(ae != NULL);
875 	archive_entry_set_pathname(ae, "testall");
876 	assertEqualInt(ARCHIVE_OK,
877 		       archive_read_disk_entry_from_file(a, ae, -1, NULL));
878 	compare_entry_acls(ae, acls_reg, "testall", 0, acls_reg_cnt);
879 	archive_entry_free(ae);
880 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
881 
882 	/* Read and compare ACL via archive_read_disk */
883 	a = archive_read_disk_new();
884 	assert(a != NULL);
885 	ae = archive_entry_new();
886 	assert(ae != NULL);
887 	archive_entry_set_pathname(ae, "dirall");
888 	assertEqualInt(ARCHIVE_OK,
889 	archive_read_disk_entry_from_file(a, ae, -1, NULL));
890 	compare_entry_acls(ae, acls_dir, "dirall", 0, acls_dir_cnt);
891 	archive_entry_free(ae);
892 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
893 #endif /* HAVE_NFS4_ACL */
894 }
895