X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fset-mode-acl.c;h=25a1eeee29510fb6d3e7d8a0c9ff9a02dbcd0ce2;hb=a177ce3f52a8bc2e08b4a95955e16501f91d086b;hp=d0fc6f8762bb067d517cf1e5e72914bd1b026a1c;hpb=389df9e59a5480871a42d147b42a2a09a9ce9dcd;p=gnulib.git diff --git a/lib/set-mode-acl.c b/lib/set-mode-acl.c index d0fc6f876..25a1eeee2 100644 --- a/lib/set-mode-acl.c +++ b/lib/set-mode-acl.c @@ -1,6 +1,6 @@ /* set-mode-acl.c - set access control list equivalent to a mode - Copyright (C) 2002-2003, 2005-2011 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2005-2012 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 @@ -197,7 +197,7 @@ qset_acl (char const *name, int desc, mode_t mode) return chmod_or_fchmod (name, desc, mode); # endif -# elif HAVE_FACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ +# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ int done_setacl = 0; @@ -214,47 +214,60 @@ qset_acl (char const *name, int desc, mode_t mode) int convention; { + /* 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; - ace_t *entries; for (;;) { - if (desc != -1) - count = facl (desc, ACE_GETACLCNT, 0, NULL); - else - count = acl (name, ACE_GETACLCNT, 0, NULL); - if (count <= 0) - { - convention = -1; - break; - } - entries = (ace_t *) malloc (count * sizeof (ace_t)); - if (entries == NULL) + count = (desc != -1 + ? facl (desc, ACE_GETACL, alloc, entries) + : acl (name, ACE_GETACL, alloc, entries)); + if (count < 0 && errno == ENOSPC) { - errno = ENOMEM; - 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 ((desc != -1 - ? facl (desc, ACE_GETACL, count, entries) - : acl (name, ACE_GETACL, count, entries)) - == count) - { - int i; + break; + } - convention = 0; - for (i = 0; i < count; i++) - if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER)) - { - convention = 1; - break; - } - free (entries); - break; - } - /* Huh? The number of ACL entries changed since the last call. - Repeat. */ - free (entries); + if (count <= 0) + convention = -1; + else + { + int i; + + convention = 0; + for (i = 0; i < count; i++) + if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER)) + { + convention = 1; + break; + } } + free (malloced); } if (convention >= 0) @@ -677,8 +690,8 @@ qset_acl (char const *name, int desc, mode_t mode) int set_acl (char const *name, int desc, mode_t mode) { - int r = qset_acl (name, desc, mode); - if (r != 0) + int ret = qset_acl (name, desc, mode); + if (ret != 0) error (0, errno, _("setting permissions for %s"), quote (name)); - return r; + return ret; }