X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Ffile-has-acl.c;h=53ac317c0ba854903da29d75450a2c706e31dbea;hb=e7086a9a301ffcfef17edbcba9e7c0312c33f7a8;hp=2d4531b74d9db77f5cc434c56e9d0a5a69f5ffe7;hpb=ec10a26aea109e60b185b026a84d68d4ebb50952;p=gnulib.git diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index 2d4531b74..53ac317c0 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -1,6 +1,6 @@ /* Test whether a file has a nontrivial access control list. - Copyright (C) 2002-2003, 2005-2012 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2005-2013 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 @@ -32,7 +32,7 @@ #if USE_ACL && HAVE_ACL_GET_FILE -# if HAVE_ACL_TYPE_EXTENDED /* MacOS X */ +# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */ /* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED. Return 1 if the given ACL is non-trivial. @@ -75,8 +75,7 @@ acl_access_nontrivial (acl_t acl) } return got_one; -# else /* IRIX, Tru64 */ -# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */ +# elif HAVE_ACL_TO_SHORT_TEXT /* IRIX */ /* Don't use acl_get_entry: it is undocumented. */ int count = acl->acl_cnt; @@ -93,8 +92,7 @@ acl_access_nontrivial (acl_t acl) } return 0; -# endif -# if HAVE_ACL_FREE_TEXT /* Tru64 */ +# elif HAVE_ACL_FREE_TEXT /* Tru64 */ /* Don't use acl_get_entry: it takes only one argument and does not work. */ int count = acl->acl_num; @@ -117,7 +115,10 @@ acl_access_nontrivial (acl_t acl) } return 0; -# endif +# else + + errno = ENOSYS; + return -1; # endif } @@ -489,7 +490,7 @@ file_has_acl (char const *name, struct stat const *sb) # if HAVE_ACL_GET_FILE /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ - /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */ + /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ int ret; if (HAVE_ACL_EXTENDED_FILE) /* Linux */ @@ -499,10 +500,10 @@ file_has_acl (char const *name, struct stat const *sb) ACL_TYPE_DEFAULT. */ ret = acl_extended_file (name); } - else /* FreeBSD, MacOS X, IRIX, Tru64 */ + else /* FreeBSD, Mac OS X, IRIX, Tru64 */ { -# if HAVE_ACL_TYPE_EXTENDED /* MacOS X */ - /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS) +# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */ + /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS) and acl_get_file (name, ACL_TYPE_DEFAULT) always return NULL / EINVAL. There is no point in making these two useless calls. The real ACL is retrieved through @@ -553,10 +554,10 @@ file_has_acl (char const *name, struct stat const *sb) # endif } if (ret < 0) - return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1; + return - acl_errno_valid (errno); return ret; -# elif HAVE_FACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ +# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ # if defined ACL_NO_TRIVIAL @@ -570,75 +571,135 @@ file_has_acl (char const *name, struct stat const *sb) /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions of Unixware. The acl() call returns the access and default ACL both at once. */ - int count; { - aclent_t *entries; + /* Initially, try to read the entries into a stack-allocated buffer. + Use malloc if it does not fit. */ + enum + { + alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */ + alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t)) + }; + aclent_t buf[alloc_init]; + size_t alloc = alloc_init; + aclent_t *entries = buf; + aclent_t *malloced = NULL; + int count; for (;;) { - count = acl (name, GETACLCNT, 0, NULL); - - if (count < 0) + count = acl (name, GETACL, alloc, entries); + if (count < 0 && errno == ENOSPC) { - if (errno == ENOSYS || errno == ENOTSUP) - break; - else - return -1; + /* Increase the size of the buffer. */ + free (malloced); + if (alloc > alloc_max / 2) + { + errno = ENOMEM; + return -1; + } + alloc = 2 * alloc; /* <= alloc_max */ + entries = malloced = + (aclent_t *) malloc (alloc * sizeof (aclent_t)); + if (entries == NULL) + { + errno = ENOMEM; + return -1; + } + continue; } - - if (count == 0) - break; - + break; + } + if (count < 0) + { + if (errno == ENOSYS || errno == ENOTSUP) + ; + else + { + int saved_errno = errno; + free (malloced); + errno = saved_errno; + return -1; + } + } + else if (count == 0) + ; + else + { /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin returns only 3 entries for files with no ACL. But this is safe: If there are more than 4 entries, there cannot be only the "user::", "group::", "other:", and "mask:" entries. */ if (count > 4) - return 1; - - entries = (aclent_t *) malloc (count * sizeof (aclent_t)); - if (entries == NULL) { - errno = ENOMEM; - return -1; + free (malloced); + return 1; } - if (acl (name, GETACL, count, entries) == count) + + if (acl_nontrivial (count, entries)) { - if (acl_nontrivial (count, entries)) - { - free (entries); - return 1; - } - free (entries); - break; + free (malloced); + return 1; } - /* Huh? The number of ACL entries changed since the last call. - Repeat. */ - free (entries); } + free (malloced); } # ifdef ACE_GETACL /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 file systems (whereas the other ones are used in UFS file systems). */ { - ace_t *entries; + /* Initially, try to read the entries into a stack-allocated buffer. + Use malloc if it does not fit. */ + enum + { + alloc_init = 4000 / sizeof (ace_t), /* >= 3 */ + alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t)) + }; + ace_t buf[alloc_init]; + size_t alloc = alloc_init; + ace_t *entries = buf; + ace_t *malloced = NULL; + int count; for (;;) { - count = acl (name, ACE_GETACLCNT, 0, NULL); - - if (count < 0) + count = acl (name, ACE_GETACL, alloc, entries); + if (count < 0 && errno == ENOSPC) { - if (errno == ENOSYS || errno == EINVAL) - break; - else - return -1; + /* Increase the size of the buffer. */ + free (malloced); + if (alloc > alloc_max / 2) + { + errno = ENOMEM; + return -1; + } + alloc = 2 * alloc; /* <= alloc_max */ + entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t)); + if (entries == NULL) + { + errno = ENOMEM; + return -1; + } + continue; } - - if (count == 0) - break; - + break; + } + if (count < 0) + { + if (errno == ENOSYS || errno == EINVAL) + ; + else + { + int saved_errno = errno; + free (malloced); + errno = saved_errno; + return -1; + } + } + else if (count == 0) + ; + else + { /* In the old (original Solaris 10) convention: If there are more than 3 entries, there cannot be only the ACE_OWNER, ACE_GROUP, ACE_OTHER entries. @@ -648,28 +709,18 @@ file_has_acl (char const *name, struct stat const *sb) NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with NEW_ACE_ACCESS_DENIED_ACE_TYPE. */ if (count > 6) - return 1; - - entries = (ace_t *) malloc (count * sizeof (ace_t)); - if (entries == NULL) { - errno = ENOMEM; - return -1; + free (malloced); + return 1; } - if (acl (name, ACE_GETACL, count, entries) == count) + + if (acl_ace_nontrivial (count, entries)) { - if (acl_ace_nontrivial (count, entries)) - { - free (entries); - return 1; - } - free (entries); - break; + free (malloced); + return 1; } - /* Huh? The number of ACL entries changed since the last call. - Repeat. */ - free (entries); } + free (malloced); } # endif @@ -678,38 +729,36 @@ file_has_acl (char const *name, struct stat const *sb) # elif HAVE_GETACL /* HP-UX */ - for (;;) - { - int count; - struct acl_entry entries[NACLENTRIES]; - - count = getacl (name, 0, NULL); - - if (count < 0) - { - /* ENOSYS is seen on newer HP-UX versions. - EOPNOTSUPP is typically seen on NFS mounts. - ENOTSUP was seen on Quantum StorNext file systems (cvfs). */ - if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) - break; - else - return -1; - } - - if (count == 0) - return 0; + { + struct acl_entry entries[NACLENTRIES]; + int count; - if (count > NACLENTRIES) - /* If NACLENTRIES cannot be trusted, use dynamic memory - allocation. */ - abort (); + count = getacl (name, NACLENTRIES, entries); - /* If there are more than 3 entries, there cannot be only the - (uid,%), (%,gid), (%,%) entries. */ - if (count > 3) - return 1; + if (count < 0) + { + /* ENOSYS is seen on newer HP-UX versions. + EOPNOTSUPP is typically seen on NFS mounts. + ENOTSUP was seen on Quantum StorNext file systems (cvfs). */ + if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) + ; + else + return -1; + } + else if (count == 0) + return 0; + else /* count > 0 */ + { + if (count > NACLENTRIES) + /* If NACLENTRIES cannot be trusted, use dynamic memory + allocation. */ + abort (); + + /* If there are more than 3 entries, there cannot be only the + (uid,%), (%,gid), (%,%) entries. */ + if (count > 3) + return 1; - if (getacl (name, count, entries) == count) { struct stat statbuf; @@ -718,47 +767,43 @@ file_has_acl (char const *name, struct stat const *sb) return acl_nontrivial (count, entries, &statbuf); } - /* Huh? The number of ACL entries changed since the last call. - Repeat. */ - } + } + } # if HAVE_ACLV_H /* HP-UX >= 11.11 */ - for (;;) - { - int count; - struct acl entries[NACLVENTRIES]; - - count = acl ((char *) name, ACL_CNT, NACLVENTRIES, entries); - - if (count < 0) - { - /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23. - EINVAL is seen on NFS in HP-UX 11.31. */ - if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) - break; - else - return -1; - } + { + struct acl entries[NACLVENTRIES]; + int count; - if (count == 0) - return 0; + count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries); - if (count > NACLVENTRIES) - /* If NACLVENTRIES cannot be trusted, use dynamic memory - allocation. */ - abort (); + if (count < 0) + { + /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23. + EINVAL is seen on NFS in HP-UX 11.31. */ + if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) + ; + else + return -1; + } + else if (count == 0) + return 0; + else /* count > 0 */ + { + if (count > NACLVENTRIES) + /* If NACLVENTRIES cannot be trusted, use dynamic memory + allocation. */ + abort (); - /* If there are more than 4 entries, there cannot be only the - four base ACL entries. */ - if (count > 4) - return 1; + /* If there are more than 4 entries, there cannot be only the + four base ACL entries. */ + if (count > 4) + return 1; - if (acl ((char *) name, ACL_GET, count, entries) == count) return aclv_nontrivial (count, entries); - /* Huh? The number of ACL entries changed since the last call. - Repeat. */ - } + } + } # endif @@ -835,39 +880,36 @@ file_has_acl (char const *name, struct stat const *sb) # elif HAVE_ACLSORT /* NonStop Kernel */ - int count; - struct acl entries[NACLENTRIES]; - - for (;;) - { - count = acl ((char *) name, ACL_CNT, NACLENTRIES, NULL); - - if (count < 0) - { - if (errno == ENOSYS || errno == ENOTSUP) - break; - else - return -1; - } + { + struct acl entries[NACLENTRIES]; + int count; - if (count == 0) - return 0; + count = acl ((char *) name, ACL_GET, NACLENTRIES, entries); - if (count > NACLENTRIES) - /* If NACLENTRIES cannot be trusted, use dynamic memory - allocation. */ - abort (); + if (count < 0) + { + if (errno == ENOSYS || errno == ENOTSUP) + ; + else + return -1; + } + else if (count == 0) + return 0; + else /* count > 0 */ + { + if (count > NACLENTRIES) + /* If NACLENTRIES cannot be trusted, use dynamic memory + allocation. */ + abort (); - /* If there are more than 4 entries, there cannot be only the - four base ACL entries. */ - if (count > 4) - return 1; + /* If there are more than 4 entries, there cannot be only the + four base ACL entries. */ + if (count > 4) + return 1; - if (acl ((char *) name, ACL_GET, count, entries) == count) return acl_nontrivial (count, entries); - /* Huh? The number of ACL entries changed since the last call. - Repeat. */ - } + } + } # endif }