]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/archive_write_disk_acl.c
MFC r310866,310868,310870,311903,313074:
[FreeBSD/stable/10.git] / contrib / libarchive / libarchive / archive_write_disk_acl.c
1 /*-
2  * Copyright (c) 2003-2010 Tim Kientzle
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
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
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 05:35:40Z kientzle $");
29
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
32 #endif
33 #ifdef HAVE_SYS_ACL_H
34 #define _ACL_PRIVATE /* For debugging */
35 #include <sys/acl.h>
36 #endif
37 #if HAVE_DARWIN_ACL
38 #include <membership.h>
39 #endif
40 #ifdef HAVE_ERRNO_H
41 #include <errno.h>
42 #endif
43
44 #include "archive.h"
45 #include "archive_entry.h"
46 #include "archive_acl_private.h"
47 #include "archive_write_disk_private.h"
48
49 #if !HAVE_POSIX_ACL && !HAVE_NFS4_ACL
50 /* Default empty function body to satisfy mainline code. */
51 int
52 archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
53          struct archive_acl *abstract_acl)
54 {
55         (void)a; /* UNUSED */
56         (void)fd; /* UNUSED */
57         (void)name; /* UNUSED */
58         (void)abstract_acl; /* UNUSED */
59         return (ARCHIVE_OK);
60 }
61
62 #else /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */
63
64 #if HAVE_SUN_ACL
65 #define ARCHIVE_PLATFORM_ACL_TYPE_NFS4  ACE_T
66 #elif HAVE_DARWIN_ACL
67 #define ARCHIVE_PLATFORM_ACL_TYPE_NFS4  ACL_TYPE_EXTENDED
68 #elif HAVE_ACL_TYPE_NFS4
69 #define ARCHIVE_PLATFORM_ACL_TYPE_NFS4  ACL_TYPE_NFS4
70 #endif
71
72 static int      set_acl(struct archive *, int fd, const char *,
73                         struct archive_acl *,
74                         acl_type_t, int archive_entry_acl_type, const char *tn);
75
76 int
77 archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
78          struct archive_acl *abstract_acl)
79 {
80         int             ret = ARCHIVE_OK;
81
82 #if !HAVE_DARWIN_ACL
83         if ((archive_acl_types(abstract_acl)
84             & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
85 #if HAVE_SUN_ACL
86                 /* Solaris writes POSIX.1e access and default ACLs together */
87                 ret = set_acl(a, fd, name, abstract_acl, ACLENT_T,
88                     ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e");
89 #else   /* HAVE_POSIX_ACL */
90                 if ((archive_acl_types(abstract_acl)
91                     & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
92                         ret = set_acl(a, fd, name, abstract_acl,
93                             ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
94                             "access");
95                         if (ret != ARCHIVE_OK)
96                                 return (ret);
97                 }
98                 if ((archive_acl_types(abstract_acl)
99                     & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
100                         ret = set_acl(a, fd, name, abstract_acl,
101                             ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT,
102                             "default");
103 #endif  /* !HAVE_SUN_ACL */
104                 /* Simultaeous POSIX.1e and NFSv4 is not supported */
105                 return (ret);
106         }
107 #endif  /* !HAVE_DARWIN_ACL */
108 #if HAVE_NFS4_ACL
109         if ((archive_acl_types(abstract_acl) &
110             ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
111                 ret = set_acl(a, fd, name, abstract_acl,
112                     ARCHIVE_PLATFORM_ACL_TYPE_NFS4,
113                     ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
114         }
115 #endif  /* HAVE_NFS4_ACL */
116         return (ret);
117 }
118
119 /*
120  * Translate system ACL permissions into libarchive internal structure
121  */
122 static struct {
123         int archive_perm;
124         int platform_perm;
125 } acl_perm_map[] = {
126 #if HAVE_SUN_ACL        /* Solaris NFSv4 ACL permissions */
127         {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},
128         {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},
129         {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},
130         {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
131         {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
132         {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
133         {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
134         {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
135         {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
136         {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
137         {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
138         {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
139         {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
140         {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
141         {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
142         {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
143         {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
144 #elif HAVE_DARWIN_ACL   /* MacOS ACL permissions */
145         {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
146         {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
147         {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
148         {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
149         {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
150         {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
151         {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
152         {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
153         {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
154         {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
155         {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
156         {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
157         {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
158         {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
159         {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
160         {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
161         {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
162 #else   /* POSIX.1e ACL permissions */
163         {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
164         {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
165         {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
166 #if HAVE_ACL_TYPE_NFS4  /* FreeBSD NFSv4 ACL permissions */
167         {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
168         {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
169         {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
170         {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
171         {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
172         {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
173         {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
174         {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
175         {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
176         {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
177         {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
178         {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
179         {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
180         {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
181         {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
182         {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
183 #endif
184 #endif  /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
185 };
186
187 #if HAVE_NFS4_ACL
188 /*
189  * Translate system NFSv4 inheritance flags into libarchive internal structure
190  */
191 static struct {
192         int archive_inherit;
193         int platform_inherit;
194 } acl_inherit_map[] = {
195 #if HAVE_SUN_ACL        /* Solaris NFSv4 inheritance flags */
196         {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},
197         {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},
198         {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},
199         {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},
200         {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
201         {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},
202         {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
203 #elif HAVE_DARWIN_ACL   /* MacOS NFSv4 inheritance flags */
204         {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
205         {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
206         {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
207         {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
208         {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
209 #else   /* FreeBSD NFSv4 ACL inheritance flags */
210         {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
211         {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
212         {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
213         {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
214         {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
215         {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
216         {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}
217 #endif  /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
218 };
219 #endif  /* HAVE_NFS4_ACL */
220
221 static int
222 set_acl(struct archive *a, int fd, const char *name,
223     struct archive_acl *abstract_acl,
224     acl_type_t acl_type, int ae_requested_type, const char *tname)
225 {
226 #if HAVE_SUN_ACL
227         aclent_t         *aclent;
228         ace_t            *ace;
229         int              e, r;
230         acl_t            *acl;
231 #else
232         acl_t            acl;
233         acl_entry_t      acl_entry;
234         acl_permset_t    acl_permset;
235 #if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
236         acl_flagset_t    acl_flagset;
237 #endif
238 #endif  /* HAVE_SUN_ACL */
239 #if HAVE_ACL_TYPE_NFS4
240         int             r;
241 #endif
242         int              ret;
243         int              ae_type, ae_permset, ae_tag, ae_id;
244 #if HAVE_DARWIN_ACL
245         uuid_t          ae_uuid;
246 #endif
247         uid_t            ae_uid;
248         gid_t            ae_gid;
249         const char      *ae_name;
250         int              entries;
251         int              i;
252
253         ret = ARCHIVE_OK;
254         entries = archive_acl_reset(abstract_acl, ae_requested_type);
255         if (entries == 0)
256                 return (ARCHIVE_OK);
257
258 #if HAVE_SUN_ACL
259         acl = NULL;
260         acl = malloc(sizeof(acl_t));
261         if (acl == NULL) {
262                 archive_set_error(a, ARCHIVE_ERRNO_MISC,
263                         "Invalid ACL type");
264                 return (ARCHIVE_FAILED);
265         }
266         if (acl_type == ACE_T)
267                 acl->acl_entry_size = sizeof(ace_t);
268         else if (acl_type == ACLENT_T)
269                 acl->acl_entry_size = sizeof(aclent_t);
270         else {
271                 archive_set_error(a, ARCHIVE_ERRNO_MISC,
272                         "Invalid ACL type");
273                 acl_free(acl);
274                 return (ARCHIVE_FAILED);
275         }
276         acl->acl_type = acl_type;
277         acl->acl_cnt = entries;
278
279         acl->acl_aclp = malloc(entries * acl->acl_entry_size);
280         if (acl->acl_aclp == NULL) {
281                 archive_set_error(a, errno,
282                     "Can't allocate memory for acl buffer");
283                 acl_free(acl);
284                 return (ARCHIVE_FAILED);
285         }
286 #else   /* !HAVE_SUN_ACL */
287         acl = acl_init(entries);
288         if (acl == (acl_t)NULL) {
289                 archive_set_error(a, errno,
290                     "Failed to initialize ACL working storage");
291                 return (ARCHIVE_FAILED);
292         }
293 #endif  /* !HAVE_SUN_ACL */
294 #if HAVE_SUN_ACL
295         e = 0;
296 #endif
297         while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
298                    &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
299 #if HAVE_SUN_ACL
300                 ace = NULL;
301                 aclent = NULL;
302                 if (acl->acl_type == ACE_T)  {
303                         ace = &((ace_t *)acl->acl_aclp)[e];
304                         ace->a_who = -1;
305                         ace->a_access_mask = 0;
306                         ace->a_flags = 0;
307                 } else {
308                         aclent = &((aclent_t *)acl->acl_aclp)[e];
309                         aclent->a_id = -1;
310                         aclent->a_type = 0;
311                         aclent->a_perm = 0;
312                 }
313 #else   /* !HAVE_SUN_ACL  */
314 #if HAVE_DARWIN_ACL
315                 /*
316                  * Mac OS doesn't support NFSv4 ACLs for
317                  * owner@, group@ and everyone@.
318                  * We skip any of these ACLs found.
319                  */
320                 if (ae_tag == ARCHIVE_ENTRY_ACL_USER_OBJ ||
321                     ae_tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ ||
322                     ae_tag == ARCHIVE_ENTRY_ACL_EVERYONE)
323                         continue;
324 #endif
325                 if (acl_create_entry(&acl, &acl_entry) != 0) {
326                         archive_set_error(a, errno,
327                             "Failed to create a new ACL entry");
328                         ret = ARCHIVE_FAILED;
329                         goto exit_free;
330                 }
331 #endif  /* !HAVE_SUN_ACL */
332 #if HAVE_DARWIN_ACL
333                 switch (ae_type) {
334                 case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
335                         acl_set_tag_type(acl_entry, ACL_EXTENDED_ALLOW);
336                         break;
337                 case ARCHIVE_ENTRY_ACL_TYPE_DENY:
338                         acl_set_tag_type(acl_entry, ACL_EXTENDED_DENY);
339                         break;
340                 default:
341                         /* We don't support any other types on MacOS */
342                         continue;
343                 }
344 #endif
345                 switch (ae_tag) {
346 #if HAVE_SUN_ACL
347                 case ARCHIVE_ENTRY_ACL_USER:
348                         ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
349                         if (acl->acl_type == ACE_T)
350                                 ace->a_who = ae_uid;
351                         else {
352                                 aclent->a_id = ae_uid;
353                                 aclent->a_type |= USER;
354                         }
355                         break;
356                 case ARCHIVE_ENTRY_ACL_GROUP:
357                         ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
358                         if (acl->acl_type == ACE_T) {
359                                 ace->a_who = ae_gid;
360                                 ace->a_flags |= ACE_IDENTIFIER_GROUP;
361                         } else {
362                                 aclent->a_id = ae_gid;
363                                 aclent->a_type |= GROUP;
364                         }
365                         break;
366                 case ARCHIVE_ENTRY_ACL_USER_OBJ:
367                         if (acl->acl_type == ACE_T)
368                                 ace->a_flags |= ACE_OWNER;
369                         else
370                                 aclent->a_type |= USER_OBJ;
371                         break;
372                 case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
373                         if (acl->acl_type == ACE_T) {
374                                 ace->a_flags |= ACE_GROUP;
375                                 ace->a_flags |= ACE_IDENTIFIER_GROUP;
376                         } else
377                                 aclent->a_type |= GROUP_OBJ;
378                         break;
379                 case ARCHIVE_ENTRY_ACL_MASK:
380                         aclent->a_type |= CLASS_OBJ;
381                         break;
382                 case ARCHIVE_ENTRY_ACL_OTHER:
383                         aclent->a_type |= OTHER_OBJ;
384                         break;
385                 case ARCHIVE_ENTRY_ACL_EVERYONE:
386                         ace->a_flags |= ACE_EVERYONE;
387                         break;
388 #else   /* !HAVE_SUN_ACL */
389                 case ARCHIVE_ENTRY_ACL_USER:
390                         ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
391 #if !HAVE_DARWIN_ACL    /* FreeBSD, Linux */
392                         acl_set_tag_type(acl_entry, ACL_USER);
393                         acl_set_qualifier(acl_entry, &ae_uid);
394 #else   /* MacOS */
395                         if (mbr_identifier_to_uuid(ID_TYPE_UID, &ae_uid,
396                             sizeof(uid_t), ae_uuid) != 0)
397                                 continue;
398                         if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)
399                                 continue;
400 #endif  /* HAVE_DARWIN_ACL */
401                         break;
402                 case ARCHIVE_ENTRY_ACL_GROUP:
403                         ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
404 #if !HAVE_DARWIN_ACL    /* FreeBSD, Linux */
405                         acl_set_tag_type(acl_entry, ACL_GROUP);
406                         acl_set_qualifier(acl_entry, &ae_gid);
407 #else   /* MacOS */
408                         if (mbr_identifier_to_uuid(ID_TYPE_GID, &ae_gid,
409                             sizeof(gid_t), ae_uuid) != 0)
410                                 continue;
411                         if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)
412                                 continue;
413 #endif  /* HAVE_DARWIN_ACL */
414                         break;
415 #if !HAVE_DARWIN_ACL    /* FreeBSD, Linux */
416                 case ARCHIVE_ENTRY_ACL_USER_OBJ:
417                         acl_set_tag_type(acl_entry, ACL_USER_OBJ);
418                         break;
419                 case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
420                         acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
421                         break;
422                 case ARCHIVE_ENTRY_ACL_MASK:
423                         acl_set_tag_type(acl_entry, ACL_MASK);
424                         break;
425                 case ARCHIVE_ENTRY_ACL_OTHER:
426                         acl_set_tag_type(acl_entry, ACL_OTHER);
427                         break;
428 #if HAVE_ACL_TYPE_NFS4  /* FreeBSD only */
429                 case ARCHIVE_ENTRY_ACL_EVERYONE:
430                         acl_set_tag_type(acl_entry, ACL_EVERYONE);
431                         break;
432 #endif
433 #endif  /* !HAVE_DARWIN_ACL */
434 #endif  /* !HAVE_SUN_ACL */
435                 default:
436                         archive_set_error(a, ARCHIVE_ERRNO_MISC,
437                             "Unknown ACL tag");
438                         ret = ARCHIVE_FAILED;
439                         goto exit_free;
440                 }
441
442 #if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL
443                 r = 0;
444                 switch (ae_type) {
445 #if HAVE_SUN_ACL
446                 case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
447                         if (ace != NULL)
448                                 ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
449                         else
450                                 r = -1;
451                         break;
452                 case ARCHIVE_ENTRY_ACL_TYPE_DENY:
453                         if (ace != NULL)
454                                 ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
455                         else
456                                 r = -1;
457                         break;
458                 case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
459                         if (ace != NULL)
460                                 ace->a_type = ACE_SYSTEM_AUDIT_ACE_TYPE;
461                         else
462                                 r = -1;
463                         break;
464                 case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
465                         if (ace != NULL)
466                                 ace->a_type = ACE_SYSTEM_ALARM_ACE_TYPE;
467                         else
468                                 r = -1;
469                         break;
470                 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
471                         if (aclent == NULL)
472                                 r = -1;
473                         break;
474                 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
475                         if (aclent != NULL)
476                                 aclent->a_type |= ACL_DEFAULT;
477                         else
478                                 r = -1;
479                         break;
480 #else   /* !HAVE_SUN_ACL */
481                 case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
482                         r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW);
483                         break;
484                 case ARCHIVE_ENTRY_ACL_TYPE_DENY:
485                         r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY);
486                         break;
487                 case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
488                         r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT);
489                         break;
490                 case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
491                         r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM);
492                         break;
493                 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
494                 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
495                         // These don't translate directly into the system ACL.
496                         break;
497 #endif  /* !HAVE_SUN_ACL */
498                 default:
499                         archive_set_error(a, ARCHIVE_ERRNO_MISC,
500                             "Unknown ACL entry type");
501                         ret = ARCHIVE_FAILED;
502                         goto exit_free;
503                 }
504
505                 if (r != 0) {
506 #if HAVE_SUN_ACL
507                         errno = EINVAL;
508 #endif
509                         archive_set_error(a, errno,
510                             "Failed to set ACL entry type");
511                         ret = ARCHIVE_FAILED;
512                         goto exit_free;
513                 }
514 #endif  /* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL */
515
516 #if HAVE_SUN_ACL
517                 if (acl->acl_type == ACLENT_T) {
518                         if (ae_permset & ARCHIVE_ENTRY_ACL_EXECUTE)
519                                 aclent->a_perm |= 1;
520                         if (ae_permset & ARCHIVE_ENTRY_ACL_WRITE)
521                                 aclent->a_perm |= 2;
522                         if (ae_permset & ARCHIVE_ENTRY_ACL_READ)
523                                 aclent->a_perm |= 4;
524                 } else
525 #else
526                 if (acl_get_permset(acl_entry, &acl_permset) != 0) {
527                         archive_set_error(a, errno,
528                             "Failed to get ACL permission set");
529                         ret = ARCHIVE_FAILED;
530                         goto exit_free;
531                 }
532                 if (acl_clear_perms(acl_permset) != 0) {
533                         archive_set_error(a, errno,
534                             "Failed to clear ACL permissions");
535                         ret = ARCHIVE_FAILED;
536                         goto exit_free;
537                 }
538 #endif  /* !HAVE_SUN_ACL */
539                 for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
540                         if (ae_permset & acl_perm_map[i].archive_perm) {
541 #if HAVE_SUN_ACL
542                                 ace->a_access_mask |=
543                                     acl_perm_map[i].platform_perm;
544 #else
545                                 if (acl_add_perm(acl_permset,
546                                     acl_perm_map[i].platform_perm) != 0) {
547                                         archive_set_error(a, errno,
548                                             "Failed to add ACL permission");
549                                         ret = ARCHIVE_FAILED;
550                                         goto exit_free;
551                                 }
552 #endif
553                         }
554                 }
555
556 #if HAVE_NFS4_ACL
557 #if HAVE_SUN_ACL
558                 if (acl_type == ACE_T)
559 #elif HAVE_DARWIN_ACL
560                 if (acl_type == ACL_TYPE_EXTENDED)
561 #else   /* FreeBSD */
562                 if (acl_type == ACL_TYPE_NFS4)
563 #endif
564                 {
565 #if HAVE_POSIX_ACL || HAVE_DARWIN_ACL
566                         /*
567                          * acl_get_flagset_np() fails with non-NFSv4 ACLs
568                          */
569                         if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
570                                 archive_set_error(a, errno,
571                                     "Failed to get flagset from an NFSv4 ACL entry");
572                                 ret = ARCHIVE_FAILED;
573                                 goto exit_free;
574                         }
575                         if (acl_clear_flags_np(acl_flagset) != 0) {
576                                 archive_set_error(a, errno,
577                                     "Failed to clear flags from an NFSv4 ACL flagset");
578                                 ret = ARCHIVE_FAILED;
579                                 goto exit_free;
580                         }
581 #endif /* HAVE_POSIX_ACL || HAVE_DARWIN_ACL */
582                         for (i = 0; i < (int)(sizeof(acl_inherit_map) /sizeof(acl_inherit_map[0])); ++i) {
583                                 if (ae_permset & acl_inherit_map[i].archive_inherit) {
584 #if HAVE_SUN_ACL
585                                         ace->a_flags |=
586                                             acl_inherit_map[i].platform_inherit;
587 #else   /* !HAVE_SUN_ACL */
588                                         if (acl_add_flag_np(acl_flagset,
589                                                         acl_inherit_map[i].platform_inherit) != 0) {
590                                                 archive_set_error(a, errno,
591                                                     "Failed to add flag to NFSv4 ACL flagset");
592                                                 ret = ARCHIVE_FAILED;
593                                                 goto exit_free;
594                                         }
595 #endif  /* HAVE_SUN_ACL */
596                                 }
597                         }
598                 }
599 #endif  /* HAVE_NFS4_ACL */
600 #if HAVE_SUN_ACL
601         e++;
602 #endif
603         }
604
605 #if HAVE_ACL_SET_FD_NP || HAVE_ACL_SET_FD || HAVE_SUN_ACL
606         /* Try restoring the ACL through 'fd' if we can. */
607 #if HAVE_SUN_ACL || HAVE_ACL_SET_FD_NP
608         if (fd >= 0)
609 #else   /* !HAVE_SUN_ACL && !HAVE_ACL_SET_FD_NP */
610         if (fd >= 0 && acl_type == ACL_TYPE_ACCESS)
611 #endif
612         {
613 #if HAVE_SUN_ACL
614                 if (facl_set(fd, acl) == 0)
615 #elif HAVE_ACL_SET_FD_NP
616                 if (acl_set_fd_np(fd, acl, acl_type) == 0)
617 #else   /* !HAVE_SUN_ACL && !HAVE_ACL_SET_FD_NP */
618                 if (acl_set_fd(fd, acl) == 0)
619 #endif
620                         ret = ARCHIVE_OK;
621                 else {
622                         if (errno == EOPNOTSUPP) {
623                                 /* Filesystem doesn't support ACLs */
624                                 ret = ARCHIVE_OK;
625                         } else {
626                                 archive_set_error(a, errno,
627                                     "Failed to set %s acl on fd", tname);
628                         }
629                 }
630         } else
631 #endif  /* HAVE_ACL_SET_FD_NP || HAVE_ACL_SET_FD || HAVE_SUN_ACL */
632 #if HAVE_SUN_ACL
633         if (acl_set(name, acl) != 0)
634 #elif HAVE_ACL_SET_LINK_NP
635         if (acl_set_link_np(name, acl_type, acl) != 0)
636 #else
637         /* TODO: Skip this if 'name' is a symlink. */
638         if (acl_set_file(name, acl_type, acl) != 0)
639 #endif
640         {
641                 if (errno == EOPNOTSUPP) {
642                         /* Filesystem doesn't support ACLs */
643                         ret = ARCHIVE_OK;
644                 } else {
645                         archive_set_error(a, errno, "Failed to set %s acl",
646                             tname);
647                         ret = ARCHIVE_WARN;
648                 }
649         }
650 exit_free:
651         acl_free(acl);
652         return (ret);
653 }
654 #endif  /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */