]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/test/test_acl_platform_nfs4.c
MFC r310866,310868,310870,311903,313074:
[FreeBSD/stable/10.git] / contrib / libarchive / libarchive / test / test_acl_platform_nfs4.c
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 (start > 0) {
258                 assertEqualInt(ARCHIVE_OK,
259                         archive_entry_acl_add_entry(ae,
260                             acls[0].type, acls[0].permset, acls[0].tag,
261                             acls[0].qual, acls[0].name));
262         }
263         for (i = start; i < end; i++) {
264                 assertEqualInt(ARCHIVE_OK,
265                     archive_entry_acl_add_entry(ae,
266                         acls[i].type, acls[i].permset, acls[i].tag,
267                         acls[i].qual, acls[i].name));
268         }
269 }
270
271 static int
272 #ifdef HAVE_SUN_ACL
273 acl_permset_to_bitmap(uint32_t a_access_mask)
274 #else
275 acl_permset_to_bitmap(acl_permset_t opaque_ps)
276 #endif
277 {
278         static struct { int machine; int portable; } perms[] = {
279 #ifdef HAVE_SUN_ACL     /* Solaris NFSv4 ACL permissions */
280                 {ACE_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
281                 {ACE_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
282                 {ACE_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
283                 {ACE_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
284                 {ACE_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
285                 {ACE_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
286                 {ACE_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
287                 {ACE_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
288                 {ACE_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
289                 {ACE_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
290                 {ACE_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
291                 {ACE_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
292                 {ACE_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
293                 {ACE_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL},
294                 {ACE_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL},
295                 {ACE_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
296                 {ACE_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}
297 #elif HAVE_DARWIN_ACL   /* MacOS NFSv4 ACL permissions */
298                 {ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
299                 {ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
300                 {ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
301                 {ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
302                 {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
303                 {ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
304                 {ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
305                 {ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
306                 {ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
307                 {ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
308                 {ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
309                 {ACL_READ_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
310                 {ACL_WRITE_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
311                 {ACL_READ_SECURITY, ARCHIVE_ENTRY_ACL_READ_ACL},
312                 {ACL_WRITE_SECURITY, ARCHIVE_ENTRY_ACL_WRITE_ACL},
313                 {ACL_CHANGE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
314                 {ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE},
315 #else   /* FreeBSD NFSv4 ACL permissions */
316                 {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
317                 {ACL_WRITE, ARCHIVE_ENTRY_ACL_WRITE},
318                 {ACL_READ, ARCHIVE_ENTRY_ACL_READ},
319                 {ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
320                 {ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
321                 {ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
322                 {ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
323                 {ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
324                 {ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
325                 {ACL_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
326                 {ACL_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
327                 {ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
328                 {ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
329                 {ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
330                 {ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
331                 {ACL_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL},
332                 {ACL_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL},
333                 {ACL_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
334                 {ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}
335 #endif
336         };
337         int i, permset = 0;
338
339         for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
340 #if HAVE_SUN_ACL
341                 if (a_access_mask & perms[i].machine)
342 #else
343                 if (acl_get_perm_np(opaque_ps, perms[i].machine))
344 #endif
345                         permset |= perms[i].portable;
346         return permset;
347 }
348
349 static int
350 #if HAVE_SUN_ACL
351 acl_flagset_to_bitmap(uint16_t a_flags)
352 #else
353 acl_flagset_to_bitmap(acl_flagset_t opaque_fs)
354 #endif
355 {
356         static struct { int machine; int portable; } flags[] = {
357 #if HAVE_SUN_ACL        /* Solaris NFSv4 ACL inheritance flags */
358                 {ACE_FILE_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
359                 {ACE_DIRECTORY_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
360                 {ACE_NO_PROPAGATE_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
361                 {ACE_INHERIT_ONLY_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY},
362                 {ACE_SUCCESSFUL_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS},
363                 {ACE_FAILED_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS},
364                 {ACE_INHERITED_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED}
365 #elif HAVE_DARWIN_ACL   /* MacOS NFSv4 ACL inheritance flags */
366                 {ACL_ENTRY_INHERITED, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED},
367                 {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
368                 {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
369                 {ACL_ENTRY_LIMIT_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
370                 {ACL_ENTRY_ONLY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY}
371 #else   /* FreeBSD NFSv4 ACL inheritance flags */
372                 {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
373                 {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
374                 {ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
375                 {ACL_ENTRY_SUCCESSFUL_ACCESS, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS},
376                 {ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS},
377                 {ACL_ENTRY_INHERIT_ONLY, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY},
378 #endif
379         };
380         int i, flagset = 0;
381
382         for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); ++i)
383 #if HAVE_SUN_ACL
384                 if (a_flags & flags[i].machine)
385 #else
386                 if (acl_get_flag_np(opaque_fs, flags[i].machine))
387 #endif
388                         flagset |= flags[i].portable;
389         return flagset;
390 }
391
392 static int
393 #if HAVE_SUN_ACL
394 acl_match(ace_t *ace, struct myacl_t *myacl)
395 #else
396 acl_match(acl_entry_t aclent, struct myacl_t *myacl)
397 #endif
398 {
399 #if !HAVE_SUN_ACL
400 #if HAVE_DARWIN_ACL
401         void *q;
402         uid_t ugid;
403         int r, idtype;
404 #else
405         gid_t g, *gp;
406         uid_t u, *up;
407         acl_entry_type_t entry_type;
408 #endif  /* !HAVE_DARWIN_ACL */
409         acl_tag_t tag_type;
410         acl_permset_t opaque_ps;
411         acl_flagset_t opaque_fs;
412 #endif  /* !HAVE_SUN_ACL */
413         int perms;
414
415 #if HAVE_SUN_ACL
416         perms = acl_permset_to_bitmap(ace->a_access_mask) | acl_flagset_to_bitmap(ace->a_flags);
417 #else
418         acl_get_tag_type(aclent, &tag_type);
419 #if !HAVE_DARWIN_ACL
420         acl_get_entry_type_np(aclent, &entry_type);
421 #endif
422
423         /* translate the silly opaque permset to a bitmap */
424         acl_get_permset(aclent, &opaque_ps);
425         acl_get_flagset_np(aclent, &opaque_fs);
426         perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs);
427 #endif
428         if (perms != myacl->permset)
429                 return (0);
430
431 #if HAVE_SUN_ACL
432         switch (ace->a_type) {
433         case ACE_ACCESS_ALLOWED_ACE_TYPE:
434                 if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
435                         return (0);
436                 break;
437         case ACE_ACCESS_DENIED_ACE_TYPE:
438                 if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
439                         return (0);
440                 break;
441         case ACE_SYSTEM_AUDIT_ACE_TYPE:
442                 if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_AUDIT)
443                         return (0);
444                 break;
445         case ACE_SYSTEM_ALARM_ACE_TYPE:
446                 if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM)
447                         return (0);
448                 break;
449         default:
450                 return (0);
451         }
452
453         if (ace->a_flags & ACE_OWNER) {
454                 if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ)
455                         return (0);
456         } else if (ace->a_flags & ACE_GROUP) {
457                 if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ)
458                         return (0);
459         } else if (ace->a_flags & ACE_EVERYONE) {
460                 if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE)
461                         return (0);
462         } else if (ace->a_flags & ACE_IDENTIFIER_GROUP) {
463                 if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
464                         return (0);
465                 if ((gid_t)myacl->qual != ace->a_who)
466                         return (0);
467         } else {
468                 if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
469                         return (0);
470                 if ((uid_t)myacl->qual != ace->a_who)
471                         return (0);
472         }
473 #elif HAVE_DARWIN_ACL
474         r = 0;
475         switch (tag_type) {
476         case ACL_EXTENDED_ALLOW:
477                 if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
478                         return (0);
479                 break;
480         case ACL_EXTENDED_DENY:
481                 if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
482                         return (0);
483                 break;
484         default:
485                 return (0);
486         }
487         q = acl_get_qualifier(aclent);
488         if (q == NULL)
489                 return (0);
490         r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
491         acl_free(q);
492         if (r != 0)
493                 return (0);
494         switch (idtype) {
495                 case ID_TYPE_UID:
496                         if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
497                                 return (0);
498                         if ((uid_t)myacl->qual != ugid)
499                                 return (0);
500                         break;
501                 case ID_TYPE_GID:
502                         if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
503                                 return (0);
504                         if ((gid_t)myacl->qual != ugid)
505                                 return (0);
506                         break;
507                 default:
508                         return (0);
509         }
510 #else   /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
511         switch (entry_type) {
512         case ACL_ENTRY_TYPE_ALLOW:
513                 if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
514                         return (0);
515                 break;
516         case ACL_ENTRY_TYPE_DENY:
517                 if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
518                         return (0);
519                 break;
520         case ACL_ENTRY_TYPE_AUDIT:
521                 if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_AUDIT)
522                         return (0);
523         case ACL_ENTRY_TYPE_ALARM:
524                 if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM)
525                         return (0);
526         default:
527                 return (0);
528         }
529
530         switch (tag_type) {
531         case ACL_USER_OBJ:
532                 if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0);
533                 break;
534         case ACL_USER:
535                 if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
536                         return (0);
537                 up = acl_get_qualifier(aclent);
538                 u = *up;
539                 acl_free(up);
540                 if ((uid_t)myacl->qual != u)
541                         return (0);
542                 break;
543         case ACL_GROUP_OBJ:
544                 if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0);
545                 break;
546         case ACL_GROUP:
547                 if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
548                         return (0);
549                 gp = acl_get_qualifier(aclent);
550                 g = *gp;
551                 acl_free(gp);
552                 if ((gid_t)myacl->qual != g)
553                         return (0);
554                 break;
555         case ACL_MASK:
556                 if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0);
557                 break;
558         case ACL_EVERYONE:
559                 if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0);
560                 break;
561         }
562 #endif  /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
563         return (1);
564 }
565
566 static void
567 compare_acls(
568 #if HAVE_SUN_ACL
569     acl_t *acl,
570 #else
571     acl_t acl,
572 #endif
573     struct myacl_t *myacls, const char *filename, int start, int end)
574 {
575         int *marker;
576         int matched;
577         int i, n;
578 #if HAVE_SUN_ACL
579         int e;
580         ace_t *acl_entry;
581 #else
582         int entry_id = ACL_FIRST_ENTRY;
583         acl_entry_t acl_entry;
584 #endif
585
586         n = end - start;
587         marker = malloc(sizeof(marker[0]) * (n + 1));
588         for (i = 0; i < n; i++)
589                 marker[i] = i + start;
590         /* Always include the first ACE. */
591         if (start > 0) {
592           marker[n] = 0;
593           ++n;
594         }
595
596         /*
597          * Iterate over acls in system acl object, try to match each
598          * one with an item in the myacls array.
599          */
600 #if HAVE_SUN_ACL
601         for (e = 0; e < acl->acl_cnt; e++)
602 #elif HAVE_DARWIN_ACL
603         while (0 == acl_get_entry(acl, entry_id, &acl_entry))
604 #else
605         while (1 == acl_get_entry(acl, entry_id, &acl_entry))
606 #endif
607         {
608 #if HAVE_SUN_ACL
609                 acl_entry = &((ace_t *)acl->acl_aclp)[e];
610 #else
611                 /* After the first time... */
612                 entry_id = ACL_NEXT_ENTRY;
613 #endif
614                 /* Search for a matching entry (tag and qualifier) */
615                 for (i = 0, matched = 0; i < n && !matched; i++) {
616                         if (acl_match(acl_entry, &myacls[marker[i]])) {
617                                 /* We found a match; remove it. */
618                                 marker[i] = marker[n - 1];
619                                 n--;
620                                 matched = 1;
621                         }
622                 }
623
624                 failure("ACL entry on file %s that shouldn't be there",
625                     filename);
626                 assert(matched == 1);
627         }
628
629         /* Dump entries in the myacls array that weren't in the system acl. */
630         for (i = 0; i < n; ++i) {
631                 failure(" ACL entry %d missing from %s: "
632                     "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
633                     marker[i], filename,
634                     myacls[marker[i]].type, myacls[marker[i]].permset,
635                     myacls[marker[i]].tag, myacls[marker[i]].qual,
636                     myacls[marker[i]].name);
637                 assert(0); /* Record this as a failure. */
638         }
639         free(marker);
640 }
641
642 static void
643 compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char *filename, int start, int end)
644 {
645         int *marker;
646         int matched;
647         int i, n;
648         int type, permset, tag, qual;
649         const char *name;
650
651         /* Count ACL entries in myacls array and allocate an indirect array. */
652         n = end - start;
653         marker = malloc(sizeof(marker[0]) * (n + 1));
654         for (i = 0; i < n; i++)
655                 marker[i] = i + start;
656         /* Always include the first ACE. */
657         if (start > 0) {
658           marker[n] = 0;
659           ++n;
660         }
661
662         /*
663          * Iterate over acls in entry, try to match each
664          * one with an item in the myacls array.
665          */
666         assertEqualInt(n, archive_entry_acl_reset(ae,
667             ARCHIVE_ENTRY_ACL_TYPE_NFS4));
668         while (ARCHIVE_OK == archive_entry_acl_next(ae,
669             ARCHIVE_ENTRY_ACL_TYPE_NFS4, &type, &permset, &tag, &qual, &name)) {
670
671                 /* Search for a matching entry (tag and qualifier) */
672                 for (i = 0, matched = 0; i < n && !matched; i++) {
673                         if (tag == myacls[marker[i]].tag
674                             && qual == myacls[marker[i]].qual
675                             && permset == myacls[marker[i]].permset
676                             && type == myacls[marker[i]].type) {
677                                 /* We found a match; remove it. */
678                                 marker[i] = marker[n - 1];
679                                 n--;
680                                 matched = 1;
681                         }
682                 }
683
684                 failure("ACL entry on file that shouldn't be there: "
685                         "type=%#010x,permset=%#010x,tag=%d,qual=%d",
686                         type,permset,tag,qual);
687                 assert(matched == 1);
688         }
689
690         /* Dump entries in the myacls array that weren't in the system acl. */
691         for (i = 0; i < n; ++i) {
692                 failure(" ACL entry %d missing from %s: "
693                     "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
694                     marker[i], filename,
695                     myacls[marker[i]].type, myacls[marker[i]].permset,
696                     myacls[marker[i]].tag, myacls[marker[i]].qual,
697                     myacls[marker[i]].name);
698                 assert(0); /* Record this as a failure. */
699         }
700         free(marker);
701 }
702 #endif  /* HAVE_NFS4_ACL */
703
704 /*
705  * Verify ACL restore-to-disk.  This test is Platform-specific.
706  */
707
708 DEFINE_TEST(test_acl_platform_nfs4)
709 {
710 #if !HAVE_NFS4_ACL
711         skipping("NFS4 ACLs are not supported on this platform");
712 #else
713         char buff[64];
714         struct stat st;
715         struct archive *a;
716         struct archive_entry *ae;
717         int i, n;
718         char *func;
719 #if HAVE_DARWIN_ACL /* On MacOS we skip trivial ACLs in some tests */
720         const int regcnt = acls_reg_cnt - 4;
721         const int dircnt = acls_dir_cnt - 4;
722 #else
723         const int regcnt = acls_reg_cnt;
724         const int dircnt = acls_dir_cnt;
725 #endif
726 #if HAVE_SUN_ACL
727         acl_t *acl;
728 #else   /* !HAVE_SUN_ACL */
729 #if HAVE_DARWIN_ACL
730         acl_entry_t aclent;
731         acl_permset_t permset;
732         const uid_t uid = 1000;
733         uuid_t uuid;
734 #endif  /* HAVE_DARWIN_ACL */
735         acl_t acl;
736 #endif  /* !HAVE_SUN_ACL */
737
738         /*
739          * First, do a quick manual set/read of ACL data to
740          * verify that the local filesystem does support ACLs.
741          * If it doesn't, we'll simply skip the remaining tests.
742          */
743 #if HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4
744         acl = acl_from_text("owner@:rwxp::allow,group@:rwp:f:allow");
745         failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
746         assert((void *)acl != NULL);
747 #elif HAVE_DARWIN_ACL
748         acl = acl_init(1);
749         assert((void *)acl != NULL);
750         assertEqualInt(0, acl_create_entry(&acl, &aclent));
751         assertEqualInt(0, acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW));
752         assertEqualInt(0, acl_get_permset(aclent, &permset));
753         assertEqualInt(0, acl_add_perm(permset, ACL_READ_DATA));
754         assertEqualInt(0, acl_add_perm(permset, ACL_WRITE_DATA));
755         assertEqualInt(0, acl_add_perm(permset, ACL_APPEND_DATA));
756         assertEqualInt(0, acl_add_perm(permset, ACL_EXECUTE));
757         assertEqualInt(0, acl_set_permset(aclent, permset));
758         assertEqualInt(0, mbr_identifier_to_uuid(ID_TYPE_UID, &uid,
759             sizeof(uid_t), uuid));
760         assertEqualInt(0, acl_set_qualifier(aclent, uuid));
761 #endif
762
763         /* Create a test dir and try to set an ACL on it. */
764         if (!assertMakeDir("pretest", 0755)) {
765 #if !HAVE_SUN_ACL
766                 acl_free(acl);
767 #endif
768                 return;
769         }
770
771 #if HAVE_SUN_ACL
772         func = "acl_get()";
773         n = acl_get("pretest", 0, &acl);
774 #else
775         func = "acl_set_file()";
776 #if HAVE_DARWIN_ACL
777         n = acl_set_file("pretest", ACL_TYPE_EXTENDED, acl);
778 #else
779         n = acl_set_file("pretest", ACL_TYPE_NFS4, acl);
780 #endif
781         acl_free(acl);
782 #endif
783         if (n != 0) {
784 #if HAVE_SUN_ACL
785                 if (errno == ENOSYS)
786 #else
787                 if (errno == EOPNOTSUPP || errno == EINVAL)
788 #endif
789                 {
790                         skipping("NFS4 ACL is not supported on this filesystem");
791                         return;
792                 }
793         }
794         failure("%s: errno = %d (%s)", func, errno, strerror(errno));
795         assertEqualInt(0, n);
796
797 #if HAVE_SUN_ACL
798         if (acl->acl_type != ACE_T) {
799                 acl_free(acl);
800                 skipping("NFS4 ACL is not supported on this filesystem");
801                 return;
802         }
803         acl_free(acl);
804 #endif
805
806         /* Create a write-to-disk object. */
807         assert(NULL != (a = archive_write_disk_new()));
808         archive_write_disk_set_options(a,
809             ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL);
810
811         /* Populate an archive entry with some metadata, including ACL info */
812         ae = archive_entry_new();
813         assert(ae != NULL);
814         archive_entry_set_pathname(ae, "testall");
815         archive_entry_set_filetype(ae, AE_IFREG);
816         archive_entry_set_perm(ae, 0654);
817         archive_entry_set_mtime(ae, 123456, 7890);
818         archive_entry_set_size(ae, 0);
819         set_acls(ae, acls_reg, 0, acls_reg_cnt);
820
821         /* Write the entry to disk, including ACLs. */
822         assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
823
824         /* Likewise for a dir. */
825         archive_entry_set_pathname(ae, "dirall");
826         archive_entry_set_filetype(ae, AE_IFDIR);
827         archive_entry_set_perm(ae, 0654);
828         archive_entry_set_mtime(ae, 123456, 7890);
829         set_acls(ae, acls_dir, 0, acls_dir_cnt);
830         assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
831
832         for (i = 0; i < acls_dir_cnt; ++i) {
833           sprintf(buff, "dir%d", i);
834           archive_entry_set_pathname(ae, buff);
835           archive_entry_set_filetype(ae, AE_IFDIR);
836           archive_entry_set_perm(ae, 0654);
837           archive_entry_set_mtime(ae, 123456 + i, 7891 + i);
838           set_acls(ae, acls_dir, i, i + 1);
839           assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
840         }
841
842         archive_entry_free(ae);
843
844         /* Close the archive. */
845         assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
846         assertEqualInt(ARCHIVE_OK, archive_write_free(a));
847
848         /* Verify the data on disk. */
849         assertEqualInt(0, stat("testall", &st));
850         assertEqualInt(st.st_mtime, 123456);
851 #if HAVE_SUN_ACL
852         n = acl_get("testall", 0, &acl);
853         failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
854         assertEqualInt(0, n);
855 #else
856 #if HAVE_DARWIN_ACL
857         acl = acl_get_file("testall", ACL_TYPE_EXTENDED);
858 #else
859         acl = acl_get_file("testall", ACL_TYPE_NFS4);
860 #endif
861         failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
862         assert(acl != (acl_t)NULL);
863 #endif
864         compare_acls(acl, acls_reg, "testall", 0, regcnt);
865         acl_free(acl);
866
867         /* Verify single-permission dirs on disk. */
868         for (i = 0; i < dircnt; ++i) {
869                 sprintf(buff, "dir%d", i);
870                 assertEqualInt(0, stat(buff, &st));
871                 assertEqualInt(st.st_mtime, 123456 + i);
872 #if HAVE_SUN_ACL
873                 n = acl_get(buff, 0, &acl);
874                 failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
875                 assertEqualInt(0, n);
876 #else
877 #if HAVE_DARWIN_ACL
878                 acl = acl_get_file(buff, ACL_TYPE_EXTENDED);
879 #else
880                 acl = acl_get_file(buff, ACL_TYPE_NFS4);
881 #endif
882                 failure("acl_get_file(): errno = %d (%s)", errno,
883                     strerror(errno));
884                 assert(acl != (acl_t)NULL);
885 #endif
886                 compare_acls(acl, acls_dir, buff, i, i + 1);
887                 acl_free(acl);
888         }
889
890         /* Verify "dirall" on disk. */
891         assertEqualInt(0, stat("dirall", &st));
892         assertEqualInt(st.st_mtime, 123456);
893 #if HAVE_SUN_ACL
894         n = acl_get("dirall", 0, &acl);
895         failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
896         assertEqualInt(0, n);
897 #else
898 #if HAVE_DARWIN_ACL
899         acl = acl_get_file("dirall", ACL_TYPE_EXTENDED);
900 #else
901         acl = acl_get_file("dirall", ACL_TYPE_NFS4);
902 #endif
903         failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
904         assert(acl != (acl_t)NULL);
905 #endif
906         compare_acls(acl, acls_dir, "dirall", 0, dircnt);
907         acl_free(acl);
908
909         /* Read and compare ACL via archive_read_disk */
910         a = archive_read_disk_new();
911         assert(a != NULL);
912         ae = archive_entry_new();
913         assert(ae != NULL);
914         archive_entry_set_pathname(ae, "testall");
915         assertEqualInt(ARCHIVE_OK,
916                        archive_read_disk_entry_from_file(a, ae, -1, NULL));
917         compare_entry_acls(ae, acls_reg, "testall", 0, acls_reg_cnt);
918         archive_entry_free(ae);
919         assertEqualInt(ARCHIVE_OK, archive_read_free(a));
920
921         /* Read and compare ACL via archive_read_disk */
922         a = archive_read_disk_new();
923         assert(a != NULL);
924         ae = archive_entry_new();
925         assert(ae != NULL);
926         archive_entry_set_pathname(ae, "dirall");
927         assertEqualInt(ARCHIVE_OK,
928         archive_read_disk_entry_from_file(a, ae, -1, NULL));
929         compare_entry_acls(ae, acls_dir, "dirall", 0, acls_dir_cnt);
930         archive_entry_free(ae);
931         assertEqualInt(ARCHIVE_OK, archive_read_free(a));
932 #endif /* HAVE_NFS4_ACL */
933 }