1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
3 /* copy-acl.c - copy access control list from one file to another file
5 Copyright (C) 2002-2003, 2005-2014 Free Software Foundation, Inc.
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
26 #include "acl-internal.h"
29 /* Copy access control lists from one file to another. If SOURCE_DESC is
30 a valid file descriptor, use file descriptor operations, else use
31 filename based operations on SRC_NAME. Likewise for DEST_DESC and
33 If access control lists are not available, fchmod the target file to
34 MODE. Also sets the non-permission bits of the destination file
35 (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
36 Return 0 if successful.
37 Return -2 and set errno for an error relating to the source file.
38 Return -1 and set errno for an error relating to the destination file. */
41 qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
42 int dest_desc, mode_t mode)
44 #if USE_ACL && HAVE_ACL_GET_FILE
45 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
46 /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
47 # if !HAVE_ACL_TYPE_EXTENDED
48 /* Linux, FreeBSD, IRIX, Tru64 */
53 if (HAVE_ACL_GET_FD && source_desc != -1)
54 acl = acl_get_fd (source_desc);
56 acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
59 if (! acl_errno_valid (errno))
60 return qset_acl (dst_name, dest_desc, mode);
65 if (HAVE_ACL_SET_FD && dest_desc != -1)
66 ret = acl_set_fd (dest_desc, acl);
68 ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
71 int saved_errno = errno;
73 if (! acl_errno_valid (errno) && !acl_access_nontrivial (acl))
76 return chmod_or_fchmod (dst_name, dest_desc, mode);
81 chmod_or_fchmod (dst_name, dest_desc, mode);
89 if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
91 /* We did not call chmod so far, and either the mode and the ACL are
92 separate or special bits are to be set which don't fit into ACLs. */
94 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
100 acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
104 if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
106 int saved_errno = errno;
117 # else /* HAVE_ACL_TYPE_EXTENDED */
120 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
121 and acl_get_file (name, ACL_TYPE_DEFAULT)
122 always return NULL / EINVAL. You have to use
123 acl_get_file (name, ACL_TYPE_EXTENDED)
124 or acl_get_fd (open (name, ...))
127 acl_set_file (name, ACL_TYPE_ACCESS, acl)
128 and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
129 have the same effect as
130 acl_set_file (name, ACL_TYPE_EXTENDED, acl):
131 Each of these calls sets the file's ACL. */
136 if (HAVE_ACL_GET_FD && source_desc != -1)
137 acl = acl_get_fd (source_desc);
139 acl = acl_get_file (src_name, ACL_TYPE_EXTENDED);
142 if (!acl_errno_valid (errno))
143 return qset_acl (dst_name, dest_desc, mode);
148 if (HAVE_ACL_SET_FD && dest_desc != -1)
149 ret = acl_set_fd (dest_desc, acl);
151 ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl);
154 int saved_errno = errno;
156 if (!acl_errno_valid (saved_errno) && !acl_extended_nontrivial (acl))
159 return chmod_or_fchmod (dst_name, dest_desc, mode);
164 chmod_or_fchmod (dst_name, dest_desc, mode);
172 /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
173 return chmod_or_fchmod (dst_name, dest_desc, mode);
177 #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
179 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
180 of Unixware. The acl() call returns the access and default ACL both
193 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
194 file systems (whereas the other ones are used in UFS file systems).
196 pathconf (name, _PC_ACL_ENABLED)
197 fpathconf (desc, _PC_ACL_ENABLED)
198 that allows to determine which of the two kinds of ACLs is supported
199 for the given file. But some file systems may implement this call
200 incorrectly, so better not use it.
201 When fetching the source ACL, we simply fetch both ACL types.
202 When setting the destination ACL, we try either ACL types, assuming
203 that the kernel will translate the ACL from one form to the other.
204 (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
205 the description of ENOTSUP.) */
208 ace_count = (source_desc != -1
209 ? facl (source_desc, ACE_GETACLCNT, 0, NULL)
210 : acl (src_name, ACE_GETACLCNT, 0, NULL));
214 if (errno == ENOSYS || errno == EINVAL)
230 ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t));
231 if (ace_entries == NULL)
237 ret = (source_desc != -1
238 ? facl (source_desc, ACE_GETACL, ace_count, ace_entries)
239 : acl (src_name, ACE_GETACL, ace_count, ace_entries));
243 if (errno == ENOSYS || errno == EINVAL)
252 if (ret == ace_count)
254 /* Huh? The number of ACL entries changed since the last call.
261 count = (source_desc != -1
262 ? facl (source_desc, GETACLCNT, 0, NULL)
263 : acl (src_name, GETACLCNT, 0, NULL));
267 if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
283 entries = (aclent_t *) malloc (count * sizeof (aclent_t));
290 if ((source_desc != -1
291 ? facl (source_desc, GETACL, count, entries)
292 : acl (src_name, GETACL, count, entries))
295 /* Huh? The number of ACL entries changed since the last call.
299 /* Is there an ACL of either kind? */
304 return qset_acl (dst_name, dest_desc, mode);
306 did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
307 saved_errno = 0; /* the first non-ignorable error code */
309 if (!MODE_INSIDE_ACL)
311 /* On Cygwin, it is necessary to call chmod before acl, because
312 chmod can change the contents of the ACL (in ways that don't
313 change the allowed accesses, but still visible). */
314 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
319 /* If both ace_entries and entries are available, try SETACL before
320 ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
325 ret = (dest_desc != -1
326 ? facl (dest_desc, SETACL, count, entries)
327 : acl (dst_name, SETACL, count, entries));
328 if (ret < 0 && saved_errno == 0)
331 if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
332 && !acl_nontrivial (count, entries))
343 ret = (dest_desc != -1
344 ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries)
345 : acl (dst_name, ACE_SETACL, ace_count, ace_entries));
346 if (ret < 0 && saved_errno == 0)
349 if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
350 && !acl_ace_nontrivial (ace_count, ace_entries))
358 && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
360 /* We did not call chmod so far, and either the mode and the ACL are
361 separate or special bits are to be set which don't fit into ACLs. */
363 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
365 if (saved_errno == 0)
377 #elif USE_ACL && HAVE_GETACL /* HP-UX */
379 struct acl_entry entries[NACLENTRIES];
382 struct acl aclv_entries[NACLVENTRIES];
389 count = (source_desc != -1
390 ? fgetacl (source_desc, NACLENTRIES, entries)
391 : getacl (src_name, NACLENTRIES, entries));
395 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
402 if (count > NACLENTRIES)
403 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
408 aclv_count = acl ((char *) src_name, ACL_GET, NACLVENTRIES, aclv_entries);
412 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
417 else if (aclv_count > 0)
419 if (aclv_count > NACLVENTRIES)
420 /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */
429 return qset_acl (dst_name, dest_desc, mode);
431 did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
432 saved_errno = 0; /* the first non-ignorable error code */
436 ret = (dest_desc != -1
437 ? fsetacl (dest_desc, count, entries)
438 : setacl (dst_name, count, entries));
439 if (ret < 0 && saved_errno == 0)
442 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
444 struct stat source_statbuf;
446 if ((source_desc != -1
447 ? fstat (source_desc, &source_statbuf)
448 : stat (src_name, &source_statbuf)) == 0)
450 if (!acl_nontrivial (count, entries, &source_statbuf))
464 ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries);
465 if (ret < 0 && saved_errno == 0)
468 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
470 if (!aclv_nontrivial (aclv_count, aclv_entries))
479 if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
481 /* We did not call chmod so far, and special bits are to be set which
482 don't fit into ACLs. */
484 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
486 if (saved_errno == 0)
498 #elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */
502 #elif USE_ACL && HAVE_STATACL /* older AIX */
504 union { struct acl a; char room[4096]; } u;
507 if ((source_desc != -1
508 ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u))
509 : statacl (src_name, STX_NORMAL, &u.a, sizeof (u)))
513 ret = (dest_desc != -1
514 ? fchacl (dest_desc, &u.a, u.a.acl_len)
515 : chacl (dst_name, &u.a, u.a.acl_len));
518 int saved_errno = errno;
520 chmod_or_fchmod (dst_name, dest_desc, mode);
525 /* No need to call chmod_or_fchmod at this point, since the mode bits
526 S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */
530 #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
532 struct acl entries[NACLENTRIES];
536 count = acl ((char *) src_name, ACL_GET, NACLENTRIES, entries);
547 if (count > NACLENTRIES)
548 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
553 return qset_acl (dst_name, dest_desc, mode);
555 ret = acl ((char *) dst_name, ACL_SET, count, entries);
558 int saved_errno = errno;
562 if (!acl_nontrivial (count, entries))
563 return chmod_or_fchmod (dst_name, dest_desc, mode);
566 chmod_or_fchmod (dst_name, dest_desc, mode);
571 if (mode & (S_ISUID | S_ISGID | S_ISVTX))
573 /* We did not call chmod so far, and either the mode and the ACL are
574 separate or special bits are to be set which don't fit into ACLs. */
576 return chmod_or_fchmod (dst_name, dest_desc, mode);
582 return qset_acl (dst_name, dest_desc, mode);