Merge from gnulib

This incorporates:
2015-05-27 qacl: Reimplement qset_acl and qcopy_acl (Bug#20666)
2015-05-27 file-has-acl: Split feature tests again (Bug#20667)
2015-05-27 string: fix build failure on BSD/OSX with FORTIFY_SOURCE
2015-05-26 stdio: limit __gnu_printf__ witness to gcc 4.4+
2015-05-26 inttypes: force correct mingw PRIdMAX even without <stdio.h>
2015-05-26 stdio: fix probe on mingw under gcc 5.1
* admin/merge-gnulib (GNULIB_MODULES):
Replace qacl with qcopy-acl, since we don't need the rest of qacl.
* doc/misc/texinfo.tex, lib/acl-internal.c, lib/acl-internal.h:
* lib/inttypes.in.h, lib/qcopy-acl.c, lib/qset-acl.c:
* lib/string.in.h, m4/acl.m4, m4/stdio_h.m4:
Get latest versions from gnulib.
* lib/get-permissions.c, lib/set-permissions.c: New files.
* lib/gnulib.mk, m4/gnulib-comp.m4:
Regenerate.
* nt/gnulib.mk: Merge lib/gnulib.mk changes by hand.
This commit is contained in:
Paul Eggert 2015-05-27 17:46:15 -07:00
parent cc41938ae0
commit 6c52e9b93b
14 changed files with 936 additions and 920 deletions

View file

@ -34,7 +34,7 @@ GNULIB_MODULES='
getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog
intprops largefile lstat
manywarnings memrchr mkostemp mktime
pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat
pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat
sig2str socklen stat-time stdalign stddef stdio
stpcpy strftime strtoimax strtoumax symlink sys_stat
sys_time time time_r timer-time timespec-add timespec-sub

View file

@ -3,7 +3,7 @@
% Load plain if necessary, i.e., if running under initex.
\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
%
\def\texinfoversion{2015-05-06.11}
\def\texinfoversion{2015-05-26.15}
%
% Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995,
% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
@ -8954,7 +8954,6 @@
\catcode\count255=#1\relax
\advance\count255 by 1
\repeat
}
% @documentencoding sets the definition of non-ASCII characters

View file

@ -467,3 +467,34 @@ acl_nontrivial (int count, struct acl *entries)
}
#endif
void
free_permission_context (struct permission_context *ctx)
{
#ifdef USE_ACL
# if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
if (ctx->acl)
acl_free (ctx->acl);
# if !HAVE_ACL_TYPE_EXTENDED
if (ctx->default_acl)
acl_free (ctx->default_acl);
# endif
# elif defined GETACL /* Solaris, Cygwin */
free (ctx->entries);
# ifdef ACE_GETACL
free (ctx->ace_entries);
# endif
# elif HAVE_GETACL /* HP-UX */
# if HAVE_ACLV_H
# endif
# elif HAVE_STATACL /* older AIX */
# elif HAVE_ACLSORT /* NonStop Kernel */
# endif
#endif
}

View file

@ -133,12 +133,9 @@ rpl_acl_set_fd (int fd, acl_t acl)
# define acl_from_mode(mode) (NULL)
# endif
/* Set to 1 if a file's mode is implicit by the ACL.
Set to 0 if a file's mode is stored independently from the ACL. */
/* Set to 0 if a file's mode is stored independently from the ACL. */
# if (HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP) || defined __sgi /* Mac OS X, IRIX */
# define MODE_INSIDE_ACL 0
# else
# define MODE_INSIDE_ACL 1
# endif
/* Return the number of entries in ACL.
@ -164,12 +161,9 @@ extern int acl_access_nontrivial (acl_t);
# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
/* Set to 1 if a file's mode is implicit by the ACL.
Set to 0 if a file's mode is stored independently from the ACL. */
/* Set to 0 if a file's mode is stored independently from the ACL. */
# if defined __CYGWIN__ /* Cygwin */
# define MODE_INSIDE_ACL 0
# else /* Solaris */
# define MODE_INSIDE_ACL 1
# endif
/* Return 1 if the given ACL is non-trivial.
@ -248,6 +242,53 @@ extern int acl_nontrivial (int count, struct acl *entries);
# endif
/* Set to 1 if a file's mode is implicit by the ACL. */
# ifndef MODE_INSIDE_ACL
# define MODE_INSIDE_ACL 1
# endif
#endif
struct permission_context {
mode_t mode;
#ifdef USE_ACL
# if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
acl_t acl;
# if !HAVE_ACL_TYPE_EXTENDED
acl_t default_acl;
# endif
bool acls_not_supported;
# elif defined GETACL /* Solaris, Cygwin */
int count;
aclent_t *entries;
# ifdef ACE_GETACL
int ace_count;
ace_t *ace_entries;
# endif
# elif HAVE_GETACL /* HP-UX */
struct acl_entry entries[NACLENTRIES];
int count;
# if HAVE_ACLV_H
struct acl aclv_entries[NACLVENTRIES];
int aclv_count;
# endif
# elif HAVE_STATACL /* older AIX */
union { struct acl a; char room[4096]; } u;
bool have_u;
# elif HAVE_ACLSORT /* NonStop Kernel */
struct acl entries[NACLENTRIES];
int count;
# endif
#endif
};
int get_permissions (const char *, int, mode_t, struct permission_context *);
int set_permissions (struct permission_context *, const char *, int);
void free_permission_context (struct permission_context *);
_GL_INLINE_HEADER_END

280
lib/get-permissions.c Normal file
View file

@ -0,0 +1,280 @@
/* get-permissions.c - get permissions of a file
Copyright (C) 2002-2003, 2005-2015 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
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
#include <config.h>
#include <string.h>
#include "acl.h"
#include "acl-internal.h"
/* Read the permissions of a file into CTX. If DESC is a valid file descriptor,
use file descriptor operations, else use filename based operations on NAME.
MODE is the file mode obtained from a previous stat call.
Return 0 if successful. Return -1 and set errno upon failure. */
int
get_permissions (const char *name, int desc, mode_t mode,
struct permission_context *ctx)
{
memset (ctx, 0, sizeof(*ctx));
ctx->mode = mode;
#if USE_ACL && HAVE_ACL_GET_FILE
/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
/* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
# if !HAVE_ACL_TYPE_EXTENDED
/* Linux, FreeBSD, IRIX, Tru64 */
if (HAVE_ACL_GET_FD && desc != -1)
ctx->acl = acl_get_fd (desc);
else
ctx->acl = acl_get_file (name, ACL_TYPE_ACCESS);
if (ctx->acl == NULL)
return acl_errno_valid (errno) ? -1 : 0;
/* With POSIX ACLs, a file cannot have "no" acl; a file without
extended permissions has a "minimal" acl which is equivalent to the
file mode. */
if (S_ISDIR (mode))
{
ctx->default_acl = acl_get_file (name, ACL_TYPE_DEFAULT);
if (ctx->default_acl == NULL)
return -1;
}
# else /* 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. You have to use
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)
have the same effect as
acl_set_file (name, ACL_TYPE_EXTENDED, acl):
Each of these calls sets the file's ACL. */
if (HAVE_ACL_GET_FD && desc != -1)
ctx->acl = acl_get_fd (desc);
else
ctx->acl = acl_get_file (name, ACL_TYPE_EXTENDED);
if (ctx->acl == NULL)
return acl_errno_valid (errno) ? -1 : 0;
# endif
#elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
/* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
of Unixware. The acl() call returns the access and default ACL both
at once. */
# 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).
There is an API
pathconf (name, _PC_ACL_ENABLED)
fpathconf (desc, _PC_ACL_ENABLED)
that allows to determine which of the two kinds of ACLs is supported
for the given file. But some file systems may implement this call
incorrectly, so better not use it.
When fetching the source ACL, we simply fetch both ACL types.
When setting the destination ACL, we try either ACL types, assuming
that the kernel will translate the ACL from one form to the other.
(See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
the description of ENOTSUP.) */
for (;;)
{
int ret;
if (desc != -1)
ret = facl (desc, ACE_GETACLCNT, 0, NULL);
else
ret = acl (name, ACE_GETACLCNT, 0, NULL);
if (ret < 0)
{
if (errno == ENOSYS || errno == EINVAL)
ret = 0;
else
return -1;
}
ctx->ace_count = ret;
if (ctx->ace_count == 0)
break;
ctx->ace_entries = (ace_t *) malloc (ctx->ace_count * sizeof (ace_t));
if (ctx->ace_entries == NULL)
{
errno = ENOMEM;
return -1;
}
if (desc != -1)
ret = facl (desc, ACE_GETACL, ctx->ace_count, ctx->ace_entries);
else
ret = acl (name, ACE_GETACL, ctx->ace_count, ctx->ace_entries);
if (ret < 0)
{
if (errno == ENOSYS || errno == EINVAL)
{
free (ctx->ace_entries);
ctx->ace_entries = NULL;
ctx->ace_count = 0;
break;
}
else
return -1;
}
if (ret <= ctx->ace_count)
{
ctx->ace_count = ret;
break;
}
/* Huh? The number of ACL entries has increased since the last call.
Repeat. */
free (ctx->ace_entries);
ctx->ace_entries = NULL;
}
# endif
for (;;)
{
int ret;
if (desc != -1)
ret = facl (desc, GETACLCNT, 0, NULL);
else
ret = acl (name, GETACLCNT, 0, NULL);
if (ret < 0)
{
if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
ret = 0;
else
return -1;
}
ctx->count = ret;
if (ctx->count == 0)
break;
ctx->entries = (aclent_t *) malloc (ctx->count * sizeof (aclent_t));
if (ctx->entries == NULL)
{
errno = ENOMEM;
return -1;
}
if (desc != -1)
ret = facl (desc, GETACL, ctx->count, ctx->entries);
else
ret = acl (name, GETACL, ctx->count, ctx->entries);
if (ret < 0)
{
if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
{
free (ctx->entries);
ctx->entries = NULL;
ctx->count = 0;
break;
}
else
return -1;
}
if (ret <= ctx->count)
{
ctx->count = ret;
break;
}
/* Huh? The number of ACL entries has increased since the last call.
Repeat. */
free (ctx->entries);
ctx->entries = NULL;
}
#elif USE_ACL && HAVE_GETACL /* HP-UX */
int ret;
if (desc != -1)
ret = fgetacl (desc, NACLENTRIES, ctx->entries);
else
ret = getacl (name, NACLENTRIES, ctx->entries);
if (ret < 0)
{
if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
ret = 0;
else
return -1;
}
else if (ret > NACLENTRIES)
/* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
abort ();
ctx->count = ret;
# if HAVE_ACLV_H
ret = acl ((char *) name, ACL_GET, NACLVENTRIES, ctx->aclv_entries);
if (ret < 0)
{
if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
ret = 0;
else
return -2;
}
else if (ret > NACLVENTRIES)
/* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */
abort ();
ctx->aclv_count = ret;
# endif
#elif USE_ACL && HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */
/* TODO (see set_permissions). */
#elif USE_ACL && HAVE_STATACL /* older AIX */
if (desc != -1)
ret = fstatacl (desc, STX_NORMAL, &ctx->u.a, sizeof (ctx->u));
else
ret = statacl (name, STX_NORMAL, &ctx->u.a, sizeof (ctx->u));
if (ret == 0)
ctx->have_u = true;
#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
int ret;
ret = acl ((char *) name, ACL_GET, NACLENTRIES, ctx->entries);
if (ret < 0)
return -1;
else if (ret > NACLENTRIES)
/* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
abort ();
ctx->count = ret;
#endif
return 0;
}

View file

@ -21,7 +21,7 @@
# the same distribution terms as the rest of that program.
#
# Generated by gnulib-tool.
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings
MOSTLYCLEANFILES += core *.stackdump
@ -42,6 +42,17 @@ HAVE_INCLUDE_NEXT = (__GNUC__ || 60000000 <= __DECC_VER)
## end gnulib module absolute-header
## begin gnulib module acl-permissions
libgnu_a_SOURCES += acl-errno-valid.c acl-internal.c \
get-permissions.c set-permissions.c
EXTRA_DIST += acl-internal.h acl.h acl_entries.c
EXTRA_libgnu_a_SOURCES += acl_entries.c
## end gnulib module acl-permissions
## begin gnulib module alloca-opt
BUILT_SOURCES += $(ALLOCA_H)
@ -696,15 +707,11 @@ EXTRA_libgnu_a_SOURCES += putenv.c
## end gnulib module putenv
## begin gnulib module qacl
## begin gnulib module qcopy-acl
libgnu_a_SOURCES += acl-errno-valid.c acl-internal.c qcopy-acl.c qset-acl.c
libgnu_a_SOURCES += qcopy-acl.c
EXTRA_DIST += acl-internal.h acl.h acl_entries.c
EXTRA_libgnu_a_SOURCES += acl_entries.c
## end gnulib module qacl
## end gnulib module qcopy-acl
## begin gnulib module readlink

View file

@ -51,6 +51,10 @@
#endif
/* Get CHAR_BIT. */
#include <limits.h>
/* On mingw, __USE_MINGW_ANSI_STDIO only works if <stdio.h> is also included */
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
# include <stdio.h>
#endif
#if !(INT_MIN == INT32_MIN && INT_MAX == INT32_MAX)
# error "This file assumes that 'int' has exactly 32 bits. Please report your platform and compiler to <bug-gnulib@gnu.org>."

View file

@ -39,534 +39,13 @@ int
qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
int dest_desc, mode_t mode)
{
#if USE_ACL && HAVE_ACL_GET_FILE
/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
/* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
# if !HAVE_ACL_TYPE_EXTENDED
/* Linux, FreeBSD, IRIX, Tru64 */
acl_t acl;
struct permission_context ctx;
int ret;
if (HAVE_ACL_GET_FD && source_desc != -1)
acl = acl_get_fd (source_desc);
else
acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
if (acl == NULL)
{
if (! acl_errno_valid (errno))
return qset_acl (dst_name, dest_desc, mode);
else
return -2;
}
if (HAVE_ACL_SET_FD && dest_desc != -1)
ret = acl_set_fd (dest_desc, acl);
else
ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
ret = get_permissions (src_name, source_desc, mode, &ctx);
if (ret != 0)
{
int saved_errno = errno;
if (! acl_errno_valid (errno) && !acl_access_nontrivial (acl))
{
acl_free (acl);
return chmod_or_fchmod (dst_name, dest_desc, mode);
}
else
{
acl_free (acl);
chmod_or_fchmod (dst_name, dest_desc, mode);
errno = saved_errno;
return -1;
}
}
else
acl_free (acl);
if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
{
/* 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. */
if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
return -1;
}
if (S_ISDIR (mode))
{
acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
if (acl == NULL)
return -2;
if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
{
int saved_errno = errno;
acl_free (acl);
errno = saved_errno;
return -1;
}
else
acl_free (acl);
}
return 0;
# else /* 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. You have to use
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)
have the same effect as
acl_set_file (name, ACL_TYPE_EXTENDED, acl):
Each of these calls sets the file's ACL. */
acl_t acl;
int ret;
if (HAVE_ACL_GET_FD && source_desc != -1)
acl = acl_get_fd (source_desc);
else
acl = acl_get_file (src_name, ACL_TYPE_EXTENDED);
if (acl == NULL)
{
if (!acl_errno_valid (errno))
return qset_acl (dst_name, dest_desc, mode);
else
return -2;
}
if (HAVE_ACL_SET_FD && dest_desc != -1)
ret = acl_set_fd (dest_desc, acl);
else
ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl);
if (ret != 0)
{
int saved_errno = errno;
if (!acl_errno_valid (saved_errno) && !acl_extended_nontrivial (acl))
{
acl_free (acl);
return chmod_or_fchmod (dst_name, dest_desc, mode);
}
else
{
acl_free (acl);
chmod_or_fchmod (dst_name, dest_desc, mode);
errno = saved_errno;
return -1;
}
}
else
acl_free (acl);
/* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
return chmod_or_fchmod (dst_name, dest_desc, mode);
# endif
#elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
/* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
of Unixware. The acl() call returns the access and default ACL both
at once. */
# ifdef ACE_GETACL
int ace_count;
ace_t *ace_entries;
# endif
int count;
aclent_t *entries;
int did_chmod;
int saved_errno;
int ret;
# 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).
There is an API
pathconf (name, _PC_ACL_ENABLED)
fpathconf (desc, _PC_ACL_ENABLED)
that allows to determine which of the two kinds of ACLs is supported
for the given file. But some file systems may implement this call
incorrectly, so better not use it.
When fetching the source ACL, we simply fetch both ACL types.
When setting the destination ACL, we try either ACL types, assuming
that the kernel will translate the ACL from one form to the other.
(See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
the description of ENOTSUP.) */
for (;;)
{
ace_count = (source_desc != -1
? facl (source_desc, ACE_GETACLCNT, 0, NULL)
: acl (src_name, ACE_GETACLCNT, 0, NULL));
if (ace_count < 0)
{
if (errno == ENOSYS || errno == EINVAL)
{
ace_count = 0;
ace_entries = NULL;
break;
}
else
return -2;
}
if (ace_count == 0)
{
ace_entries = NULL;
break;
}
ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t));
if (ace_entries == NULL)
{
errno = ENOMEM;
return -2;
}
ret = (source_desc != -1
? facl (source_desc, ACE_GETACL, ace_count, ace_entries)
: acl (src_name, ACE_GETACL, ace_count, ace_entries));
if (ret < 0)
{
free (ace_entries);
if (errno == ENOSYS || errno == EINVAL)
{
ace_count = 0;
ace_entries = NULL;
break;
}
else
return -2;
}
if (ret == ace_count)
break;
/* Huh? The number of ACL entries changed since the last call.
Repeat. */
}
# endif
for (;;)
{
count = (source_desc != -1
? facl (source_desc, GETACLCNT, 0, NULL)
: acl (src_name, GETACLCNT, 0, NULL));
if (count < 0)
{
if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
{
count = 0;
entries = NULL;
break;
}
else
return -2;
}
if (count == 0)
{
entries = NULL;
break;
}
entries = (aclent_t *) malloc (count * sizeof (aclent_t));
if (entries == NULL)
{
errno = ENOMEM;
return -2;
}
if ((source_desc != -1
? facl (source_desc, GETACL, count, entries)
: acl (src_name, GETACL, count, entries))
== count)
break;
/* Huh? The number of ACL entries changed since the last call.
Repeat. */
}
/* Is there an ACL of either kind? */
# ifdef ACE_GETACL
if (ace_count == 0)
# endif
if (count == 0)
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 (!MODE_INSIDE_ACL)
{
/* On Cygwin, it is necessary to call chmod before acl, because
chmod can change the contents of the ACL (in ways that don't
change the allowed accesses, but still visible). */
if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
saved_errno = errno;
did_chmod = 1;
}
/* If both ace_entries and entries are available, try SETACL before
ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
can. */
if (count > 0)
{
ret = (dest_desc != -1
? facl (dest_desc, SETACL, count, entries)
: acl (dst_name, SETACL, count, entries));
if (ret < 0 && saved_errno == 0)
{
saved_errno = errno;
if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
&& !acl_nontrivial (count, entries))
saved_errno = 0;
}
else
did_chmod = 1;
}
free (entries);
# ifdef ACE_GETACL
if (ace_count > 0)
{
ret = (dest_desc != -1
? facl (dest_desc, ACE_SETACL, ace_count, ace_entries)
: acl (dst_name, ACE_SETACL, ace_count, ace_entries));
if (ret < 0 && saved_errno == 0)
{
saved_errno = errno;
if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
&& !acl_ace_nontrivial (ace_count, ace_entries))
saved_errno = 0;
}
}
free (ace_entries);
# endif
if (MODE_INSIDE_ACL
&& did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 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. */
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;
#elif USE_ACL && HAVE_GETACL /* HP-UX */
struct acl_entry entries[NACLENTRIES];
int count;
# if HAVE_ACLV_H
struct acl aclv_entries[NACLVENTRIES];
int aclv_count;
# endif
int did_chmod;
int saved_errno;
int ret;
count = (source_desc != -1
? fgetacl (source_desc, NACLENTRIES, entries)
: getacl (src_name, NACLENTRIES, entries));
if (count < 0)
{
if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
count = 0;
else
return -2;
}
else if (count > 0)
{
if (count > NACLENTRIES)
/* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
abort ();
}
# if HAVE_ACLV_H
aclv_count = acl ((char *) src_name, ACL_GET, NACLVENTRIES, aclv_entries);
if (aclv_count < 0)
{
if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
count = 0;
else
return -2;
}
else if (aclv_count > 0)
{
if (aclv_count > NACLVENTRIES)
/* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */
abort ();
}
# endif
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)
{
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
&& !acl_nontrivial (count, entries))
saved_errno = 0;
}
else
did_chmod = 1;
}
# 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;
#elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */
/* TODO */
#elif USE_ACL && HAVE_STATACL /* older AIX */
union { struct acl a; char room[4096]; } u;
int ret;
if ((source_desc != -1
? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u))
: statacl (src_name, STX_NORMAL, &u.a, sizeof (u)))
< 0)
return -2;
ret = (dest_desc != -1
? fchacl (dest_desc, &u.a, u.a.acl_len)
: chacl (dst_name, &u.a, u.a.acl_len));
if (ret < 0)
{
int saved_errno = errno;
chmod_or_fchmod (dst_name, dest_desc, mode);
errno = saved_errno;
return -1;
}
/* No need to call chmod_or_fchmod at this point, since the mode bits
S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */
return 0;
#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
struct acl entries[NACLENTRIES];
int count;
int ret;
count = acl ((char *) src_name, ACL_GET, NACLENTRIES, entries);
if (count < 0)
{
if (0)
count = 0;
else
return -2;
}
else if (count > 0)
{
if (count > NACLENTRIES)
/* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
abort ();
}
if (count == 0)
return qset_acl (dst_name, dest_desc, mode);
ret = acl ((char *) dst_name, ACL_SET, count, entries);
if (ret < 0)
{
int saved_errno = errno;
if (0)
{
if (!acl_nontrivial (count, entries))
return chmod_or_fchmod (dst_name, dest_desc, mode);
}
chmod_or_fchmod (dst_name, dest_desc, mode);
errno = saved_errno;
return -1;
}
if (mode & (S_ISUID | S_ISGID | S_ISVTX))
{
/* 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 (dst_name, dest_desc, mode);
}
return 0;
#else
return qset_acl (dst_name, dest_desc, mode);
#endif
ret = set_permissions (&ctx, dst_name, dest_desc);
free_permission_context (&ctx);
return ret;
}

View file

@ -1,4 +1,4 @@
/* qset-acl.c - set access control list equivalent to a mode
/* set-permissions.c - set permissions of a file
Copyright (C) 2002-2003, 2005-2015 Free Software Foundation, Inc.
@ -15,182 +15,43 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Written by Paul Eggert and Andreas Gruenbacher, and Bruno Haible. */
Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
#include <config.h>
#define ACL_INTERNAL_INLINE _GL_EXTERN_INLINE
#include "acl.h"
#include "acl-internal.h"
/* If DESC is a valid file descriptor use fchmod to change the
file's mode to MODE on systems that have fchmod. On systems
that don't have fchmod and if DESC is invalid, use chmod on
NAME instead.
Return 0 if successful. Return -1 and set errno upon failure. */
int
chmod_or_fchmod (const char *name, int desc, mode_t mode)
{
if (HAVE_FCHMOD && desc != -1)
return fchmod (desc, mode);
else
return chmod (name, mode);
}
/* Set the access control lists of a file. If DESC is a valid file
descriptor, use file descriptor operations where available, else use
filename based operations on NAME. If access control lists are not
available, fchmod the target file to MODE. Also sets the
non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX)
to those from MODE if any are set.
Return 0 if successful. Return -1 and set errno upon failure. */
int
qset_acl (char const *name, int desc, mode_t mode)
{
#if USE_ACL
# if HAVE_ACL_GET_FILE
/* POSIX 1003.1e draft 17 (abandoned) specific version. */
/* 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.
(acl_delete_def_file could be emulated with acl_init followed
by acl_set_file, but acl_set_file with an empty acl is
unspecified.) */
# ifndef HAVE_ACL_FROM_TEXT
# error Must have acl_from_text (see POSIX 1003.1e draft 17).
# endif
# ifndef HAVE_ACL_DELETE_DEF_FILE
# error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
# endif
acl_t acl;
int ret;
if (HAVE_ACL_FROM_MODE) /* Linux */
{
acl = acl_from_mode (mode);
if (!acl)
return -1;
}
else /* FreeBSD, IRIX, Tru64 */
{
/* If we were to create the ACL using the functions acl_init(),
acl_create_entry(), acl_set_tag_type(), acl_set_qualifier(),
acl_get_permset(), acl_clear_perm[s](), acl_add_perm(), we
would need to create a qualifier. I don't know how to do this.
So create it using acl_from_text(). */
# if HAVE_ACL_FREE_TEXT /* Tru64 */
char acl_text[] = "u::---,g::---,o::---,";
# else /* FreeBSD, IRIX */
char acl_text[] = "u::---,g::---,o::---";
# endif
if (mode & S_IRUSR) acl_text[ 3] = 'r';
if (mode & S_IWUSR) acl_text[ 4] = 'w';
if (mode & S_IXUSR) acl_text[ 5] = 'x';
if (mode & S_IRGRP) acl_text[10] = 'r';
if (mode & S_IWGRP) acl_text[11] = 'w';
if (mode & S_IXGRP) acl_text[12] = 'x';
if (mode & S_IROTH) acl_text[17] = 'r';
if (mode & S_IWOTH) acl_text[18] = 'w';
if (mode & S_IXOTH) acl_text[19] = 'x';
acl = acl_from_text (acl_text);
if (!acl)
return -1;
}
if (HAVE_ACL_SET_FD && desc != -1)
ret = acl_set_fd (desc, acl);
else
ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
if (ret != 0)
{
int saved_errno = errno;
acl_free (acl);
if (! acl_errno_valid (errno))
return chmod_or_fchmod (name, desc, mode);
errno = saved_errno;
return -1;
}
else
acl_free (acl);
if (S_ISDIR (mode) && acl_delete_def_file (name))
return -1;
if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
{
/* 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 /* 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. You have to use
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)
have the same effect as
acl_set_file (name, ACL_TYPE_EXTENDED, acl):
Each of these calls sets the file's ACL. */
acl_t acl;
int ret;
/* Remove the ACL if the file has ACLs. */
if (HAVE_ACL_GET_FD && desc != -1)
acl = acl_get_fd (desc);
else
acl = acl_get_file (name, ACL_TYPE_EXTENDED);
if (acl)
{
acl_free (acl);
acl = acl_init (0);
if (acl)
{
if (HAVE_ACL_SET_FD && desc != -1)
ret = acl_set_fd (desc, acl);
else
ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl);
if (ret != 0)
{
int saved_errno = errno;
acl_free (acl);
if (! acl_errno_valid (saved_errno))
return chmod_or_fchmod (name, desc, mode);
errno = saved_errno;
return -1;
}
acl_free (acl);
}
}
/* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
return chmod_or_fchmod (name, desc, mode);
# if ! defined HAVE_ACL_FROM_MODE && defined HAVE_ACL_FROM_TEXT /* FreeBSD, IRIX, Tru64 */
static acl_t
acl_from_mode (mode_t mode)
{
# if HAVE_ACL_FREE_TEXT /* Tru64 */
char acl_text[] = "u::---,g::---,o::---,";
# else /* FreeBSD, IRIX */
char acl_text[] = "u::---,g::---,o::---";
# endif
# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
if (mode & S_IRUSR) acl_text[ 3] = 'r';
if (mode & S_IWUSR) acl_text[ 4] = 'w';
if (mode & S_IXUSR) acl_text[ 5] = 'x';
if (mode & S_IRGRP) acl_text[10] = 'r';
if (mode & S_IWGRP) acl_text[11] = 'w';
if (mode & S_IXGRP) acl_text[12] = 'x';
if (mode & S_IROTH) acl_text[17] = 'r';
if (mode & S_IWOTH) acl_text[18] = 'w';
if (mode & S_IXOTH) acl_text[19] = 'x';
int done_setacl = 0;
return acl_from_text (acl_text);
}
# endif
# if HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
static int
set_acls_from_mode (const char *name, int desc, mode_t mode, bool *must_chmod)
{
# 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). */
@ -365,53 +226,53 @@ qset_acl (char const *name, int desc, mode_t mode)
if (ret < 0 && errno != EINVAL && errno != ENOTSUP)
{
if (errno == ENOSYS)
return chmod_or_fchmod (name, desc, mode);
{
*must_chmod = true;
return 0;
}
return -1;
}
if (ret == 0)
done_setacl = 1;
return 0;
}
# endif
if (!done_setacl)
{
aclent_t entries[3];
int ret;
{
aclent_t entries[3];
int ret;
entries[0].a_type = USER_OBJ;
entries[0].a_id = 0; /* irrelevant */
entries[0].a_perm = (mode >> 6) & 7;
entries[1].a_type = GROUP_OBJ;
entries[1].a_id = 0; /* irrelevant */
entries[1].a_perm = (mode >> 3) & 7;
entries[2].a_type = OTHER_OBJ;
entries[2].a_id = 0;
entries[2].a_perm = mode & 7;
entries[0].a_type = USER_OBJ;
entries[0].a_id = 0; /* irrelevant */
entries[0].a_perm = (mode >> 6) & 7;
entries[1].a_type = GROUP_OBJ;
entries[1].a_id = 0; /* irrelevant */
entries[1].a_perm = (mode >> 3) & 7;
entries[2].a_type = OTHER_OBJ;
entries[2].a_id = 0;
entries[2].a_perm = mode & 7;
if (desc != -1)
ret = facl (desc, SETACL,
sizeof (entries) / sizeof (aclent_t), entries);
else
ret = acl (name, SETACL,
sizeof (entries) / sizeof (aclent_t), entries);
if (ret < 0)
{
if (errno == ENOSYS || errno == EOPNOTSUPP)
return chmod_or_fchmod (name, desc, mode);
return -1;
}
}
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. */
return chmod_or_fchmod (name, desc, mode);
}
return 0;
# elif HAVE_GETACL /* HP-UX */
if (desc != -1)
ret = facl (desc, SETACL,
sizeof (entries) / sizeof (aclent_t), entries);
else
ret = acl (name, SETACL,
sizeof (entries) / sizeof (aclent_t), entries);
if (ret < 0)
{
if (errno == ENOSYS || errno == EOPNOTSUPP)
{
*must_chmod = true;
return 0;
}
return -1;
}
}
}
#elif HAVE_GETACL /* HP-UX */
static int
context_acl_from_mode (struct permission_context *ctx, const char *name, int desc)
{
struct stat statbuf;
int ret;
@ -422,87 +283,60 @@ qset_acl (char const *name, int desc, mode_t mode)
if (ret < 0)
return -1;
{
struct acl_entry entries[3];
entries[0].uid = statbuf.st_uid;
entries[0].gid = ACL_NSGROUP;
entries[0].mode = (mode >> 6) & 7;
entries[1].uid = ACL_NSUSER;
entries[1].gid = statbuf.st_gid;
entries[1].mode = (mode >> 3) & 7;
entries[2].uid = ACL_NSUSER;
entries[2].gid = ACL_NSGROUP;
entries[2].mode = mode & 7;
if (desc != -1)
ret = fsetacl (desc, sizeof (entries) / sizeof (struct acl_entry), entries);
else
ret = setacl (name, sizeof (entries) / sizeof (struct acl_entry), entries);
}
if (ret < 0)
{
if (!(errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
return -1;
ctx->entries[0].uid = statbuf.st_uid;
ctx->entries[0].gid = ACL_NSGROUP;
ctx->entries[0].mode = (mode >> 6) & 7;
ctx->entries[1].uid = ACL_NSUSER;
ctx->entries[1].gid = statbuf.st_gid;
ctx->entries[1].mode = (mode >> 3) & 7;
ctx->entries[2].uid = ACL_NSUSER;
ctx->entries[2].gid = ACL_NSGROUP;
ctx->entries[2].mode = mode & 7;
ctx->count = 3;
return 0;
}
# if HAVE_ACLV_H /* HP-UX >= 11.11 */
{
struct acl entries[4];
static int
context_aclv_from_mode (struct permission_context *ctx)
{
int ret;
entries[0].a_type = USER_OBJ;
entries[0].a_id = 0; /* irrelevant */
entries[0].a_perm = (mode >> 6) & 7;
entries[1].a_type = GROUP_OBJ;
entries[1].a_id = 0; /* irrelevant */
entries[1].a_perm = (mode >> 3) & 7;
entries[2].a_type = CLASS_OBJ;
entries[2].a_id = 0;
entries[2].a_perm = (mode >> 3) & 7;
entries[3].a_type = OTHER_OBJ;
entries[3].a_id = 0;
entries[3].a_perm = mode & 7;
ctx->aclv_entries[0].a_type = USER_OBJ;
ctx->aclv_entries[0].a_id = 0; /* irrelevant */
ctx->aclv_entries[0].a_perm = (mode >> 6) & 7;
ctx->aclv_entries[1].a_type = GROUP_OBJ;
ctx->aclv_entries[1].a_id = 0; /* irrelevant */
ctx->aclv_entries[1].a_perm = (mode >> 3) & 7;
ctx->aclv_entries[2].a_type = CLASS_OBJ;
ctx->aclv_entries[2].a_id = 0;
ctx->aclv_entries[2].a_perm = (mode >> 3) & 7;
ctx->aclv_entries[3].a_type = OTHER_OBJ;
ctx->aclv_entries[3].a_id = 0;
ctx->aclv_entries[3].a_perm = mode & 7;
ctx->aclv_count = 4;
ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries);
if (ret > 0)
abort ();
if (ret < 0)
{
if (0)
return chmod_or_fchmod (name, desc, mode);
return -1;
}
ret = acl ((char *) name, ACL_SET,
sizeof (entries) / sizeof (struct acl), entries);
if (ret < 0)
{
if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
return chmod_or_fchmod (name, desc, mode);
return -1;
}
}
# else
return chmod_or_fchmod (name, desc, mode);
# endif
}
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;
ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries);
if (ret > 0)
abort ();
return ret;
}
#endif
# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
static int
set_acls_from_mode (const char *name, int desc, mode_t mode, bool *must_chmod)
{
acl_type_list_t types;
size_t types_size = sizeof (types);
acl_type_t type;
if (aclx_gettypes (name, &types, &types_size) < 0
|| types.num_entries == 0)
return chmod_or_fchmod (name, desc, mode);
{
*must_chmod = true;
return 0;
}
/* XXX Do we need to clear all types of ACLs for the given file, or is it
sufficient to clear the first one? */
@ -599,78 +433,401 @@ qset_acl (char const *name, int desc, mode_t mode)
return ret;
}
return chmod_or_fchmod (name, desc, mode);
*must_chmod = true;
return 0;
}
# elif HAVE_STATACL /* older AIX */
union { struct acl a; char room[128]; } u;
int ret;
u.a.acl_len = (char *) &u.a.acl_ext[0] - (char *) &u.a; /* no entries */
u.a.acl_mode = mode & ~(S_IXACL | 0777);
u.a.u_access = (mode >> 6) & 7;
u.a.g_access = (mode >> 3) & 7;
u.a.o_access = mode & 7;
if (desc != -1)
ret = fchacl (desc, &u.a, u.a.acl_len);
else
ret = chacl (name, &u.a, u.a.acl_len);
if (ret < 0 && errno == ENOSYS)
return chmod_or_fchmod (name, desc, mode);
return ret;
static int
context_acl_from_mode (struct permission_context *ctx)
{
ctx->u.a.acl_len = (char *) &ctx->u.a.acl_ext[0] - (char *) &ctx->u.a; /* no entries */
ctx->u.a.acl_mode = ctx->mode & ~(S_IXACL | 0777);
ctx->u.a.u_access = (ctx->mode >> 6) & 7;
ctx->u.a.g_access = (ctx->mode >> 3) & 7;
ctx->u.a.o_access = ctx->mode & 7;
ctx->have_u = true;
return 0;
}
# elif HAVE_ACLSORT /* NonStop Kernel */
struct acl entries[4];
static int
context_acl_from_mode (struct permission_context *ctx)
{
int ret;
entries[0].a_type = USER_OBJ;
entries[0].a_id = 0; /* irrelevant */
entries[0].a_perm = (mode >> 6) & 7;
entries[1].a_type = GROUP_OBJ;
entries[1].a_id = 0; /* irrelevant */
entries[1].a_perm = (mode >> 3) & 7;
entries[2].a_type = CLASS_OBJ;
entries[2].a_id = 0;
entries[2].a_perm = (mode >> 3) & 7;
entries[3].a_type = OTHER_OBJ;
entries[3].a_id = 0;
entries[3].a_perm = mode & 7;
ctx->entries[0].a_type = USER_OBJ;
ctx->entries[0].a_id = 0; /* irrelevant */
ctx->entries[0].a_perm = (mode >> 6) & 7;
ctx->entries[1].a_type = GROUP_OBJ;
ctx->entries[1].a_id = 0; /* irrelevant */
ctx->entries[1].a_perm = (mode >> 3) & 7;
ctx->entries[2].a_type = CLASS_OBJ;
ctx->entries[2].a_id = 0;
ctx->entries[2].a_perm = (mode >> 3) & 7;
ctx->entries[3].a_type = OTHER_OBJ;
ctx->entries[3].a_id = 0;
ctx->entries[3].a_perm = mode & 7;
ctx->count = 4;
ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries);
if (ret > 0)
abort ();
if (ret < 0)
{
if (0)
return chmod_or_fchmod (name, desc, mode);
return -1;
}
ret = acl ((char *) name, ACL_SET,
sizeof (entries) / sizeof (struct acl), entries);
if (ret < 0)
{
if (0)
return chmod_or_fchmod (name, desc, mode);
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 /* Unknown flavor of ACLs */
return chmod_or_fchmod (name, desc, mode);
# endif
#else /* !USE_ACL */
return chmod_or_fchmod (name, desc, mode);
#endif
return ret;
}
# endif
static int
set_acls (struct permission_context *ctx, const char *name, int desc,
int from_mode, bool *must_chmod, bool *acls_set)
{
int ret = 0;
#if HAVE_ACL_GET_FILE
/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
/* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
# if !HAVE_ACL_TYPE_EXTENDED
/* Linux, FreeBSD, IRIX, Tru64 */
# ifndef HAVE_ACL_FROM_TEXT
# error Must have acl_from_text (see POSIX 1003.1e draft 17).
# endif
# ifndef HAVE_ACL_DELETE_DEF_FILE
# error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
# endif
if (! ctx->acls_not_supported)
{
if (ret == 0 && from_mode)
{
if (ctx->acl)
acl_free (ctx->acl);
ctx->acl = acl_from_mode (ctx->mode);
if (ctx->acl == NULL)
ret = -1;
}
if (ret == 0 && ctx->acl)
{
if (HAVE_ACL_SET_FD && desc != -1)
ret = acl_set_fd (desc, ctx->acl);
else
ret = acl_set_file (name, ACL_TYPE_ACCESS, ctx->acl);
if (ret != 0)
{
if (! acl_errno_valid (errno))
{
ctx->acls_not_supported = true;
if (from_mode || acl_access_nontrivial (ctx->acl) == 0)
ret = 0;
}
}
else
{
*acls_set = true;
if (S_ISDIR(ctx->mode))
{
if (! from_mode && ctx->default_acl)
ret = acl_set_file (name, ACL_TYPE_DEFAULT,
ctx->default_acl);
else
ret = acl_delete_def_file (name);
}
}
}
}
# else /* 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. You have to use
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)
have the same effect as
acl_set_file (name, ACL_TYPE_EXTENDED, acl):
Each of these calls sets the file's ACL. */
if (ctx->acl == NULL)
{
acl_t acl;
/* Remove ACLs if the file has ACLs. */
if (HAVE_ACL_GET_FD && desc != -1)
acl = acl_get_fd (desc);
else
acl = acl_get_file (name, ACL_TYPE_EXTENDED);
if (acl)
{
acl_free (acl);
acl = acl_init (acl);
if (acl)
{
if (HAVE_ACL_SET_FD && desc != -1)
ret = acl_set_fd (desc, acl);
else
ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl);
acl_free (acl);
}
else
ret = -1;
}
}
else
{
if (HAVE_ACL_SET_FD && desc != -1)
ret = acl_set_fd (desc, acl);
else
ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl);
if (ret != 0)
{
if (! acl_errno_valid (saved_errno) && ! acl_extended_nontrivial (acl))
ret = 0;
}
}
*acls_set = true;
# endif
# elif defined GETACL /* Solaris, Cygwin, not HP-UX */
/* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
of Unixware. The acl() call returns the access and default ACL both
at once. */
/* If both ace_entries and entries are available, try SETACL before
ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
can. */
if (from_mode)
return set_acls_from_mode (name, desc, ctx->mode, must_chmod);
if (ret == 0 && ctx->count)
{
if (desc != -1)
ret = facl (desc, SETACL, count, entries);
else
ret = acl (name, SETACL, count, entries);
if (ret < 0)
{
if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
&& acl_nontrivial (count, entries) == 0)
ret = 0;
}
else
*acls_set = true;
}
# ifdef ACE_GETACL
if (ret == 0 && ctx->ace_count)
{
if (desc != -1)
ret = facl (desc, ACE_SETACL, ace_count, ace_entries);
else
ret = acl (name, ACE_SETACL, ace_count, ace_entries);
if (ret < 0)
{
if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
&& acl_ace_nontrivial (ace_count, ace_entries) == 0)
ret = 0;
}
else
*acls_set = true;
}
# endif
#elif HAVE_GETACL /* HP-UX */
if (from_mode)
ret = context_acl_from_mode (ctx, name, desc);
if (ret == 0 && ctx->count > 0)
{
if (desc != -1)
ret = fsetacl (desc, ctx->count, ctx->entries);
else
ret = setacl (name, ctx->count, ctx->entries);
if (ret < 0)
{
if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
&& (from_mode || !acl_nontrivial (ctx->count, ctx->entries, &source_statbuf)))
ret = 0;
}
else
*acls_set = true;
}
# if HAVE_ACLV_H
if (from_mode)
ret = context_aclv_from_mode (ctx);
if (ret == 0 && ctx->aclv_count > 0)
{
ret = acl ((char *) name, ACL_SET, ctx->aclv_count, ctx->aclv_entries);
if (ret < 0)
{
if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
&& (from_mode || !aclv_nontrivial (ctx->aclv_count, ctx->aclv_entries)))
ret = 0;
}
else
*acls_set = true;
}
# endif
# elif HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */
/* TODO: Implement setting ACLs once get_permissions() reads them. */
if (from_mode)
ret = set_acls_from_mode (name, desc, mode, must_chmod);
# elif HAVE_STATACL /* older AIX */
if (from_mode)
ret = context_acl_from_mode (ctx);
if (ret == 0 && ctx->have_u)
{
if (desc != -1)
ret = fchacl (desc, &u.a, u.a.acl_len);
else
ret = chacl (name, &u.a, u.a.acl_len);
if (ret < 0)
{
if (errno == ENOSYS && from_mode)
ret = 0;
}
else
*acls_set = true;
}
# elif HAVE_ACLSORT /* NonStop Kernel */
if (from_mode)
ret = context_acl_from_mode (ctx);
if (ret == 0 && ctx->count)
{
ret = acl ((char *) name, ACL_SET, ctx->count, ctx->entries);
if (ret != 0)
{
if (!acl_nontrivial (ctx->count, ctx->entries))
ret = 0;
}
else
*acls_set = true;
}
# else /* No ACLs */
/* Nothing to do. */
#endif
return ret;
}
#endif
/* If DESC is a valid file descriptor use fchmod to change the
file's mode to MODE on systems that have fchmod. On systems
that don't have fchmod and if DESC is invalid, use chmod on
NAME instead.
Return 0 if successful. Return -1 and set errno upon failure. */
int
chmod_or_fchmod (const char *name, int desc, mode_t mode)
{
if (HAVE_FCHMOD && desc != -1)
return fchmod (desc, mode);
else
return chmod (name, mode);
}
/* Set the permissions in CTX on a file. If DESC is a valid file descriptor,
use file descriptor operations, else use filename based operations on NAME.
If access control lists are not available, fchmod the target file to the
mode in CTX. Also sets the non-permission bits of the destination file
(S_ISUID, S_ISGID, S_ISVTX) to those from the mode in CTX if any are set.
Return 0 if successful. Return -1 and set errno upon failure. */
int
set_permissions (struct permission_context *ctx, const char *name, int desc)
{
bool acls_set _GL_UNUSED = false;
bool early_chmod;
bool must_chmod = false;
int ret = 0;
#if USE_ACL
# if HAVE_STATACL
/* older AIX */
/* There is no need to call chmod_or_fchmod, since the mode
bits S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */
early_chmod = false;
# else
/* All other plaforms */
/* On Cygwin, it is necessary to call chmod before acl, because
chmod can change the contents of the ACL (in ways that don't
change the allowed accesses, but still visible). */
early_chmod = (! MODE_INSIDE_ACL || (ctx->mode & (S_ISUID | S_ISGID | S_ISVTX)));
# endif
#else
/* No ACLs */
early_chmod = true;
#endif
if (early_chmod)
{
ret = chmod_or_fchmod (name, desc, ctx->mode);
if (ret != 0)
return -1;
}
#if USE_ACL
ret = set_acls (ctx, name, desc, false, &must_chmod, &acls_set);
if (! acls_set)
{
int saved_errno = ret ? errno : 0;
/* If we can't set an acl which we expect to be able to set, try setting
the permissions to ctx->mode. Doe to possible inherited permissions,
we cannot simply chmod. */
acls_set = false;
ret = set_acls (ctx, name, desc, true, &must_chmod, &acls_set);
if (! acls_set)
must_chmod = true;
if (saved_errno)
{
errno = saved_errno;
ret = -1;
}
}
#endif
if (must_chmod && ! early_chmod)
{
int saved_errno = ret ? errno : 0;
ret = chmod_or_fchmod (name, desc, ctx->mode);
if (saved_errno)
{
errno = saved_errno;
ret = -1;
}
}
return ret;
}

