]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/test/test_acl_platform_nfs4.c
MFC r368207,368607:
[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 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
41 struct 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
49 static 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
136 static const int acls_reg_cnt = (int)(sizeof(acls_reg)/sizeof(acls_reg[0]));
137
138 static 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
256 static const int acls_dir_cnt = (int)(sizeof(acls_dir)/sizeof(acls_dir[0]));
257
258 static void
259 set_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
280 static int
281 #if ARCHIVE_ACL_SUNOS_NFS4
282 acl_permset_to_bitmap(uint32_t mask)
283 #elif ARCHIVE_ACL_LIBRICHACL
284 acl_permset_to_bitmap(unsigned int mask)
285 #else
286 acl_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
378 static int
379 #if ARCHIVE_ACL_SUNOS_NFS4
380 acl_flagset_to_bitmap(uint16_t flags)
381 #elif ARCHIVE_ACL_LIBRICHACL
382 acl_flagset_to_bitmap(int flags)
383 #else
384 acl_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
435 static int
436 acl_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
489 static int
490 acl_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
545 static int
546 acl_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 */
604 static int
605 acl_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                 break;
638         case ACL_ENTRY_TYPE_ALARM:
639                 if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM)
640                         return (0);
641                 break;
642         default:
643                 return (0);
644         }
645
646         switch (tag_type) {
647         case ACL_USER_OBJ:
648                 if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0);
649                 break;
650         case ACL_USER:
651                 if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
652                         return (0);
653                 up = acl_get_qualifier(aclent);
654                 u = *up;
655                 acl_free(up);
656                 if ((uid_t)myacl->qual != u)
657                         return (0);
658                 break;
659         case ACL_GROUP_OBJ:
660                 if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0);
661                 break;
662         case ACL_GROUP:
663                 if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
664                         return (0);
665                 gp = acl_get_qualifier(aclent);
666                 g = *gp;
667                 acl_free(gp);
668                 if ((gid_t)myacl->qual != g)
669                         return (0);
670                 break;
671         case ACL_MASK:
672                 if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0);
673                 break;
674         case ACL_EVERYONE:
675                 if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0);
676                 break;
677         }
678         return (1);
679 }
680 #endif  /* various ARCHIVE_ACL_NFS4 implementations */
681
682 static void
683 compare_acls(
684 #if ARCHIVE_ACL_SUNOS_NFS4
685     void *aclp,
686     int aclcnt,
687 #elif ARCHIVE_ACL_LIBRICHACL
688     struct richacl *richacl,
689 #else
690     acl_t acl,
691 #endif
692     struct myacl_t *myacls, const char *filename, int start, int end)
693 {
694         int *marker;
695         int matched;
696         int i, n;
697 #if ARCHIVE_ACL_SUNOS_NFS4
698         int e;
699         ace_t *acl_entry;
700 #elif ARCHIVE_ACL_LIBRICHACL
701         int e;
702         struct richace *acl_entry;
703         int aclcnt;
704 #else
705         int entry_id = ACL_FIRST_ENTRY;
706         acl_entry_t acl_entry;
707 #if ARCHIVE_ACL_DARWIN
708         const int acl_get_entry_ret = 0;
709 #else
710         const int acl_get_entry_ret = 1;
711 #endif
712 #endif
713
714 #if ARCHIVE_ACL_SUNOS_NFS4
715         if (aclp == NULL)
716                 return;
717 #elif ARCHIVE_ACL_LIBRICHACL
718         if (richacl == NULL)
719                 return;
720         aclcnt = richacl->a_count;
721 #else
722         if (acl == NULL)
723                 return;
724 #endif
725
726         n = end - start;
727         marker = malloc(sizeof(marker[0]) * (n + 1));
728         for (i = 0; i < n; i++)
729                 marker[i] = i + start;
730 #if !ARCHIVE_ACL_DARWIN
731         /* Always include the first ACE. */
732         if (start > 0) {
733           marker[n] = 0;
734           ++n;
735         }
736 #endif
737
738         /*
739          * Iterate over acls in system acl object, try to match each
740          * one with an item in the myacls array.
741          */
742 #if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
743         for (e = 0; e < aclcnt; e++)
744 #else
745         while (acl_get_entry_ret == acl_get_entry(acl, entry_id, &acl_entry))
746 #endif
747         {
748 #if ARCHIVE_ACL_SUNOS_NFS4
749                 acl_entry = &((ace_t *)aclp)[e];
750 #elif ARCHIVE_ACL_LIBRICHACL
751                 acl_entry = &(richacl->a_entries[e]);
752 #else
753                 /* After the first time... */
754                 entry_id = ACL_NEXT_ENTRY;
755 #endif
756                 /* Search for a matching entry (tag and qualifier) */
757                 for (i = 0, matched = 0; i < n && !matched; i++) {
758                         if (acl_match(acl_entry, &myacls[marker[i]])) {
759                                 /* We found a match; remove it. */
760                                 marker[i] = marker[n - 1];
761                                 n--;
762                                 matched = 1;
763                         }
764                 }
765
766                 failure("ACL entry on file %s that shouldn't be there",
767                     filename);
768                 assert(matched == 1);
769         }
770
771         /* Dump entries in the myacls array that weren't in the system acl. */
772         for (i = 0; i < n; ++i) {
773                 failure(" ACL entry %d missing from %s: "
774                     "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
775                     marker[i], filename,
776                     myacls[marker[i]].type, myacls[marker[i]].permset,
777                     myacls[marker[i]].tag, myacls[marker[i]].qual,
778                     myacls[marker[i]].name);
779                 assert(0); /* Record this as a failure. */
780         }
781         free(marker);
782 }
783
784 static void
785 compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char *filename, int start, int end)
786 {
787         int *marker;
788         int matched;
789         int i, n;
790         int type, permset, tag, qual;
791         const char *name;
792
793         /* Count ACL entries in myacls array and allocate an indirect array. */
794         n = end - start;
795         marker = malloc(sizeof(marker[0]) * (n + 1));
796         for (i = 0; i < n; i++)
797                 marker[i] = i + start;
798         /* Always include the first ACE. */
799         if (start > 0) {
800           marker[n] = 0;
801           ++n;
802         }
803
804         /*
805          * Iterate over acls in entry, try to match each
806          * one with an item in the myacls array.
807          */
808         assertEqualInt(n, archive_entry_acl_reset(ae,
809             ARCHIVE_ENTRY_ACL_TYPE_NFS4));
810         while (ARCHIVE_OK == archive_entry_acl_next(ae,
811             ARCHIVE_ENTRY_ACL_TYPE_NFS4, &type, &permset, &tag, &qual, &name)) {
812
813                 /* Search for a matching entry (tag and qualifier) */
814                 for (i = 0, matched = 0; i < n && !matched; i++) {
815                         if (tag == myacls[marker[i]].tag
816                             && qual == myacls[marker[i]].qual
817                             && permset == myacls[marker[i]].permset
818                             && type == myacls[marker[i]].type) {
819                                 /* We found a match; remove it. */
820                                 marker[i] = marker[n - 1];
821                                 n--;
822                                 matched = 1;
823                         }
824                 }
825
826                 failure("ACL entry on file that shouldn't be there: "
827                         "type=%#010x,permset=%#010x,tag=%d,qual=%d",
828                         type,permset,tag,qual);
829                 assert(matched == 1);
830         }
831
832         /* Dump entries in the myacls array that weren't in the system acl. */
833         for (i = 0; i < n; ++i) {
834                 failure(" ACL entry %d missing from %s: "
835                     "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
836                     marker[i], filename,
837                     myacls[marker[i]].type, myacls[marker[i]].permset,
838                     myacls[marker[i]].tag, myacls[marker[i]].qual,
839                     myacls[marker[i]].name);
840                 assert(0); /* Record this as a failure. */
841         }
842         free(marker);
843 }
844 #endif  /* ARCHIVE_ACL_NFS4 */
845
846 /*
847  * Verify ACL restore-to-disk.  This test is Platform-specific.
848  */
849
850 DEFINE_TEST(test_acl_platform_nfs4)
851 {
852 #if !ARCHIVE_ACL_NFS4
853         skipping("NFS4 ACLs are not supported on this platform");
854 #else /* ARCHIVE_ACL_NFS4 */
855         char buff[64];
856         int i;
857         struct stat st;
858         struct archive *a;
859         struct archive_entry *ae;
860 #if ARCHIVE_ACL_DARWIN /* On MacOS we skip trivial ACLs in some tests */
861         const int regcnt = acls_reg_cnt - 4;
862         const int dircnt = acls_dir_cnt - 4;
863 #else
864         const int regcnt = acls_reg_cnt;
865         const int dircnt = acls_dir_cnt;
866 #endif
867 #if ARCHIVE_ACL_SUNOS_NFS4
868         void *aclp;
869         int aclcnt;
870 #elif ARCHIVE_ACL_LIBRICHACL
871         struct richacl *richacl;
872 #else   /* !ARCHIVE_ACL_SUNOS_NFS4 */
873         acl_t acl;
874 #endif
875
876         assertMakeFile("pretest", 0644, "a");
877
878         if (setTestAcl("pretest") != ARCHIVE_TEST_ACL_TYPE_NFS4) {
879                 skipping("NFS4 ACLs are not writable on this filesystem");
880                 return;
881         }
882
883         /* Create a write-to-disk object. */
884         assert(NULL != (a = archive_write_disk_new()));
885         archive_write_disk_set_options(a,
886             ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL);
887
888         /* Populate an archive entry with some metadata, including ACL info */
889         ae = archive_entry_new();
890         assert(ae != NULL);
891         archive_entry_set_pathname(ae, "testall");
892         archive_entry_set_filetype(ae, AE_IFREG);
893         archive_entry_set_perm(ae, 0654);
894         archive_entry_set_mtime(ae, 123456, 7890);
895         archive_entry_set_size(ae, 0);
896         set_acls(ae, acls_reg, 0, acls_reg_cnt);
897
898         /* Write the entry to disk, including ACLs. */
899         assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
900
901         /* Likewise for a dir. */
902         archive_entry_set_pathname(ae, "dirall");
903         archive_entry_set_filetype(ae, AE_IFDIR);
904         archive_entry_set_perm(ae, 0654);
905         archive_entry_set_mtime(ae, 123456, 7890);
906         set_acls(ae, acls_dir, 0, acls_dir_cnt);
907         assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
908
909         for (i = 0; i < acls_dir_cnt; ++i) {
910           sprintf(buff, "dir%d", i);
911           archive_entry_set_pathname(ae, buff);
912           archive_entry_set_filetype(ae, AE_IFDIR);
913           archive_entry_set_perm(ae, 0654);
914           archive_entry_set_mtime(ae, 123456 + i, 7891 + i);
915           set_acls(ae, acls_dir, i, i + 1);
916           assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
917         }
918
919         archive_entry_free(ae);
920
921         /* Close the archive. */
922         assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
923         assertEqualInt(ARCHIVE_OK, archive_write_free(a));
924
925         /* Verify the data on disk. */
926         assertEqualInt(0, stat("testall", &st));
927         assertEqualInt(st.st_mtime, 123456);
928 #if ARCHIVE_ACL_SUNOS_NFS4
929         aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "testall");
930         failure("acl(\"%s\"): errno = %d (%s)", "testall", errno,
931             strerror(errno));
932         assert(aclp != NULL);
933 #elif ARCHIVE_ACL_LIBRICHACL
934         richacl = richacl_get_file("testall");
935         failure("richacl_get_file(\"%s\"): errno = %d (%s)", "testall", errno,
936             strerror(errno));
937         assert(richacl != NULL);
938 #else
939 #if ARCHIVE_ACL_DARWIN
940         acl = acl_get_file("testall", ACL_TYPE_EXTENDED);
941 #else
942         acl = acl_get_file("testall", ACL_TYPE_NFS4);
943 #endif
944         failure("acl_get_file(\"%s\"): errno = %d (%s)", "testall", errno,
945             strerror(errno));
946         assert(acl != (acl_t)NULL);
947 #endif
948 #if ARCHIVE_ACL_SUNOS_NFS4
949         compare_acls(aclp, aclcnt, acls_reg, "testall", 0, regcnt);
950         free(aclp);
951         aclp = NULL;
952 #elif ARCHIVE_ACL_LIBRICHACL
953         compare_acls(richacl, acls_reg, "testall", 0, regcnt);
954         richacl_free(richacl);
955 #else
956         compare_acls(acl, acls_reg, "testall", 0, regcnt);
957         acl_free(acl);
958 #endif
959
960
961         /* Verify single-permission dirs on disk. */
962         for (i = 0; i < dircnt; ++i) {
963                 sprintf(buff, "dir%d", i);
964                 assertEqualInt(0, stat(buff, &st));
965                 assertEqualInt(st.st_mtime, 123456 + i);
966 #if ARCHIVE_ACL_SUNOS_NFS4
967                 aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, buff);
968                 failure("acl(\"%s\"): errno = %d (%s)", buff, errno,
969                     strerror(errno));
970                 assert(aclp != NULL);
971 #elif ARCHIVE_ACL_LIBRICHACL
972                 richacl = richacl_get_file(buff);
973                 /* First and last two dir do not return a richacl */
974                 if ((i == 0 || i >= dircnt - 2) && richacl == NULL &&
975                     errno == ENODATA)
976                         continue;
977                 failure("richacl_get_file(\"%s\"): errno = %d (%s)", buff,
978                     errno, strerror(errno));
979                 assert(richacl != NULL);
980 #else
981 #if ARCHIVE_ACL_DARWIN
982                 acl = acl_get_file(buff, ACL_TYPE_EXTENDED);
983 #else
984                 acl = acl_get_file(buff, ACL_TYPE_NFS4);
985 #endif
986                 failure("acl_get_file(\"%s\"): errno = %d (%s)", buff, errno,
987                     strerror(errno));
988                 assert(acl != (acl_t)NULL);
989 #endif
990 #if ARCHIVE_ACL_SUNOS_NFS4
991                 compare_acls(aclp, aclcnt, acls_dir, buff, i, i + 1);
992                 free(aclp);
993                 aclp = NULL;
994 #elif ARCHIVE_ACL_LIBRICHACL
995                 compare_acls(richacl, acls_dir, buff, i, i + 1);
996                 richacl_free(richacl);
997 #else
998                 compare_acls(acl, acls_dir, buff, i, i + 1);
999                 acl_free(acl);
1000 #endif
1001         }
1002
1003         /* Verify "dirall" on disk. */
1004         assertEqualInt(0, stat("dirall", &st));
1005         assertEqualInt(st.st_mtime, 123456);
1006 #if ARCHIVE_ACL_SUNOS_NFS4
1007         aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "dirall");
1008         failure("acl(\"%s\"): errno = %d (%s)", "dirall", errno,
1009             strerror(errno));
1010         assert(aclp != NULL);
1011 #elif ARCHIVE_ACL_LIBRICHACL
1012         richacl = richacl_get_file("dirall");
1013         failure("richacl_get_file(\"%s\"): errno = %d (%s)", "dirall",
1014             errno, strerror(errno));
1015         assert(richacl != NULL);
1016 #else
1017 #if ARCHIVE_ACL_DARWIN
1018         acl = acl_get_file("dirall", ACL_TYPE_EXTENDED);
1019 #else
1020         acl = acl_get_file("dirall", ACL_TYPE_NFS4);
1021 #endif
1022         failure("acl_get_file(\"%s\"): errno = %d (%s)", "dirall", errno,
1023             strerror(errno));
1024         assert(acl != (acl_t)NULL);
1025 #endif
1026 #if ARCHIVE_ACL_SUNOS_NFS4
1027         compare_acls(aclp, aclcnt, acls_dir, "dirall", 0, dircnt);
1028         free(aclp);
1029         aclp = NULL;
1030 #elif ARCHIVE_ACL_LIBRICHACL
1031         compare_acls(richacl, acls_dir, "dirall", 0, dircnt);
1032         richacl_free(richacl);
1033 #else
1034         compare_acls(acl, acls_dir, "dirall", 0, dircnt);
1035         acl_free(acl);
1036 #endif
1037
1038         /* Read and compare ACL via archive_read_disk */
1039         a = archive_read_disk_new();
1040         assert(a != NULL);
1041         ae = archive_entry_new();
1042         assert(ae != NULL);
1043         archive_entry_set_pathname(ae, "testall");
1044         assertEqualInt(ARCHIVE_OK,
1045                        archive_read_disk_entry_from_file(a, ae, -1, NULL));
1046         compare_entry_acls(ae, acls_reg, "testall", 0, acls_reg_cnt);
1047         archive_entry_free(ae);
1048         assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1049
1050         /* Read and compare ACL via archive_read_disk */
1051         a = archive_read_disk_new();
1052         assert(a != NULL);
1053         ae = archive_entry_new();
1054         assert(ae != NULL);
1055         archive_entry_set_pathname(ae, "dirall");
1056         assertEqualInt(ARCHIVE_OK,
1057         archive_read_disk_entry_from_file(a, ae, -1, NULL));
1058         compare_entry_acls(ae, acls_dir, "dirall", 0, acls_dir_cnt);
1059         archive_entry_free(ae);
1060         assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1061 #endif /* ARCHIVE_ACL_NFS4 */
1062 }