/* 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
#include <config.h>
+#define ACL_INTERNAL_INLINE _GL_EXTERN_INLINE
+
#include "acl.h"
#include "acl-internal.h"
#if USE_ACL
# if HAVE_ACL_GET_FILE
/* POSIX 1003.1e draft 17 (abandoned) specific version. */
- /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
-# if MODE_INSIDE_ACL
+ /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
+# if !HAVE_ACL_TYPE_EXTENDED
/* Linux, FreeBSD, IRIX, Tru64 */
/* We must also have acl_from_text and acl_delete_def_file.
if (S_ISDIR (mode) && acl_delete_def_file (name))
return -1;
- if (mode & (S_ISUID | S_ISGID | S_ISVTX))
+ if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
{
- /* We did not call chmod so far, so the special bits have not yet
- been set. */
+ /* 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. */
return chmod_or_fchmod (name, desc, mode);
}
return 0;
-# else /* !MODE_INSIDE_ACL */
- /* MacOS X */
-
-# if !HAVE_ACL_TYPE_EXTENDED
-# error Must have ACL_TYPE_EXTENDED
-# endif
+# else /* HAVE_ACL_TYPE_EXTENDED */
+ /* Mac OS X */
- /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
- and acl_get_file (name, ACL_TYPE_DEFAULT)
+ /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
+ and acl_get_file (name, ACL_TYPE_DEFAULT)
always return NULL / EINVAL. You have to use
- acl_get_file (name, ACL_TYPE_EXTENDED)
- or acl_get_fd (open (name, ...))
+ acl_get_file (name, ACL_TYPE_EXTENDED)
+ or acl_get_fd (open (name, ...))
to retrieve an ACL.
On the other hand,
- acl_set_file (name, ACL_TYPE_ACCESS, acl)
- and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
+ acl_set_file (name, ACL_TYPE_ACCESS, acl)
+ and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
have the same effect as
- acl_set_file (name, ACL_TYPE_EXTENDED, acl):
+ acl_set_file (name, ACL_TYPE_EXTENDED, acl):
Each of these calls sets the file's ACL. */
acl_t acl;
return chmod_or_fchmod (name, desc, mode);
# endif
-# elif HAVE_FACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */
-
-# if defined ACL_NO_TRIVIAL && 0
- /* Solaris 10 (newer version), which has additional API declared in
- <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
- acl_fromtext, ...). */
-
- acl_t *aclp;
- char acl_text[] = "user::---,group::---,mask:---,other:---";
- int ret;
- int saved_errno;
-
- if (mode & S_IRUSR) acl_text[ 6] = 'r';
- if (mode & S_IWUSR) acl_text[ 7] = 'w';
- if (mode & S_IXUSR) acl_text[ 8] = 'x';
- if (mode & S_IRGRP) acl_text[17] = acl_text[26] = 'r';
- if (mode & S_IWGRP) acl_text[18] = acl_text[27] = 'w';
- if (mode & S_IXGRP) acl_text[19] = acl_text[28] = 'x';
- if (mode & S_IROTH) acl_text[36] = 'r';
- if (mode & S_IWOTH) acl_text[37] = 'w';
- if (mode & S_IXOTH) acl_text[38] = 'x';
-
- if (acl_fromtext (acl_text, &aclp) != 0)
- {
- errno = ENOMEM;
- return -1;
- }
-
- ret = (desc < 0 ? acl_set (name, aclp) : facl_set (desc, aclp));
- saved_errno = errno;
- acl_free (aclp);
- if (ret < 0)
- {
- if (saved_errno == ENOSYS || saved_errno == EOPNOTSUPP)
- return chmod_or_fchmod (name, desc, mode);
- errno = saved_errno;
- return -1;
- }
-
- if (mode & (S_ISUID | S_ISGID | S_ISVTX))
- {
- /* We did not call chmod so far, so the special bits have not yet
- been set. */
- return chmod_or_fchmod (name, desc, mode);
- }
- return 0;
-
-# else /* Solaris, Cygwin, general case */
+# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
int done_setacl = 0;
-# ifdef ACE_GETACL
+# 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). */
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)
+ count = (desc != -1
+ ? facl (desc, ACE_GETACL, alloc, entries)
+ : acl (name, ACE_GETACL, alloc, entries));
+ if (count < 0 && errno == ENOSPC)
{
- convention = -1;
- break;
+ /* 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;
}
- entries = (ace_t *) malloc (count * sizeof (ace_t));
- if (entries == NULL)
- {
- errno = ENOMEM;
- return -1;
- }
- 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)
{
/* Running on Solaris 10 (newer version) or Solaris 11.
The details here were found through "/bin/ls -lvd somefiles". */
- struct stat statbuf;
- int dir;
-
- if ((desc != -1 ? fstat (desc, &statbuf) : stat (name, &statbuf)) >= 0)
- dir = S_ISDIR (statbuf.st_mode);
- else
- dir = 0;
-
entries[0].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
entries[0].a_flags = NEW_ACE_OWNER;
entries[0].a_who = 0; /* irrelevant */
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
if (ret == 0)
done_setacl = 1;
}
-# endif
+# endif
if (!done_setacl)
{
}
return 0;
-# endif
-
# elif HAVE_GETACL /* HP-UX */
struct stat statbuf;
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;
}