View file

@ -15,16 +15,32 @@
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>. */
#ifndef _@GUARD_PREFIX@_STRING_H
#if __GNUC__ >= 3
@PRAGMA_SYSTEM_HEADER@
#endif
@PRAGMA_COLUMNS@
#if defined _GL_ALREADY_INCLUDING_STRING_H
/* Special invocation convention:
- On OS X/NetBSD we have a sequence of nested includes
<string.h> -> <strings.h> -> "string.h"
In this situation system _chk variants due to -D_FORTIFY_SOURCE
might be used after any replacements defined here. */
#@INCLUDE_NEXT@ @NEXT_STRING_H@
#else
/* Normal invocation convention. */
#ifndef _@GUARD_PREFIX@_STRING_H
#define _GL_ALREADY_INCLUDING_STRING_H
/* The include_next requires a split double-inclusion guard. */
#@INCLUDE_NEXT@ @NEXT_STRING_H@
#undef _GL_ALREADY_INCLUDING_STRING_H
#ifndef _@GUARD_PREFIX@_STRING_H
#define _@GUARD_PREFIX@_STRING_H
@ -1027,3 +1043,4 @@ _GL_WARN_ON_USE (strverscmp, "strverscmp is unportable - "
#endif /* _@GUARD_PREFIX@_STRING_H */
#endif /* _@GUARD_PREFIX@_STRING_H */
#endif

View file

@ -1,5 +1,5 @@
# acl.m4 - check for access control list (ACL) primitives
# serial 19
# serial 20
# Copyright (C) 2002, 2004-2015 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
@ -181,26 +181,12 @@ AC_DEFUN([gl_FILE_HAS_ACL],
[
AC_REQUIRE([gl_FUNC_ACL_ARG])
if test "$enable_acl" != no; then
AC_CACHE_CHECK([for getxattr with XATTR_NAME_POSIX_ACL macros],
[gl_cv_getxattr_with_posix_acls],
[gl_cv_getxattr_with_posix_acls=no
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[#include <sys/types.h>
#include <sys/xattr.h>
#include <linux/xattr.h>
]],
[[ssize_t a = getxattr (".", XATTR_NAME_POSIX_ACL_ACCESS, 0, 0);
ssize_t b = getxattr (".", XATTR_NAME_POSIX_ACL_DEFAULT, 0, 0);
return a < 0 || b < 0;
]])],
[gl_cv_getxattr_with_posix_acls=yes])])
AC_CHECK_HEADERS([linux/xattr.h])
AC_CHECK_HEADERS([sys/xattr.h],
[AC_CHECK_FUNCS([getxattr])])
fi
if test "$gl_cv_getxattr_with_posix_acls" = yes; then
if test "$ac_cv_header_sys_xattr_h,$ac_cv_func_getxattr" = yes,yes; then
LIB_HAS_ACL=
AC_DEFINE([GETXATTR_WITH_POSIX_ACLS], 1,
[Define to 1 if getxattr works with XATTR_NAME_POSIX_ACL_ACCESS
and XATTR_NAME_POSIX_ACL_DEFAULT.])
else
dnl Set gl_need_lib_has_acl to a nonempty value, so that any
dnl later gl_FUNC_ACL call will set LIB_HAS_ACL=$LIB_ACL.

