/* 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
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;
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)
else
entries[2].a_access_mask |= NEW_ACE_EXECUTE;
entries[4].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
- entries[4].a_flags = ACE_EVERYONE;
+ entries[4].a_flags = NEW_ACE_EVERYONE;
entries[4].a_who = 0;
entries[4].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS
| NEW_ACE_WRITE_ATTRIBUTES
| NEW_ACE_WRITE_ACL
| NEW_ACE_WRITE_OWNER;
entries[5].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
- entries[5].a_flags = ACE_EVERYONE;
+ entries[5].a_flags = NEW_ACE_EVERYONE;
entries[5].a_who = 0;
entries[5].a_access_mask = NEW_ACE_READ_NAMED_ATTRS
| NEW_ACE_READ_ATTRIBUTES
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;
}