X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fcopy-acl.c;h=4f2ea06a6fffb7f14a786d8974cc0ccdbcbe3a14;hb=fb6aa6ad7dd950729f4e3349d89d4ad82761af61;hp=e8a4460f57359dbdcf2ecbbf8c84f1bf082f0574;hpb=7c2e36888a6f0d63557fc2b98a8c8f3d3cb73aa3;p=gnulib.git diff --git a/lib/copy-acl.c b/lib/copy-acl.c index e8a4460f5..4f2ea06a6 100644 --- a/lib/copy-acl.c +++ b/lib/copy-acl.c @@ -1,6 +1,6 @@ /* copy-acl.c - copy access control list from one file to another file - Copyright (C) 2002-2003, 2005-2010 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2005-2011 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -358,7 +358,7 @@ qcopy_acl (const char *src_name, int source_desc, const char *dst_name, if (ret < 0 && saved_errno == 0) { saved_errno = errno; - if ((errno == ENOSYS || errno == EOPNOTSUPP) + if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) && !acl_nontrivial (count, entries)) saved_errno = 0; } @@ -410,6 +410,12 @@ qcopy_acl (const char *src_name, int source_desc, const char *dst_name, int count; struct acl_entry entries[NACLENTRIES]; +# if HAVE_ACLV_H + int aclv_count; + struct acl aclv_entries[NACLVENTRIES]; +# endif + int did_chmod; + int saved_errno; int ret; for (;;) @@ -420,7 +426,7 @@ qcopy_acl (const char *src_name, int source_desc, const char *dst_name, if (count < 0) { - if (ACL_NOT_WELL_SUPPORTED (errno)) + if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) { count = 0; break; @@ -445,42 +451,107 @@ qcopy_acl (const char *src_name, int source_desc, const char *dst_name, Repeat. */ } - if (count == 0) - return qset_acl (dst_name, dest_desc, mode); - - ret = (dest_desc != -1 - ? fsetacl (dest_desc, count, entries) - : setacl (dst_name, count, entries)); - if (ret < 0) +# if HAVE_ACLV_H + for (;;) { - int saved_errno = errno; + aclv_count = acl ((char *) src_name, ACL_CNT, NACLVENTRIES, aclv_entries); - if (ACL_NOT_WELL_SUPPORTED (errno)) + if (aclv_count < 0) { - struct stat source_statbuf; - - if ((source_desc != -1 - ? fstat (source_desc, &source_statbuf) - : stat (src_name, &source_statbuf)) == 0) + if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) { - if (!acl_nontrivial (count, entries, &source_statbuf)) - return chmod_or_fchmod (dst_name, dest_desc, mode); + count = 0; + break; } else - saved_errno = errno; + return -2; } - chmod_or_fchmod (dst_name, dest_desc, mode); - errno = saved_errno; - return -1; + if (aclv_count == 0) + break; + + if (aclv_count > NACLVENTRIES) + /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */ + abort (); + + if (acl ((char *) src_name, ACL_GET, aclv_count, aclv_entries) + == aclv_count) + break; + /* Huh? The number of ACL entries changed since the last call. + Repeat. */ } +# endif - if (mode & (S_ISUID | S_ISGID | S_ISVTX)) + if (count == 0) +# if HAVE_ACLV_H + if (aclv_count == 0) +# endif + return qset_acl (dst_name, dest_desc, mode); + + did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */ + saved_errno = 0; /* the first non-ignorable error code */ + + if (count > 0) { - /* We did not call chmod so far, and either the mode and the ACL are - separate or special bits are to be set which don't fit into ACLs. */ + ret = (dest_desc != -1 + ? fsetacl (dest_desc, count, entries) + : setacl (dst_name, count, entries)); + if (ret < 0 && saved_errno == 0) + { + saved_errno = errno; + if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) + { + struct stat source_statbuf; + + if ((source_desc != -1 + ? fstat (source_desc, &source_statbuf) + : stat (src_name, &source_statbuf)) == 0) + { + if (!acl_nontrivial (count, entries, &source_statbuf)) + saved_errno = 0; + } + else + saved_errno = errno; + } + } + else + did_chmod = 1; + } - return chmod_or_fchmod (dst_name, dest_desc, mode); +# if HAVE_ACLV_H + if (aclv_count > 0) + { + ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries); + if (ret < 0 && saved_errno == 0) + { + saved_errno = errno; + if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) + { + if (!aclv_nontrivial (aclv_count, aclv_entries)) + saved_errno = 0; + } + } + else + did_chmod = 1; + } +# endif + + if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0)) + { + /* We did not call chmod so far, and special bits are to be set which + don't fit into ACLs. */ + + if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) + { + if (saved_errno == 0) + saved_errno = errno; + } + } + + if (saved_errno) + { + errno = saved_errno; + return -1; } return 0;