View file

@ -39,6 +39,7 @@ AC_DEFUN([gl_EARLY],
m4_pattern_allow([^gl_LTLIBOBJS$])dnl a variable
AC_REQUIRE([gl_PROG_AR_RANLIB])
# Code from module absolute-header:
# Code from module acl-permissions:
# Code from module alloca-opt:
# Code from module allocator:
# Code from module at-internal:
@ -105,7 +106,7 @@ AC_DEFUN([gl_EARLY],
# Code from module pselect:
# Code from module pthread_sigmask:
# Code from module putenv:
# Code from module qacl:
# Code from module qcopy-acl:
# Code from module readlink:
# Code from module readlinkat:
# Code from module root-uid:
@ -172,6 +173,7 @@ AC_DEFUN([gl_INIT],
m4_pushdef([gl_LIBSOURCES_DIR], [])
gl_COMMON
gl_source_base='lib'
gl_FUNC_ACL
gl_FUNC_ALLOCA
gl_BYTESWAP
AC_CHECK_FUNCS_ONCE([readlinkat])
@ -317,7 +319,6 @@ AC_DEFUN([gl_INIT],
gl_PREREQ_PUTENV
fi
gl_STDLIB_MODULE_INDICATOR([putenv])
gl_FUNC_ACL
gl_FUNC_READLINK
if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then
AC_LIBOBJ([readlink])
@ -865,6 +866,7 @@ AC_DEFUN([gl_FILE_LIST], [
lib/fsync.c
lib/ftoastr.c
lib/ftoastr.h
lib/get-permissions.c
lib/getdtablesize.c
lib/getgroups.c
lib/getloadavg.c
@ -895,11 +897,11 @@ AC_DEFUN([gl_FILE_LIST], [
lib/pthread_sigmask.c
lib/putenv.c
lib/qcopy-acl.c
lib/qset-acl.c
lib/readlink.c
lib/readlinkat.c
lib/root-uid.h
lib/secure_getenv.c
lib/set-permissions.c
lib/sha1.c
lib/sha1.h
lib/sha256.c

View file

@ -1,4 +1,4 @@
# stdio_h.m4 serial 44
# stdio_h.m4 serial 46
dnl Copyright (C) 2007-2015 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@ -15,15 +15,21 @@ AC_DEFUN([gl_STDIO_H],
dnl Determine whether __USE_MINGW_ANSI_STDIO makes printf and
dnl inttypes.h behave like gnu instead of system; we must give our
dnl printf wrapper the right attribute to match.
AC_CACHE_CHECK([whether inttypes macros match system or gnu printf],
AC_CACHE_CHECK([which flavor of printf attribute matches inttypes macros],
[gl_cv_func_printf_attribute_flavor],
[AC_EGREP_CPP([findme .(ll|j)d. findme],
[#define __STDC_FORMAT_MACROS 1
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#define __STDC_FORMAT_MACROS 1
#include <stdio.h>
#include <inttypes.h>
findme PRIdMAX findme
], [gl_cv_func_printf_attribute_flavor=gnu],
[gl_cv_func_printf_attribute_flavor=system])])
/* For non-mingw systems, compilation will trivially succeed.
For mingw, compilation will succeed for older mingw (system
printf, "I64d") and fail for newer mingw (gnu printf, "lld"). */
#if ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__) && \
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))
extern char PRIdMAX_probe[sizeof PRIdMAX == sizeof "I64d" ? 1 : -1];
#endif
]])], [gl_cv_func_printf_attribute_flavor=system],
[gl_cv_func_printf_attribute_flavor=gnu])])
if test "$gl_cv_func_printf_attribute_flavor" = gnu; then
AC_DEFINE([GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU], [1],
[Define to 1 if printf and friends should be labeled with

View file

@ -43,7 +43,7 @@
# the same distribution terms as the rest of that program.
#
# Generated by gnulib-tool.
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings
MOSTLYCLEANFILES += core *.stackdump
@ -64,6 +64,17 @@ HAVE_INCLUDE_NEXT = (__GNUC__ || 60000000 <= __DECC_VER)
## end gnulib module absolute-header
## begin gnulib module acl-permissions
libgnu_a_SOURCES += acl-errno-valid.c acl-internal.c \
get-permissions.c set-permissions.c
EXTRA_DIST += acl-internal.h acl.h acl_entries.c
EXTRA_libgnu_a_SOURCES += acl_entries.c
## end gnulib module acl-permissions
## begin gnulib module alloca-opt
BUILT_SOURCES += $(ALLOCA_H)
@ -521,15 +532,11 @@ EXTRA_libgnu_a_SOURCES += putenv.c
## end gnulib module putenv
## begin gnulib module qacl
## begin gnulib module qcopy-acl
libgnu_a_SOURCES += acl-errno-valid.c acl-internal.c qcopy-acl.c
libgnu_a_SOURCES += qcopy-acl.c
EXTRA_DIST += acl-internal.h acl.h acl_entries.c
EXTRA_libgnu_a_SOURCES += acl_entries.c
## end gnulib module qacl
## end gnulib module qcopy-acl
## begin gnulib module readlink