1 /* copy-acl.c - copy access control list from one file to another file
3 Copyright (C) 2002-2003, 2005-2012 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
24 #include "acl-internal.h"
27 #define _(msgid) gettext (msgid)
30 /* Copy access control lists from one file to another. If SOURCE_DESC is
31 a valid file descriptor, use file descriptor operations, else use
32 filename based operations on SRC_NAME. Likewise for DEST_DESC and
34 If access control lists are not available, fchmod the target file to
35 MODE. Also sets the non-permission bits of the destination file
36 (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
37 Return 0 if successful.
38 Return -2 and set errno for an error relating to the source file.
39 Return -1 and set errno for an error relating to the destination file. */
42 qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
43 int dest_desc, mode_t mode)
45 #if USE_ACL && HAVE_ACL_GET_FILE
46 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
47 /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
48 # if !HAVE_ACL_TYPE_EXTENDED
49 /* Linux, FreeBSD, IRIX, Tru64 */
54 if (HAVE_ACL_GET_FD && source_desc != -1)
55 acl = acl_get_fd (source_desc);
57 acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
60 if (ACL_NOT_WELL_SUPPORTED (errno))
61 return qset_acl (dst_name, dest_desc, mode);
66 if (HAVE_ACL_SET_FD && dest_desc != -1)
67 ret = acl_set_fd (dest_desc, acl);
69 ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
72 int saved_errno = errno;
74 if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_access_nontrivial (acl))
77 return chmod_or_fchmod (dst_name, dest_desc, mode);
82 chmod_or_fchmod (dst_name, dest_desc, mode);
90 if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
92 /* We did not call chmod so far, and either the mode and the ACL are
93 separate or special bits are to be set which don't fit into ACLs. */
95 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
101 acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
105 if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
107 int saved_errno = errno;
118 # else /* HAVE_ACL_TYPE_EXTENDED */
121 /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
122 and acl_get_file (name, ACL_TYPE_DEFAULT)
123 always return NULL / EINVAL. You have to use
124 acl_get_file (name, ACL_TYPE_EXTENDED)
125 or acl_get_fd (open (name, ...))
128 acl_set_file (name, ACL_TYPE_ACCESS, acl)
129 and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
130 have the same effect as
131 acl_set_file (name, ACL_TYPE_EXTENDED, acl):
132 Each of these calls sets the file's ACL. */
137 if (HAVE_ACL_GET_FD && source_desc != -1)
138 acl = acl_get_fd (source_desc);
140 acl = acl_get_file (src_name, ACL_TYPE_EXTENDED);
143 if (ACL_NOT_WELL_SUPPORTED (errno))
144 return qset_acl (dst_name, dest_desc, mode);
149 if (HAVE_ACL_SET_FD && dest_desc != -1)
150 ret = acl_set_fd (dest_desc, acl);
152 ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl);
155 int saved_errno = errno;
157 if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_extended_nontrivial (acl))
160 return chmod_or_fchmod (dst_name, dest_desc, mode);
165 chmod_or_fchmod (dst_name, dest_desc, mode);
173 /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
174 return chmod_or_fchmod (dst_name, dest_desc, mode);
178 #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
180 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
181 of Unixware. The acl() call returns the access and default ACL both
194 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
195 file systems (whereas the other ones are used in UFS file systems).
197 pathconf (name, _PC_ACL_ENABLED)
198 fpathconf (desc, _PC_ACL_ENABLED)
199 that allows to determine which of the two kinds of ACLs is supported
200 for the given file. But some file systems may implement this call
201 incorrectly, so better not use it.
202 When fetching the source ACL, we simply fetch both ACL types.
203 When setting the destination ACL, we try either ACL types, assuming
204 that the kernel will translate the ACL from one form to the other.
205 (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
206 the description of ENOTSUP.) */
209 ace_count = (source_desc != -1
210 ? facl (source_desc, ACE_GETACLCNT, 0, NULL)
211 : acl (src_name, ACE_GETACLCNT, 0, NULL));
215 if (errno == ENOSYS || errno == EINVAL)
231 ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t));
232 if (ace_entries == NULL)
238 if ((source_desc != -1
239 ? facl (source_desc, ACE_GETACL, ace_count, ace_entries)
240 : acl (src_name, ACE_GETACL, ace_count, ace_entries))
243 /* Huh? The number of ACL entries changed since the last call.
250 count = (source_desc != -1
251 ? facl (source_desc, GETACLCNT, 0, NULL)
252 : acl (src_name, GETACLCNT, 0, NULL));
256 if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
272 entries = (aclent_t *) malloc (count * sizeof (aclent_t));
279 if ((source_desc != -1
280 ? facl (source_desc, GETACL, count, entries)
281 : acl (src_name, GETACL, count, entries))
284 /* Huh? The number of ACL entries changed since the last call.
288 /* Is there an ACL of either kind? */
293 return qset_acl (dst_name, dest_desc, mode);
295 did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
296 saved_errno = 0; /* the first non-ignorable error code */
298 if (!MODE_INSIDE_ACL)
300 /* On Cygwin, it is necessary to call chmod before acl, because
301 chmod can change the contents of the ACL (in ways that don't
302 change the allowed accesses, but still visible). */
303 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
308 /* If both ace_entries and entries are available, try SETACL before
309 ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
314 ret = (dest_desc != -1
315 ? facl (dest_desc, SETACL, count, entries)
316 : acl (dst_name, SETACL, count, entries));
317 if (ret < 0 && saved_errno == 0)
320 if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
321 && !acl_nontrivial (count, entries))
332 ret = (dest_desc != -1
333 ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries)
334 : acl (dst_name, ACE_SETACL, ace_count, ace_entries));
335 if (ret < 0 && saved_errno == 0)
338 if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
339 && !acl_ace_nontrivial (ace_count, ace_entries))
347 && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
349 /* We did not call chmod so far, and either the mode and the ACL are
350 separate or special bits are to be set which don't fit into ACLs. */
352 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
354 if (saved_errno == 0)
366 #elif USE_ACL && HAVE_GETACL /* HP-UX */
369 struct acl_entry entries[NACLENTRIES];
372 struct acl aclv_entries[NACLVENTRIES];
380 count = (source_desc != -1
381 ? fgetacl (source_desc, 0, NULL)
382 : getacl (src_name, 0, NULL));
386 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
398 if (count > NACLENTRIES)
399 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
402 if ((source_desc != -1
403 ? fgetacl (source_desc, count, entries)
404 : getacl (src_name, count, entries))
407 /* Huh? The number of ACL entries changed since the last call.
414 aclv_count = acl ((char *) src_name, ACL_CNT, NACLVENTRIES, aclv_entries);
418 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
430 if (aclv_count > NACLVENTRIES)
431 /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */
434 if (acl ((char *) src_name, ACL_GET, aclv_count, aclv_entries)
437 /* Huh? The number of ACL entries changed since the last call.
446 return qset_acl (dst_name, dest_desc, mode);
448 did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
449 saved_errno = 0; /* the first non-ignorable error code */
453 ret = (dest_desc != -1
454 ? fsetacl (dest_desc, count, entries)
455 : setacl (dst_name, count, entries));
456 if (ret < 0 && saved_errno == 0)
459 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
461 struct stat source_statbuf;
463 if ((source_desc != -1
464 ? fstat (source_desc, &source_statbuf)
465 : stat (src_name, &source_statbuf)) == 0)
467 if (!acl_nontrivial (count, entries, &source_statbuf))
481 ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries);
482 if (ret < 0 && saved_errno == 0)
485 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
487 if (!aclv_nontrivial (aclv_count, aclv_entries))
496 if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
498 /* We did not call chmod so far, and special bits are to be set which
499 don't fit into ACLs. */
501 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
503 if (saved_errno == 0)
515 #elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */
519 #elif USE_ACL && HAVE_STATACL /* older AIX */
521 union { struct acl a; char room[4096]; } u;
524 if ((source_desc != -1
525 ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u))
526 : statacl (src_name, STX_NORMAL, &u.a, sizeof (u)))
530 ret = (dest_desc != -1
531 ? fchacl (dest_desc, &u.a, u.a.acl_len)
532 : chacl (dst_name, &u.a, u.a.acl_len));
535 int saved_errno = errno;
537 chmod_or_fchmod (dst_name, dest_desc, mode);
542 /* No need to call chmod_or_fchmod at this point, since the mode bits
543 S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */
547 #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
550 struct acl entries[NACLENTRIES];
555 count = acl ((char *) src_name, ACL_CNT, NACLENTRIES, NULL);
571 if (count > NACLENTRIES)
572 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
575 if (acl ((char *) src_name, ACL_GET, count, entries) == count)
577 /* Huh? The number of ACL entries changed since the last call.
582 return qset_acl (dst_name, dest_desc, mode);
584 ret = acl ((char *) dst_name, ACL_SET, count, entries);
587 int saved_errno = errno;
591 if (!acl_nontrivial (count, entries))
592 return chmod_or_fchmod (dst_name, dest_desc, mode);
595 chmod_or_fchmod (dst_name, dest_desc, mode);
600 if (mode & (S_ISUID | S_ISGID | S_ISVTX))
602 /* We did not call chmod so far, and either the mode and the ACL are
603 separate or special bits are to be set which don't fit into ACLs. */
605 return chmod_or_fchmod (dst_name, dest_desc, mode);
611 return qset_acl (dst_name, dest_desc, mode);
617 /* Copy access control lists from one file to another. If SOURCE_DESC is
618 a valid file descriptor, use file descriptor operations, else use
619 filename based operations on SRC_NAME. Likewise for DEST_DESC and
621 If access control lists are not available, fchmod the target file to
622 MODE. Also sets the non-permission bits of the destination file
623 (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
624 Return 0 if successful, otherwise output a diagnostic and return a
625 negative error code. */
628 copy_acl (const char *src_name, int source_desc, const char *dst_name,
629 int dest_desc, mode_t mode)
631 int ret = qcopy_acl (src_name, source_desc, dst_name, dest_desc, mode);
635 error (0, errno, "%s", quote (src_name));
639 error (0, errno, _("preserving permissions for %s"), quote (dst_name));