Use Gnulib ACL implementation, for benefit of Solaris etc.
* configure.ac: Remove -with-acl option, since Gnulib does that for us now. (LIBACL_LIBS): Remove; no longer needed. * lib/Makefile.am (CLEANFILES, SUFFIXES): New (empty) macros, for the benefit of the new ACL implementation. * lib/makefile.w32-in (GNULIBOBJS): Add $(BLD)/acl-errno-valid.$(O). ($(BLD)/acl-errno-valid.$(O)): New rule. * lib/acl-errno-valid.c, lib/acl-internal.h, lib/acl.h: * lib/acl_entries.c, lib/errno.in.h, lib/file-has-acl.c: * lib/qcopy-acl.c, lib/qset-acl.c, m4/acl.m4, m4/errno_h.m4: New files, taken from gnulib. * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. * admin/merge-gnulib (GNULIB_MODULES): Add qacl. (GNULIB_TOOL_FLAGS): Do not avoid errno. * etc/NEWS: Emacs is no longer limited to POSIX ACLs. --disable-acl, not --without-acl, since we're now using Gnulib's implementation. * nt/config.nt (HAVE_ACL_SET_FILE): Rename from HAVE_POSIX_ACL. * nt/inc/ms-w32.h (EOPNOTSUPP): New macro. * src/Makefile.in (LIB_ACL): New macro. (LIBACL_LIBS): Remove. (LIBES): Use LIB_ACL, not LIBACL_LIBS. * src/fileio.c: Include <acl.h>. Use HAVE_ACL_SET_FILE rather than HAVE_POSIX_ACL. (ACL_NOT_WELL_SUPPORTED): Remove. All uses replaced by !acl_errno_valid. (Fcopy_file) [!WINDOWSNT]: Use qcopy_acl instead of rolling it ourselves. Fixes: debbugs:14295
This commit is contained in:
parent
ad64371062
commit
ffdc270a76
26 changed files with 3313 additions and 81 deletions
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,19 @@
|
|||
2013-05-07 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Use Gnulib ACL implementation, for benefit of Solaris etc. (Bug#14295)
|
||||
* configure.ac: Remove -with-acl option, since Gnulib does that for
|
||||
us now.
|
||||
(LIBACL_LIBS): Remove; no longer needed.
|
||||
* lib/Makefile.am (CLEANFILES, SUFFIXES): New (empty) macros,
|
||||
for the benefit of the new ACL implementation.
|
||||
* lib/makefile.w32-in (GNULIBOBJS): Add $(BLD)/acl-errno-valid.$(O).
|
||||
($(BLD)/acl-errno-valid.$(O)): New rule.
|
||||
* lib/acl-errno-valid.c, lib/acl-internal.h, lib/acl.h:
|
||||
* lib/acl_entries.c, lib/errno.in.h, lib/file-has-acl.c:
|
||||
* lib/qcopy-acl.c, lib/qset-acl.c, m4/acl.m4, m4/errno_h.m4:
|
||||
New files, taken from gnulib.
|
||||
* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
|
||||
|
||||
2013-05-07 Jan Djärv <jan.h.d@swipnet.se>
|
||||
|
||||
* configure.ac (HAVE_XRANDR, HAVE_XINERAMA): Define if available.
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2013-05-07 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Use Gnulib ACL implementation, for benefit of Solaris etc. (Bug#14295)
|
||||
* merge-gnulib (GNULIB_MODULES): Add qacl.
|
||||
(GNULIB_TOOL_FLAGS): Do not avoid errno.
|
||||
|
||||
2013-04-01 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Use UTF-8 for most files with non-ASCII characters (Bug#13936).
|
||||
|
|
|
@ -33,7 +33,7 @@ GNULIB_MODULES='
|
|||
getloadavg getopt-gnu gettime gettimeofday
|
||||
ignore-value intprops largefile lstat
|
||||
manywarnings memrchr mktime
|
||||
pselect pthread_sigmask putenv readlink readlinkat
|
||||
pselect pthread_sigmask putenv qacl readlink readlinkat
|
||||
sig2str socklen stat-time stdalign stdarg stdbool stdio
|
||||
strftime strtoimax strtoumax symlink sys_stat
|
||||
sys_time time timer-time timespec-add timespec-sub unsetenv utimens
|
||||
|
@ -42,7 +42,7 @@ GNULIB_MODULES='
|
|||
|
||||
GNULIB_TOOL_FLAGS='
|
||||
--avoid=dup
|
||||
--avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat
|
||||
--avoid=fchdir --avoid=fcntl --avoid=fstat
|
||||
--avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow
|
||||
--avoid=open --avoid=openat-die --avoid=opendir
|
||||
--avoid=raise
|
||||
|
|
18
configure.ac
18
configure.ac
|
@ -199,7 +199,6 @@ OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus support])
|
|||
OPTION_DEFAULT_ON([gconf],[don't compile with GConf support])
|
||||
OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support])
|
||||
OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
|
||||
OPTION_DEFAULT_ON([acl],[don't compile with ACL support])
|
||||
OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
|
||||
OPTION_DEFAULT_ON([inotify],[don't compile with inotify (file-watch) support])
|
||||
|
||||
|
@ -2185,23 +2184,6 @@ if test "$ac_cv_func_inotify_init1" = yes; then
|
|||
AC_DEFINE(HAVE_INOTIFY, 1, [Define to 1 to use inotify.])
|
||||
fi
|
||||
|
||||
dnl POSIX ACL support: provided by libacl on GNU/Linux, by libc on FreeBSD.
|
||||
HAVE_POSIX_ACL=no
|
||||
LIBACL_LIBS=
|
||||
if test "${with_acl}" = "yes"; then
|
||||
AC_CHECK_LIB([acl], [acl_set_file], HAVE_POSIX_ACL=yes, HAVE_POSIX_ACL=no)
|
||||
if test "$HAVE_POSIX_ACL" = yes; then
|
||||
AC_DEFINE(HAVE_POSIX_ACL, 1, [Define to 1 if using POSIX ACL support.])
|
||||
LIBACL_LIBS=-lacl
|
||||
else
|
||||
AC_CHECK_FUNC(acl_set_file, HAVE_POSIX_ACL=yes, HAVE_POSIX_ACL=no)
|
||||
if test "$HAVE_POSIX_ACL" = yes; then
|
||||
AC_DEFINE(HAVE_POSIX_ACL, 1, [Define to 1 if using POSIX ACL support.])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(LIBACL_LIBS)
|
||||
|
||||
dnl Do not put whitespace before the #include statements below.
|
||||
dnl Older compilers (eg sunos4 cc) choke on it.
|
||||
HAVE_XAW3D=no
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2013-05-07 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Use Gnulib ACL implementation, for benefit of Solaris etc. (Bug#14295)
|
||||
* NEWS: Emacs is no longer limited to POSIX ACLs. --disable-acl,
|
||||
not --without-acl, since we're now using Gnulib's implementation.
|
||||
|
||||
2013-05-07 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
|
||||
|
||||
* NEWS: Mention multi-monitor support.
|
||||
|
|
4
etc/NEWS
4
etc/NEWS
|
@ -23,10 +23,10 @@ so we will look at it and add it to the manual.
|
|||
|
||||
* Installation Changes in Emacs 24.4
|
||||
|
||||
** Emacs can be compiled with POSIX ACL support.
|
||||
** Emacs can be compiled with ACL support.
|
||||
This happens by default if a suitable support library is found at
|
||||
build time, like libacl on GNU/Linux. To prevent this, use the
|
||||
configure option `--without-acl'.
|
||||
configure option `--disable-acl'.
|
||||
|
||||
** The configure option --with-crt-dir has been removed.
|
||||
It is no longer needed, as the crt*.o files are no longer linked specially.
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
BUILT_SOURCES =
|
||||
CLEANFILES =
|
||||
EXTRA_DIST =
|
||||
MOSTLYCLEANDIRS =
|
||||
MOSTLYCLEANFILES =
|
||||
noinst_LIBRARIES =
|
||||
SUFFIXES =
|
||||
|
||||
AM_CFLAGS = $(PROFILING_CFLAGS) $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS)
|
||||
DEFAULT_INCLUDES = -I. -I$(top_srcdir)/lib -I../src -I$(top_srcdir)/src
|
||||
|
|
52
lib/acl-errno-valid.c
Normal file
52
lib/acl-errno-valid.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* Test whether ACLs are well supported on this system.
|
||||
|
||||
Copyright 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
|
||||
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. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <acl.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
/* Return true if errno value ERRNUM indicates that ACLs are well
|
||||
supported on this system. ERRNUM should be an errno value obtained
|
||||
after an ACL-related system call fails. */
|
||||
bool
|
||||
acl_errno_valid (int errnum)
|
||||
{
|
||||
/* Recognize some common errors such as from an NFS mount that does
|
||||
not support ACLs, even when local drives do. */
|
||||
switch (errnum)
|
||||
{
|
||||
case EBUSY: return false;
|
||||
case EINVAL: return false;
|
||||
#if defined __APPLE__ && defined __MACH__
|
||||
case ENOENT: return false;
|
||||
#endif
|
||||
case ENOSYS: return false;
|
||||
|
||||
#if defined ENOTSUP && ENOTSUP != EOPNOTSUPP
|
||||
# if ENOTSUP != ENOSYS /* Needed for the MS-Windows port of GNU Emacs. */
|
||||
case ENOTSUP: return false;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
case EOPNOTSUPP: return false;
|
||||
default: return true;
|
||||
}
|
||||
}
|
250
lib/acl-internal.h
Normal file
250
lib/acl-internal.h
Normal file
|
@ -0,0 +1,250 @@
|
|||
/* Internal implementation of access control lists.
|
||||
|
||||
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
|
||||
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 "acl.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* All systems define the ACL related API in <sys/acl.h>. */
|
||||
#if HAVE_SYS_ACL_H
|
||||
# include <sys/acl.h>
|
||||
#endif
|
||||
#if defined HAVE_FACL && ! defined GETACLCNT && defined ACL_CNT
|
||||
# define GETACLCNT ACL_CNT
|
||||
#endif
|
||||
|
||||
/* On Linux, additional ACL related API is available in <acl/libacl.h>. */
|
||||
#ifdef HAVE_ACL_LIBACL_H
|
||||
# include <acl/libacl.h>
|
||||
#endif
|
||||
|
||||
/* On HP-UX >= 11.11, additional ACL API is available in <aclv.h>. */
|
||||
#if HAVE_ACLV_H
|
||||
# include <sys/types.h>
|
||||
# include <aclv.h>
|
||||
/* HP-UX 11.11 lacks these declarations. */
|
||||
extern int acl (char *, int, int, struct acl *);
|
||||
extern int aclsort (int, int, struct acl *);
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <limits.h>
|
||||
#ifndef MIN
|
||||
# define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
# define SIZE_MAX ((size_t) -1)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FCHMOD
|
||||
# define HAVE_FCHMOD false
|
||||
# define fchmod(fd, mode) (-1)
|
||||
#endif
|
||||
|
||||
_GL_INLINE_HEADER_BEGIN
|
||||
#ifndef ACL_INTERNAL_INLINE
|
||||
# define ACL_INTERNAL_INLINE _GL_INLINE
|
||||
#endif
|
||||
|
||||
#if USE_ACL
|
||||
|
||||
# if HAVE_ACL_GET_FILE
|
||||
/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
|
||||
/* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
|
||||
|
||||
# ifndef MIN_ACL_ENTRIES
|
||||
# define MIN_ACL_ENTRIES 4
|
||||
# endif
|
||||
|
||||
/* POSIX 1003.1e (draft 17) */
|
||||
# ifdef HAVE_ACL_GET_FD
|
||||
/* Most platforms have a 1-argument acl_get_fd, only OSF/1 has a 2-argument
|
||||
macro(!). */
|
||||
# if HAVE_ACL_FREE_TEXT /* OSF/1 */
|
||||
ACL_INTERNAL_INLINE acl_t
|
||||
rpl_acl_get_fd (int fd)
|
||||
{
|
||||
return acl_get_fd (fd, ACL_TYPE_ACCESS);
|
||||
}
|
||||
# undef acl_get_fd
|
||||
# define acl_get_fd rpl_acl_get_fd
|
||||
# endif
|
||||
# else
|
||||
# define HAVE_ACL_GET_FD false
|
||||
# undef acl_get_fd
|
||||
# define acl_get_fd(fd) (NULL)
|
||||
# endif
|
||||
|
||||
/* POSIX 1003.1e (draft 17) */
|
||||
# ifdef HAVE_ACL_SET_FD
|
||||
/* Most platforms have a 2-argument acl_set_fd, only OSF/1 has a 3-argument
|
||||
macro(!). */
|
||||
# if HAVE_ACL_FREE_TEXT /* OSF/1 */
|
||||
ACL_INTERNAL_INLINE int
|
||||
rpl_acl_set_fd (int fd, acl_t acl)
|
||||
{
|
||||
return acl_set_fd (fd, ACL_TYPE_ACCESS, acl);
|
||||
}
|
||||
# undef acl_set_fd
|
||||
# define acl_set_fd rpl_acl_set_fd
|
||||
# endif
|
||||
# else
|
||||
# define HAVE_ACL_SET_FD false
|
||||
# undef acl_set_fd
|
||||
# define acl_set_fd(fd, acl) (-1)
|
||||
# endif
|
||||
|
||||
/* POSIX 1003.1e (draft 13) */
|
||||
# if ! HAVE_ACL_FREE_TEXT
|
||||
# define acl_free_text(buf) acl_free (buf)
|
||||
# endif
|
||||
|
||||
/* Linux-specific */
|
||||
# ifndef HAVE_ACL_EXTENDED_FILE
|
||||
# define HAVE_ACL_EXTENDED_FILE false
|
||||
# define acl_extended_file(name) (-1)
|
||||
# endif
|
||||
|
||||
/* Linux-specific */
|
||||
# ifndef HAVE_ACL_FROM_MODE
|
||||
# define HAVE_ACL_FROM_MODE false
|
||||
# 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. */
|
||||
# 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.
|
||||
Return -1 and set errno upon failure to determine it. */
|
||||
/* Define a replacement for acl_entries if needed. (Only Linux has it.) */
|
||||
# if !HAVE_ACL_ENTRIES
|
||||
# define acl_entries rpl_acl_entries
|
||||
extern int acl_entries (acl_t);
|
||||
# endif
|
||||
|
||||
# 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.
|
||||
Return 0 if it is trivial. */
|
||||
extern int acl_extended_nontrivial (acl_t);
|
||||
# else
|
||||
/* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS.
|
||||
Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
|
||||
Return -1 and set errno upon failure to determine it. */
|
||||
extern int acl_access_nontrivial (acl_t);
|
||||
# endif
|
||||
|
||||
# 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. */
|
||||
# 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.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
extern int acl_nontrivial (int count, aclent_t *entries);
|
||||
|
||||
# ifdef ACE_GETACL /* Solaris 10 */
|
||||
|
||||
/* Test an ACL retrieved with ACE_GETACL.
|
||||
Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
extern int acl_ace_nontrivial (int count, ace_t *entries);
|
||||
|
||||
/* Definitions for when the built executable is executed on Solaris 10
|
||||
(newer version) or Solaris 11. */
|
||||
/* For a_type. */
|
||||
# define OLD_ALLOW 0
|
||||
# define OLD_DENY 1
|
||||
# define NEW_ACE_ACCESS_ALLOWED_ACE_TYPE 0 /* replaces ALLOW */
|
||||
# define NEW_ACE_ACCESS_DENIED_ACE_TYPE 1 /* replaces DENY */
|
||||
/* For a_flags. */
|
||||
# define OLD_ACE_OWNER 0x0100
|
||||
# define OLD_ACE_GROUP 0x0200
|
||||
# define OLD_ACE_OTHER 0x0400
|
||||
# define NEW_ACE_OWNER 0x1000
|
||||
# define NEW_ACE_GROUP 0x2000
|
||||
# define NEW_ACE_IDENTIFIER_GROUP 0x0040
|
||||
# define NEW_ACE_EVERYONE 0x4000
|
||||
/* For a_access_mask. */
|
||||
# define NEW_ACE_READ_DATA 0x001 /* corresponds to 'r' */
|
||||
# define NEW_ACE_WRITE_DATA 0x002 /* corresponds to 'w' */
|
||||
# define NEW_ACE_APPEND_DATA 0x004
|
||||
# define NEW_ACE_READ_NAMED_ATTRS 0x008
|
||||
# define NEW_ACE_WRITE_NAMED_ATTRS 0x010
|
||||
# define NEW_ACE_EXECUTE 0x020
|
||||
# define NEW_ACE_DELETE_CHILD 0x040
|
||||
# define NEW_ACE_READ_ATTRIBUTES 0x080
|
||||
# define NEW_ACE_WRITE_ATTRIBUTES 0x100
|
||||
# define NEW_ACE_DELETE 0x10000
|
||||
# define NEW_ACE_READ_ACL 0x20000
|
||||
# define NEW_ACE_WRITE_ACL 0x40000
|
||||
# define NEW_ACE_WRITE_OWNER 0x80000
|
||||
# define NEW_ACE_SYNCHRONIZE 0x100000
|
||||
|
||||
# endif
|
||||
|
||||
# elif HAVE_GETACL /* HP-UX */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
extern int acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb);
|
||||
|
||||
# if HAVE_ACLV_H /* HP-UX >= 11.11 */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
extern int aclv_nontrivial (int count, struct acl *entries);
|
||||
|
||||
# endif
|
||||
|
||||
# elif HAVE_ACLX_GET && 0 /* AIX */
|
||||
|
||||
/* TODO */
|
||||
|
||||
# elif HAVE_STATACL /* older AIX */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
extern int acl_nontrivial (struct acl *a);
|
||||
|
||||
# elif HAVE_ACLSORT /* NonStop Kernel */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
extern int acl_nontrivial (int count, struct acl *entries);
|
||||
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
_GL_INLINE_HEADER_END
|
30
lib/acl.h
Normal file
30
lib/acl.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* acl.c - access control lists
|
||||
|
||||
Copyright (C) 2002, 2008-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
|
||||
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. */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
bool acl_errno_valid (int) _GL_ATTRIBUTE_CONST;
|
||||
int file_has_acl (char const *, struct stat const *);
|
||||
int qset_acl (char const *, int, mode_t);
|
||||
int set_acl (char const *, int, mode_t);
|
||||
int qcopy_acl (char const *, int, char const *, int, mode_t);
|
||||
int copy_acl (char const *, int, char const *, int, mode_t);
|
||||
int chmod_or_fchmod (char const *, int, mode_t);
|
75
lib/acl_entries.c
Normal file
75
lib/acl_entries.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
/* Return the number of entries in an ACL.
|
||||
|
||||
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
|
||||
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 and Andreas Gruenbacher. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "acl-internal.h"
|
||||
|
||||
/* This file assumes POSIX-draft like ACLs
|
||||
(Linux, FreeBSD, Mac OS X, IRIX, Tru64). */
|
||||
|
||||
/* Return the number of entries in ACL.
|
||||
Return -1 and set errno upon failure to determine it. */
|
||||
|
||||
int
|
||||
acl_entries (acl_t acl)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (acl != NULL)
|
||||
{
|
||||
#if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD, Mac OS X */
|
||||
# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
|
||||
/* acl_get_entry returns 0 when it successfully fetches an entry,
|
||||
and -1/EINVAL at the end. */
|
||||
acl_entry_t ace;
|
||||
int got_one;
|
||||
|
||||
for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
|
||||
got_one >= 0;
|
||||
got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
|
||||
count++;
|
||||
# else /* Linux, FreeBSD */
|
||||
/* acl_get_entry returns 1 when it successfully fetches an entry,
|
||||
and 0 at the end. */
|
||||
acl_entry_t ace;
|
||||
int got_one;
|
||||
|
||||
for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
|
||||
got_one > 0;
|
||||
got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
|
||||
count++;
|
||||
if (got_one < 0)
|
||||
return -1;
|
||||
# endif
|
||||
#else /* IRIX, Tru64 */
|
||||
# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */
|
||||
/* Don't use acl_get_entry: it is undocumented. */
|
||||
count = acl->acl_cnt;
|
||||
# endif
|
||||
# if HAVE_ACL_FREE_TEXT /* Tru64 */
|
||||
/* Don't use acl_get_entry: it takes only one argument and does not
|
||||
work. */
|
||||
count = acl->acl_num;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
279
lib/errno.in.h
Normal file
279
lib/errno.in.h
Normal file
|
@ -0,0 +1,279 @@
|
|||
/* A POSIX-like <errno.h>.
|
||||
|
||||
Copyright (C) 2008-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
|
||||
the Free Software Foundation; either version 3, 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/>. */
|
||||
|
||||
#ifndef _@GUARD_PREFIX@_ERRNO_H
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
@PRAGMA_SYSTEM_HEADER@
|
||||
#endif
|
||||
@PRAGMA_COLUMNS@
|
||||
|
||||
/* The include_next requires a split double-inclusion guard. */
|
||||
#@INCLUDE_NEXT@ @NEXT_ERRNO_H@
|
||||
|
||||
#ifndef _@GUARD_PREFIX@_ERRNO_H
|
||||
#define _@GUARD_PREFIX@_ERRNO_H
|
||||
|
||||
|
||||
/* On native Windows platforms, many macros are not defined. */
|
||||
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
|
||||
|
||||
/* These are the same values as defined by MSVC 10, for interoperability. */
|
||||
|
||||
# ifndef ENOMSG
|
||||
# define ENOMSG 122
|
||||
# define GNULIB_defined_ENOMSG 1
|
||||
# endif
|
||||
|
||||
# ifndef EIDRM
|
||||
# define EIDRM 111
|
||||
# define GNULIB_defined_EIDRM 1
|
||||
# endif
|
||||
|
||||
# ifndef ENOLINK
|
||||
# define ENOLINK 121
|
||||
# define GNULIB_defined_ENOLINK 1
|
||||
# endif
|
||||
|
||||
# ifndef EPROTO
|
||||
# define EPROTO 134
|
||||
# define GNULIB_defined_EPROTO 1
|
||||
# endif
|
||||
|
||||
# ifndef EBADMSG
|
||||
# define EBADMSG 104
|
||||
# define GNULIB_defined_EBADMSG 1
|
||||
# endif
|
||||
|
||||
# ifndef EOVERFLOW
|
||||
# define EOVERFLOW 132
|
||||
# define GNULIB_defined_EOVERFLOW 1
|
||||
# endif
|
||||
|
||||
# ifndef ENOTSUP
|
||||
# define ENOTSUP 129
|
||||
# define GNULIB_defined_ENOTSUP 1
|
||||
# endif
|
||||
|
||||
# ifndef ENETRESET
|
||||
# define ENETRESET 117
|
||||
# define GNULIB_defined_ENETRESET 1
|
||||
# endif
|
||||
|
||||
# ifndef ECONNABORTED
|
||||
# define ECONNABORTED 106
|
||||
# define GNULIB_defined_ECONNABORTED 1
|
||||
# endif
|
||||
|
||||
# ifndef ECANCELED
|
||||
# define ECANCELED 105
|
||||
# define GNULIB_defined_ECANCELED 1
|
||||
# endif
|
||||
|
||||
# ifndef EOWNERDEAD
|
||||
# define EOWNERDEAD 133
|
||||
# define GNULIB_defined_EOWNERDEAD 1
|
||||
# endif
|
||||
|
||||
# ifndef ENOTRECOVERABLE
|
||||
# define ENOTRECOVERABLE 127
|
||||
# define GNULIB_defined_ENOTRECOVERABLE 1
|
||||
# endif
|
||||
|
||||
# ifndef EINPROGRESS
|
||||
# define EINPROGRESS 112
|
||||
# define EALREADY 103
|
||||
# define ENOTSOCK 128
|
||||
# define EDESTADDRREQ 109
|
||||
# define EMSGSIZE 115
|
||||
# define EPROTOTYPE 136
|
||||
# define ENOPROTOOPT 123
|
||||
# define EPROTONOSUPPORT 135
|
||||
# define EOPNOTSUPP 130
|
||||
# define EAFNOSUPPORT 102
|
||||
# define EADDRINUSE 100
|
||||
# define EADDRNOTAVAIL 101
|
||||
# define ENETDOWN 116
|
||||
# define ENETUNREACH 118
|
||||
# define ECONNRESET 108
|
||||
# define ENOBUFS 119
|
||||
# define EISCONN 113
|
||||
# define ENOTCONN 126
|
||||
# define ETIMEDOUT 138
|
||||
# define ECONNREFUSED 107
|
||||
# define ELOOP 114
|
||||
# define EHOSTUNREACH 110
|
||||
# define EWOULDBLOCK 140
|
||||
# define GNULIB_defined_ESOCK 1
|
||||
# endif
|
||||
|
||||
# ifndef ETXTBSY
|
||||
# define ETXTBSY 139
|
||||
# define ENODATA 120 /* not required by POSIX */
|
||||
# define ENOSR 124 /* not required by POSIX */
|
||||
# define ENOSTR 125 /* not required by POSIX */
|
||||
# define ETIME 137 /* not required by POSIX */
|
||||
# define EOTHER 131 /* not required by POSIX */
|
||||
# define GNULIB_defined_ESTREAMS 1
|
||||
# endif
|
||||
|
||||
/* These are intentionally the same values as the WSA* error numbers, defined
|
||||
in <winsock2.h>. */
|
||||
# define ESOCKTNOSUPPORT 10044 /* not required by POSIX */
|
||||
# define EPFNOSUPPORT 10046 /* not required by POSIX */
|
||||
# define ESHUTDOWN 10058 /* not required by POSIX */
|
||||
# define ETOOMANYREFS 10059 /* not required by POSIX */
|
||||
# define EHOSTDOWN 10064 /* not required by POSIX */
|
||||
# define EPROCLIM 10067 /* not required by POSIX */
|
||||
# define EUSERS 10068 /* not required by POSIX */
|
||||
# define EDQUOT 10069
|
||||
# define ESTALE 10070
|
||||
# define EREMOTE 10071 /* not required by POSIX */
|
||||
# define GNULIB_defined_EWINSOCK 1
|
||||
|
||||
# endif
|
||||
|
||||
|
||||
/* On OSF/1 5.1, when _XOPEN_SOURCE_EXTENDED is not defined, the macros
|
||||
EMULTIHOP, ENOLINK, EOVERFLOW are not defined. */
|
||||
# if @EMULTIHOP_HIDDEN@
|
||||
# define EMULTIHOP @EMULTIHOP_VALUE@
|
||||
# define GNULIB_defined_EMULTIHOP 1
|
||||
# endif
|
||||
# if @ENOLINK_HIDDEN@
|
||||
# define ENOLINK @ENOLINK_VALUE@
|
||||
# define GNULIB_defined_ENOLINK 1
|
||||
# endif
|
||||
# if @EOVERFLOW_HIDDEN@
|
||||
# define EOVERFLOW @EOVERFLOW_VALUE@
|
||||
# define GNULIB_defined_EOVERFLOW 1
|
||||
# endif
|
||||
|
||||
|
||||
/* On OpenBSD 4.0 and on native Windows, the macros ENOMSG, EIDRM, ENOLINK,
|
||||
EPROTO, EMULTIHOP, EBADMSG, EOVERFLOW, ENOTSUP, ECANCELED are not defined.
|
||||
Likewise, on NonStop Kernel, EDQUOT is not defined.
|
||||
Define them here. Values >= 2000 seem safe to use: Solaris ESTALE = 151,
|
||||
HP-UX EWOULDBLOCK = 246, IRIX EDQUOT = 1133.
|
||||
|
||||
Note: When one of these systems defines some of these macros some day,
|
||||
binaries will have to be recompiled so that they recognizes the new
|
||||
errno values from the system. */
|
||||
|
||||
# ifndef ENOMSG
|
||||
# define ENOMSG 2000
|
||||
# define GNULIB_defined_ENOMSG 1
|
||||
# endif
|
||||
|
||||
# ifndef EIDRM
|
||||
# define EIDRM 2001
|
||||
# define GNULIB_defined_EIDRM 1
|
||||
# endif
|
||||
|
||||
# ifndef ENOLINK
|
||||
# define ENOLINK 2002
|
||||
# define GNULIB_defined_ENOLINK 1
|
||||
# endif
|
||||
|
||||
# ifndef EPROTO
|
||||
# define EPROTO 2003
|
||||
# define GNULIB_defined_EPROTO 1
|
||||
# endif
|
||||
|
||||
# ifndef EMULTIHOP
|
||||
# define EMULTIHOP 2004
|
||||
# define GNULIB_defined_EMULTIHOP 1
|
||||
# endif
|
||||
|
||||
# ifndef EBADMSG
|
||||
# define EBADMSG 2005
|
||||
# define GNULIB_defined_EBADMSG 1
|
||||
# endif
|
||||
|
||||
# ifndef EOVERFLOW
|
||||
# define EOVERFLOW 2006
|
||||
# define GNULIB_defined_EOVERFLOW 1
|
||||
# endif
|
||||
|
||||
# ifndef ENOTSUP
|
||||
# define ENOTSUP 2007
|
||||
# define GNULIB_defined_ENOTSUP 1
|
||||
# endif
|
||||
|
||||
# ifndef ENETRESET
|
||||
# define ENETRESET 2011
|
||||
# define GNULIB_defined_ENETRESET 1
|
||||
# endif
|
||||
|
||||
# ifndef ECONNABORTED
|
||||
# define ECONNABORTED 2012
|
||||
# define GNULIB_defined_ECONNABORTED 1
|
||||
# endif
|
||||
|
||||
# ifndef ESTALE
|
||||
# define ESTALE 2009
|
||||
# define GNULIB_defined_ESTALE 1
|
||||
# endif
|
||||
|
||||
# ifndef EDQUOT
|
||||
# define EDQUOT 2010
|
||||
# define GNULIB_defined_EDQUOT 1
|
||||
# endif
|
||||
|
||||
# ifndef ECANCELED
|
||||
# define ECANCELED 2008
|
||||
# define GNULIB_defined_ECANCELED 1
|
||||
# endif
|
||||
|
||||
/* On many platforms, the macros EOWNERDEAD and ENOTRECOVERABLE are not
|
||||
defined. */
|
||||
|
||||
# ifndef EOWNERDEAD
|
||||
# if defined __sun
|
||||
/* Use the same values as defined for Solaris >= 8, for
|
||||
interoperability. */
|
||||
# define EOWNERDEAD 58
|
||||
# define ENOTRECOVERABLE 59
|
||||
# elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
|
||||
/* We have a conflict here: pthreads-win32 defines these values
|
||||
differently than MSVC 10. It's hairy to decide which one to use. */
|
||||
# if defined __MINGW32__ && !defined USE_WINDOWS_THREADS
|
||||
/* Use the same values as defined by pthreads-win32, for
|
||||
interoperability. */
|
||||
# define EOWNERDEAD 43
|
||||
# define ENOTRECOVERABLE 44
|
||||
# else
|
||||
/* Use the same values as defined by MSVC 10, for
|
||||
interoperability. */
|
||||
# define EOWNERDEAD 133
|
||||
# define ENOTRECOVERABLE 127
|
||||
# endif
|
||||
# else
|
||||
# define EOWNERDEAD 2013
|
||||
# define ENOTRECOVERABLE 2014
|
||||
# endif
|
||||
# define GNULIB_defined_EOWNERDEAD 1
|
||||
# define GNULIB_defined_ENOTRECOVERABLE 1
|
||||
# endif
|
||||
|
||||
# ifndef EILSEQ
|
||||
# define EILSEQ 2015
|
||||
# define GNULIB_defined_EILSEQ 1
|
||||
# endif
|
||||
|
||||
#endif /* _@GUARD_PREFIX@_ERRNO_H */
|
||||
#endif /* _@GUARD_PREFIX@_ERRNO_H */
|
918
lib/file-has-acl.c
Normal file
918
lib/file-has-acl.c
Normal file
|
@ -0,0 +1,918 @@
|
|||
/* Test whether a file has a nontrivial access control list.
|
||||
|
||||
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
|
||||
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. */
|
||||
|
||||
/* Without this pragma, gcc 4.7.0 20120126 may suggest that the
|
||||
file_has_acl function might be candidate for attribute 'const' */
|
||||
#if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wsuggest-attribute=const"
|
||||
#endif
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "acl.h"
|
||||
|
||||
#include "acl-internal.h"
|
||||
|
||||
|
||||
#if USE_ACL && HAVE_ACL_GET_FILE
|
||||
|
||||
# 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.
|
||||
Return 0 if it is trivial. */
|
||||
int
|
||||
acl_extended_nontrivial (acl_t acl)
|
||||
{
|
||||
/* acl is non-trivial if it is non-empty. */
|
||||
return (acl_entries (acl) > 0);
|
||||
}
|
||||
|
||||
# else /* Linux, FreeBSD, IRIX, Tru64 */
|
||||
|
||||
/* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS.
|
||||
Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
|
||||
Return -1 and set errno upon failure to determine it. */
|
||||
int
|
||||
acl_access_nontrivial (acl_t acl)
|
||||
{
|
||||
/* acl is non-trivial if it has some entries other than for "user::",
|
||||
"group::", and "other::". Normally these three should be present
|
||||
at least, allowing us to write
|
||||
return (3 < acl_entries (acl));
|
||||
but the following code is more robust. */
|
||||
# if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD */
|
||||
|
||||
acl_entry_t ace;
|
||||
int got_one;
|
||||
|
||||
for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
|
||||
got_one > 0;
|
||||
got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
|
||||
{
|
||||
acl_tag_t tag;
|
||||
if (acl_get_tag_type (ace, &tag) < 0)
|
||||
return -1;
|
||||
if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
|
||||
return 1;
|
||||
}
|
||||
return got_one;
|
||||
|
||||
# else /* IRIX, Tru64 */
|
||||
# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */
|
||||
/* Don't use acl_get_entry: it is undocumented. */
|
||||
|
||||
int count = acl->acl_cnt;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
acl_entry_t ace = &acl->acl_entry[i];
|
||||
acl_tag_t tag = ace->ae_tag;
|
||||
|
||||
if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ
|
||||
|| tag == ACL_OTHER_OBJ))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
# endif
|
||||
# if 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;
|
||||
acl_entry_t ace;
|
||||
|
||||
for (ace = acl->acl_first; count > 0; ace = ace->next, count--)
|
||||
{
|
||||
acl_tag_t tag;
|
||||
acl_perm_t perm;
|
||||
|
||||
tag = ace->entry->acl_type;
|
||||
if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
|
||||
return 1;
|
||||
|
||||
perm = ace->entry->acl_perm;
|
||||
/* On Tru64, perm can also contain non-standard bits such as
|
||||
PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ... */
|
||||
if ((perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)) != 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
|
||||
#elif USE_ACL && HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
|
||||
|
||||
/* Test an ACL retrieved with GETACL.
|
||||
Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
acl_nontrivial (int count, aclent_t *entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
aclent_t *ace = &entries[i];
|
||||
|
||||
/* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
|
||||
If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
|
||||
We don't need to check ace->a_id in these cases. */
|
||||
if (!(ace->a_type == USER_OBJ
|
||||
|| ace->a_type == GROUP_OBJ
|
||||
|| ace->a_type == OTHER_OBJ
|
||||
/* Note: Cygwin does not return a CLASS_OBJ ("mask:") entry
|
||||
sometimes. */
|
||||
|| ace->a_type == CLASS_OBJ))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
# ifdef ACE_GETACL
|
||||
|
||||
/* A shortcut for a bitmask. */
|
||||
# define NEW_ACE_WRITEA_DATA (NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA)
|
||||
|
||||
/* Test an ACL retrieved with ACE_GETACL.
|
||||
Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
acl_ace_nontrivial (int count, ace_t *entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* The flags in the ace_t structure changed in a binary incompatible way
|
||||
when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
|
||||
How to distinguish the two conventions at runtime?
|
||||
In the old convention, usually three ACEs have a_flags = ACE_OWNER /
|
||||
ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400. In the new
|
||||
convention, these values are not used. */
|
||||
int old_convention = 0;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER))
|
||||
{
|
||||
old_convention = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (old_convention)
|
||||
/* Running on Solaris 10. */
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
ace_t *ace = &entries[i];
|
||||
|
||||
/* Note:
|
||||
If ace->a_flags = ACE_OWNER, ace->a_who is the st_uid from stat().
|
||||
If ace->a_flags = ACE_GROUP, ace->a_who is the st_gid from stat().
|
||||
We don't need to check ace->a_who in these cases. */
|
||||
if (!(ace->a_type == OLD_ALLOW
|
||||
&& (ace->a_flags == OLD_ACE_OWNER
|
||||
|| ace->a_flags == OLD_ACE_GROUP
|
||||
|| ace->a_flags == OLD_ACE_OTHER)))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Running on Solaris 10 (newer version) or Solaris 11. */
|
||||
unsigned int access_masks[6] =
|
||||
{
|
||||
0, /* owner@ deny */
|
||||
0, /* owner@ allow */
|
||||
0, /* group@ deny */
|
||||
0, /* group@ allow */
|
||||
0, /* everyone@ deny */
|
||||
0 /* everyone@ allow */
|
||||
};
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
ace_t *ace = &entries[i];
|
||||
unsigned int index1;
|
||||
unsigned int index2;
|
||||
|
||||
if (ace->a_type == NEW_ACE_ACCESS_ALLOWED_ACE_TYPE)
|
||||
index1 = 1;
|
||||
else if (ace->a_type == NEW_ACE_ACCESS_DENIED_ACE_TYPE)
|
||||
index1 = 0;
|
||||
else
|
||||
return 1;
|
||||
|
||||
if (ace->a_flags == NEW_ACE_OWNER)
|
||||
index2 = 0;
|
||||
else if (ace->a_flags == (NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP))
|
||||
index2 = 2;
|
||||
else if (ace->a_flags == NEW_ACE_EVERYONE)
|
||||
index2 = 4;
|
||||
else
|
||||
return 1;
|
||||
|
||||
access_masks[index1 + index2] |= ace->a_access_mask;
|
||||
}
|
||||
|
||||
/* The same bit shouldn't be both allowed and denied. */
|
||||
if (access_masks[0] & access_masks[1])
|
||||
return 1;
|
||||
if (access_masks[2] & access_masks[3])
|
||||
return 1;
|
||||
if (access_masks[4] & access_masks[5])
|
||||
return 1;
|
||||
|
||||
/* Check minimum masks. */
|
||||
if ((NEW_ACE_WRITE_NAMED_ATTRS
|
||||
| NEW_ACE_WRITE_ATTRIBUTES
|
||||
| NEW_ACE_WRITE_ACL
|
||||
| NEW_ACE_WRITE_OWNER)
|
||||
& ~ access_masks[1])
|
||||
return 1;
|
||||
access_masks[1] &= ~(NEW_ACE_WRITE_NAMED_ATTRS
|
||||
| NEW_ACE_WRITE_ATTRIBUTES
|
||||
| NEW_ACE_WRITE_ACL
|
||||
| NEW_ACE_WRITE_OWNER);
|
||||
if ((NEW_ACE_READ_NAMED_ATTRS
|
||||
| NEW_ACE_READ_ATTRIBUTES
|
||||
| NEW_ACE_READ_ACL
|
||||
| NEW_ACE_SYNCHRONIZE)
|
||||
& ~ access_masks[5])
|
||||
return 1;
|
||||
access_masks[5] &= ~(NEW_ACE_READ_NAMED_ATTRS
|
||||
| NEW_ACE_READ_ATTRIBUTES
|
||||
| NEW_ACE_READ_ACL
|
||||
| NEW_ACE_SYNCHRONIZE);
|
||||
|
||||
/* Check the allowed or denied bits. */
|
||||
switch ((access_masks[0] | access_masks[1])
|
||||
& ~(NEW_ACE_READ_NAMED_ATTRS
|
||||
| NEW_ACE_READ_ATTRIBUTES
|
||||
| NEW_ACE_READ_ACL
|
||||
| NEW_ACE_SYNCHRONIZE))
|
||||
{
|
||||
case 0:
|
||||
case NEW_ACE_READ_DATA:
|
||||
case NEW_ACE_WRITEA_DATA:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
|
||||
case NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
switch ((access_masks[2] | access_masks[3])
|
||||
& ~(NEW_ACE_READ_NAMED_ATTRS
|
||||
| NEW_ACE_READ_ATTRIBUTES
|
||||
| NEW_ACE_READ_ACL
|
||||
| NEW_ACE_SYNCHRONIZE))
|
||||
{
|
||||
case 0:
|
||||
case NEW_ACE_READ_DATA:
|
||||
case NEW_ACE_WRITEA_DATA:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
|
||||
case NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
switch ((access_masks[4] | access_masks[5])
|
||||
& ~(NEW_ACE_WRITE_NAMED_ATTRS
|
||||
| NEW_ACE_WRITE_ATTRIBUTES
|
||||
| NEW_ACE_WRITE_ACL
|
||||
| NEW_ACE_WRITE_OWNER))
|
||||
{
|
||||
case 0:
|
||||
case NEW_ACE_READ_DATA:
|
||||
case NEW_ACE_WRITEA_DATA:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
|
||||
case NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check that the NEW_ACE_WRITE_DATA and NEW_ACE_APPEND_DATA bits are
|
||||
either both allowed or both denied. */
|
||||
if (((access_masks[0] & NEW_ACE_WRITE_DATA) != 0)
|
||||
!= ((access_masks[0] & NEW_ACE_APPEND_DATA) != 0))
|
||||
return 1;
|
||||
if (((access_masks[2] & NEW_ACE_WRITE_DATA) != 0)
|
||||
!= ((access_masks[2] & NEW_ACE_APPEND_DATA) != 0))
|
||||
return 1;
|
||||
if (((access_masks[4] & NEW_ACE_WRITE_DATA) != 0)
|
||||
!= ((access_masks[4] & NEW_ACE_APPEND_DATA) != 0))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
#elif USE_ACL && HAVE_GETACL /* HP-UX */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
struct acl_entry *ace = &entries[i];
|
||||
|
||||
if (!((ace->uid == sb->st_uid && ace->gid == ACL_NSGROUP)
|
||||
|| (ace->uid == ACL_NSUSER && ace->gid == sb->st_gid)
|
||||
|| (ace->uid == ACL_NSUSER && ace->gid == ACL_NSGROUP)))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
# if HAVE_ACLV_H /* HP-UX >= 11.11 */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
aclv_nontrivial (int count, struct acl *entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
struct acl *ace = &entries[i];
|
||||
|
||||
/* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
|
||||
If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
|
||||
We don't need to check ace->a_id in these cases. */
|
||||
if (!(ace->a_type == USER_OBJ /* no need to check ace->a_id here */
|
||||
|| ace->a_type == GROUP_OBJ /* no need to check ace->a_id here */
|
||||
|| ace->a_type == CLASS_OBJ
|
||||
|| ace->a_type == OTHER_OBJ))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
#elif USE_ACL && (HAVE_ACLX_GET || HAVE_STATACL) /* AIX */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
acl_nontrivial (struct acl *a)
|
||||
{
|
||||
/* The normal way to iterate through an ACL is like this:
|
||||
struct acl_entry *ace;
|
||||
for (ace = a->acl_ext; ace != acl_last (a); ace = acl_nxt (ace))
|
||||
{
|
||||
struct ace_id *aei;
|
||||
switch (ace->ace_type)
|
||||
{
|
||||
case ACC_PERMIT:
|
||||
case ACC_DENY:
|
||||
case ACC_SPECIFY:
|
||||
...;
|
||||
}
|
||||
for (aei = ace->ace_id; aei != id_last (ace); aei = id_nxt (aei))
|
||||
...
|
||||
}
|
||||
*/
|
||||
return (acl_last (a) != a->acl_ext ? 1 : 0);
|
||||
}
|
||||
|
||||
# if HAVE_ACLX_GET && defined ACL_AIX_WIP /* newer AIX */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
acl_nfs4_nontrivial (nfs4_acl_int_t *a)
|
||||
{
|
||||
# if 1 /* let's try this first */
|
||||
return (a->aclEntryN > 0 ? 1 : 0);
|
||||
# else
|
||||
int count = a->aclEntryN;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
nfs4_ace_int_t *ace = &a->aclEntry[i];
|
||||
|
||||
if (!((ace->flags & ACE4_ID_SPECIAL) != 0
|
||||
&& (ace->aceWho.special_whoid == ACE4_WHO_OWNER
|
||||
|| ace->aceWho.special_whoid == ACE4_WHO_GROUP
|
||||
|| ace->aceWho.special_whoid == ACE4_WHO_EVERYONE)
|
||||
&& ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE
|
||||
&& ace->aceFlags == 0
|
||||
&& (ace->aceMask & ~(ACE4_READ_DATA | ACE4_LIST_DIRECTORY
|
||||
| ACE4_WRITE_DATA | ACE4_ADD_FILE
|
||||
| ACE4_EXECUTE)) == 0))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
# endif
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
|
||||
|
||||
/* Test an ACL retrieved with ACL_GET.
|
||||
Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
acl_nontrivial (int count, struct acl *entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
struct acl *ace = &entries[i];
|
||||
|
||||
/* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
|
||||
If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
|
||||
We don't need to check ace->a_id in these cases. */
|
||||
if (!(ace->a_type == USER_OBJ /* no need to check ace->a_id here */
|
||||
|| ace->a_type == GROUP_OBJ /* no need to check ace->a_id here */
|
||||
|| ace->a_type == CLASS_OBJ
|
||||
|| ace->a_type == OTHER_OBJ))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Return 1 if NAME has a nontrivial access control list, 0 if NAME
|
||||
only has no or a base access control list, and -1 (setting errno)
|
||||
on error. SB must be set to the stat buffer of NAME, obtained
|
||||
through stat() or lstat(). */
|
||||
|
||||
int
|
||||
file_has_acl (char const *name, struct stat const *sb)
|
||||
{
|
||||
#if USE_ACL
|
||||
if (! S_ISLNK (sb->st_mode))
|
||||
{
|
||||
# if HAVE_ACL_GET_FILE
|
||||
|
||||
/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
|
||||
/* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
|
||||
int ret;
|
||||
|
||||
if (HAVE_ACL_EXTENDED_FILE) /* Linux */
|
||||
{
|
||||
/* On Linux, acl_extended_file is an optimized function: It only
|
||||
makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
|
||||
ACL_TYPE_DEFAULT. */
|
||||
ret = acl_extended_file (name);
|
||||
}
|
||||
else /* FreeBSD, Mac OS X, IRIX, Tru64 */
|
||||
{
|
||||
# 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
|
||||
acl_get_file (name, ACL_TYPE_EXTENDED). */
|
||||
acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED);
|
||||
if (acl)
|
||||
{
|
||||
ret = acl_extended_nontrivial (acl);
|
||||
acl_free (acl);
|
||||
}
|
||||
else
|
||||
ret = -1;
|
||||
# else /* FreeBSD, IRIX, Tru64 */
|
||||
acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
|
||||
if (acl)
|
||||
{
|
||||
int saved_errno;
|
||||
|
||||
ret = acl_access_nontrivial (acl);
|
||||
saved_errno = errno;
|
||||
acl_free (acl);
|
||||
errno = saved_errno;
|
||||
# if HAVE_ACL_FREE_TEXT /* Tru64 */
|
||||
/* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
|
||||
returns NULL with errno not set. There is no point in
|
||||
making this call. */
|
||||
# else /* FreeBSD, IRIX */
|
||||
/* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS)
|
||||
and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
|
||||
either both succeed or both fail; it depends on the
|
||||
file system. Therefore there is no point in making the second
|
||||
call if the first one already failed. */
|
||||
if (ret == 0 && S_ISDIR (sb->st_mode))
|
||||
{
|
||||
acl = acl_get_file (name, ACL_TYPE_DEFAULT);
|
||||
if (acl)
|
||||
{
|
||||
ret = (0 < acl_entries (acl));
|
||||
acl_free (acl);
|
||||
}
|
||||
else
|
||||
ret = -1;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
else
|
||||
ret = -1;
|
||||
# endif
|
||||
}
|
||||
if (ret < 0)
|
||||
return - acl_errno_valid (errno);
|
||||
return ret;
|
||||
|
||||
# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
|
||||
|
||||
# if defined ACL_NO_TRIVIAL
|
||||
|
||||
/* 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, ...). */
|
||||
return acl_trivial (name);
|
||||
|
||||
# else /* Solaris, Cygwin, general case */
|
||||
|
||||
/* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
|
||||
of Unixware. The acl() call returns the access and default ACL both
|
||||
at once. */
|
||||
{
|
||||
/* 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, GETACL, alloc, entries);
|
||||
if (count < 0 && errno == ENOSPC)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
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)
|
||||
{
|
||||
free (malloced);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (acl_nontrivial (count, entries))
|
||||
{
|
||||
free (malloced);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
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). */
|
||||
{
|
||||
/* 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_GETACL, alloc, entries);
|
||||
if (count < 0 && errno == ENOSPC)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
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.
|
||||
In the newer Solaris 10 and Solaris 11 convention:
|
||||
If there are more than 6 entries, there cannot be only the
|
||||
ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
|
||||
NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
|
||||
NEW_ACE_ACCESS_DENIED_ACE_TYPE. */
|
||||
if (count > 6)
|
||||
{
|
||||
free (malloced);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (acl_ace_nontrivial (count, entries))
|
||||
{
|
||||
free (malloced);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
free (malloced);
|
||||
}
|
||||
# endif
|
||||
|
||||
return 0;
|
||||
# endif
|
||||
|
||||
# elif HAVE_GETACL /* HP-UX */
|
||||
|
||||
{
|
||||
struct acl_entry entries[NACLENTRIES];
|
||||
int count;
|
||||
|
||||
count = getacl (name, NACLENTRIES, entries);
|
||||
|
||||
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;
|
||||
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat (name, &statbuf) < 0)
|
||||
return -1;
|
||||
|
||||
return acl_nontrivial (count, entries, &statbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# if HAVE_ACLV_H /* HP-UX >= 11.11 */
|
||||
|
||||
{
|
||||
struct acl entries[NACLVENTRIES];
|
||||
int count;
|
||||
|
||||
count = acl ((char *) name, ACL_GET, 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)
|
||||
;
|
||||
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;
|
||||
|
||||
return aclv_nontrivial (count, entries);
|
||||
}
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
|
||||
|
||||
acl_type_t type;
|
||||
char aclbuf[1024];
|
||||
void *acl = aclbuf;
|
||||
size_t aclsize = sizeof (aclbuf);
|
||||
mode_t mode;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* The docs say that type being 0 is equivalent to ACL_ANY, but it
|
||||
is not true, in AIX 5.3. */
|
||||
type.u64 = ACL_ANY;
|
||||
if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)
|
||||
break;
|
||||
if (errno == ENOSYS)
|
||||
return 0;
|
||||
if (errno != ENOSPC)
|
||||
{
|
||||
if (acl != aclbuf)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
free (acl);
|
||||
errno = saved_errno;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
aclsize = 2 * aclsize;
|
||||
if (acl != aclbuf)
|
||||
free (acl);
|
||||
acl = malloc (aclsize);
|
||||
if (acl == NULL)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (type.u64 == ACL_AIXC)
|
||||
{
|
||||
int result = acl_nontrivial ((struct acl *) acl);
|
||||
if (acl != aclbuf)
|
||||
free (acl);
|
||||
return result;
|
||||
}
|
||||
else if (type.u64 == ACL_NFS4)
|
||||
{
|
||||
int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl);
|
||||
if (acl != aclbuf)
|
||||
free (acl);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A newer type of ACL has been introduced in the system.
|
||||
We should better support it. */
|
||||
if (acl != aclbuf)
|
||||
free (acl);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
# elif HAVE_STATACL /* older AIX */
|
||||
|
||||
union { struct acl a; char room[4096]; } u;
|
||||
|
||||
if (statacl (name, STX_NORMAL, &u.a, sizeof (u)) < 0)
|
||||
return -1;
|
||||
|
||||
return acl_nontrivial (&u.a);
|
||||
|
||||
# elif HAVE_ACLSORT /* NonStop Kernel */
|
||||
|
||||
{
|
||||
struct acl entries[NACLENTRIES];
|
||||
int count;
|
||||
|
||||
count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);
|
||||
|
||||
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;
|
||||
|
||||
return acl_nontrivial (count, entries);
|
||||
}
|
||||
}
|
||||
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -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=dup --avoid=errno --avoid=fchdir --avoid=fcntl --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=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings memrchr mktime pselect pthread_sigmask putenv readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv utimens 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=dup --avoid=fchdir --avoid=fcntl --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=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings memrchr mktime pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv utimens warnings
|
||||
|
||||
|
||||
MOSTLYCLEANFILES += core *.stackdump
|
||||
|
@ -217,6 +217,40 @@ EXTRA_libgnu_a_SOURCES += dup2.c
|
|||
|
||||
## end gnulib module dup2
|
||||
|
||||
## begin gnulib module errno
|
||||
|
||||
BUILT_SOURCES += $(ERRNO_H)
|
||||
|
||||
# We need the following in order to create <errno.h> when the system
|
||||
# doesn't have one that is POSIX compliant.
|
||||
if GL_GENERATE_ERRNO_H
|
||||
errno.h: errno.in.h $(top_builddir)/config.status
|
||||
$(AM_V_GEN)rm -f $@-t $@ && \
|
||||
{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \
|
||||
sed -e 's|@''GUARD_PREFIX''@|GL|g' \
|
||||
-e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
|
||||
-e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
|
||||
-e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
|
||||
-e 's|@''NEXT_ERRNO_H''@|$(NEXT_ERRNO_H)|g' \
|
||||
-e 's|@''EMULTIHOP_HIDDEN''@|$(EMULTIHOP_HIDDEN)|g' \
|
||||
-e 's|@''EMULTIHOP_VALUE''@|$(EMULTIHOP_VALUE)|g' \
|
||||
-e 's|@''ENOLINK_HIDDEN''@|$(ENOLINK_HIDDEN)|g' \
|
||||
-e 's|@''ENOLINK_VALUE''@|$(ENOLINK_VALUE)|g' \
|
||||
-e 's|@''EOVERFLOW_HIDDEN''@|$(EOVERFLOW_HIDDEN)|g' \
|
||||
-e 's|@''EOVERFLOW_VALUE''@|$(EOVERFLOW_VALUE)|g' \
|
||||
< $(srcdir)/errno.in.h; \
|
||||
} > $@-t && \
|
||||
mv $@-t $@
|
||||
else
|
||||
errno.h: $(top_builddir)/config.status
|
||||
rm -f $@
|
||||
endif
|
||||
MOSTLYCLEANFILES += errno.h errno.h-t
|
||||
|
||||
EXTRA_DIST += errno.in.h
|
||||
|
||||
## end gnulib module errno
|
||||
|
||||
## begin gnulib module euidaccess
|
||||
|
||||
if gl_GNULIB_ENABLED_euidaccess
|
||||
|
@ -561,6 +595,16 @@ EXTRA_libgnu_a_SOURCES += putenv.c
|
|||
|
||||
## end gnulib module putenv
|
||||
|
||||
## begin gnulib module qacl
|
||||
|
||||
libgnu_a_SOURCES += acl-errno-valid.c file-has-acl.c qcopy-acl.c qset-acl.c
|
||||
|
||||
EXTRA_DIST += acl-internal.h acl.h acl_entries.c
|
||||
|
||||
EXTRA_libgnu_a_SOURCES += acl_entries.c
|
||||
|
||||
## end gnulib module qacl
|
||||
|
||||
## begin gnulib module readlink
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ ALL = gnulib
|
|||
LOCAL_FLAGS = -I. -I../nt/inc -I../src
|
||||
LIBS =
|
||||
|
||||
GNULIBOBJS = $(BLD)/c-ctype.$(O) \
|
||||
GNULIBOBJS = $(BLD)/acl-errno-valid.$(O) \
|
||||
$(BLD)/c-ctype.$(O) \
|
||||
$(BLD)/c-strcasecmp.$(O) \
|
||||
$(BLD)/c-strncasecmp.$(O) \
|
||||
$(BLD)/close-stream.$(O) \
|
||||
|
@ -109,6 +110,12 @@ SIG2STR_H = $(GNU_LIB)/sig2str.h \
|
|||
STAT_TIME_H = $(GNU_LIB)/stat-time.h \
|
||||
$(NT_INC)/sys/stat.h
|
||||
|
||||
$(BLD)/acl-errno-valid.$(O) : \
|
||||
$(GNU_LIB)/acl-errno-valid.c \
|
||||
$(CONFIG_H) \
|
||||
$(GNU_LIB)/acl.h \
|
||||
$(NT_INC)/stdbool.h
|
||||
|
||||
$(BLD)/c-ctype.$(O) : \
|
||||
$(GNU_LIB)/c-ctype.c \
|
||||
$(CONFIG_H) \
|
||||
|
|
583
lib/qcopy-acl.c
Normal file
583
lib/qcopy-acl.c
Normal file
|
@ -0,0 +1,583 @@
|
|||
/* copy-acl.c - copy access control list from one file to another file
|
||||
|
||||
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
|
||||
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 "acl.h"
|
||||
|
||||
#include "acl-internal.h"
|
||||
|
||||
|
||||
/* Copy access control lists from one file to another. If SOURCE_DESC is
|
||||
a valid file descriptor, use file descriptor operations, else use
|
||||
filename based operations on SRC_NAME. Likewise for DEST_DESC and
|
||||
DST_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 -2 and set errno for an error relating to the source file.
|
||||
Return -1 and set errno for an error relating to the destination file. */
|
||||
|
||||
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;
|
||||
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);
|
||||
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)
|
||||
{
|
||||
struct stat source_statbuf;
|
||||
|
||||
if ((source_desc != -1
|
||||
? fstat (source_desc, &source_statbuf)
|
||||
: stat (src_name, &source_statbuf)) == 0)
|
||||
{
|
||||
if (!acl_nontrivial (count, entries, &source_statbuf))
|
||||
saved_errno = 0;
|
||||
}
|
||||
else
|
||||
saved_errno = errno;
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
676
lib/qset-acl.c
Normal file
676
lib/qset-acl.c
Normal file
|
@ -0,0 +1,676 @@
|
|||
/* qset-acl.c - set access control list equivalent to a mode
|
||||
|
||||
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
|
||||
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 and Andreas Gruenbacher, 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);
|
||||
# endif
|
||||
|
||||
# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
|
||||
|
||||
int done_setacl = 0;
|
||||
|
||||
# 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). */
|
||||
|
||||
/* The flags in the ace_t structure changed in a binary incompatible way
|
||||
when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
|
||||
How to distinguish the two conventions at runtime?
|
||||
We fetch the existing ACL. In the old convention, usually three ACEs have
|
||||
a_flags = ACE_OWNER / ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400.
|
||||
In the new convention, these values are not used. */
|
||||
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;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
count = (desc != -1
|
||||
? facl (desc, ACE_GETACL, alloc, entries)
|
||||
: acl (name, ACE_GETACL, alloc, entries));
|
||||
if (count < 0 && errno == ENOSPC)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ace_t entries[6];
|
||||
int count;
|
||||
int ret;
|
||||
|
||||
if (convention)
|
||||
{
|
||||
/* Running on Solaris 10. */
|
||||
entries[0].a_type = OLD_ALLOW;
|
||||
entries[0].a_flags = OLD_ACE_OWNER;
|
||||
entries[0].a_who = 0; /* irrelevant */
|
||||
entries[0].a_access_mask = (mode >> 6) & 7;
|
||||
entries[1].a_type = OLD_ALLOW;
|
||||
entries[1].a_flags = OLD_ACE_GROUP;
|
||||
entries[1].a_who = 0; /* irrelevant */
|
||||
entries[1].a_access_mask = (mode >> 3) & 7;
|
||||
entries[2].a_type = OLD_ALLOW;
|
||||
entries[2].a_flags = OLD_ACE_OTHER;
|
||||
entries[2].a_who = 0;
|
||||
entries[2].a_access_mask = mode & 7;
|
||||
count = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Running on Solaris 10 (newer version) or Solaris 11.
|
||||
The details here were found through "/bin/ls -lvd somefiles". */
|
||||
entries[0].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
|
||||
entries[0].a_flags = NEW_ACE_OWNER;
|
||||
entries[0].a_who = 0; /* irrelevant */
|
||||
entries[0].a_access_mask = 0;
|
||||
entries[1].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
|
||||
entries[1].a_flags = NEW_ACE_OWNER;
|
||||
entries[1].a_who = 0; /* irrelevant */
|
||||
entries[1].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS
|
||||
| NEW_ACE_WRITE_ATTRIBUTES
|
||||
| NEW_ACE_WRITE_ACL
|
||||
| NEW_ACE_WRITE_OWNER;
|
||||
if (mode & 0400)
|
||||
entries[1].a_access_mask |= NEW_ACE_READ_DATA;
|
||||
else
|
||||
entries[0].a_access_mask |= NEW_ACE_READ_DATA;
|
||||
if (mode & 0200)
|
||||
entries[1].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
|
||||
else
|
||||
entries[0].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
|
||||
if (mode & 0100)
|
||||
entries[1].a_access_mask |= NEW_ACE_EXECUTE;
|
||||
else
|
||||
entries[0].a_access_mask |= NEW_ACE_EXECUTE;
|
||||
entries[2].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
|
||||
entries[2].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP;
|
||||
entries[2].a_who = 0; /* irrelevant */
|
||||
entries[2].a_access_mask = 0;
|
||||
entries[3].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
|
||||
entries[3].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP;
|
||||
entries[3].a_who = 0; /* irrelevant */
|
||||
entries[3].a_access_mask = 0;
|
||||
if (mode & 0040)
|
||||
entries[3].a_access_mask |= NEW_ACE_READ_DATA;
|
||||
else
|
||||
entries[2].a_access_mask |= NEW_ACE_READ_DATA;
|
||||
if (mode & 0020)
|
||||
entries[3].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
|
||||
else
|
||||
entries[2].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
|
||||
if (mode & 0010)
|
||||
entries[3].a_access_mask |= NEW_ACE_EXECUTE;
|
||||
else
|
||||
entries[2].a_access_mask |= NEW_ACE_EXECUTE;
|
||||
entries[4].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
|
||||
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 = NEW_ACE_EVERYONE;
|
||||
entries[5].a_who = 0;
|
||||
entries[5].a_access_mask = NEW_ACE_READ_NAMED_ATTRS
|
||||
| NEW_ACE_READ_ATTRIBUTES
|
||||
| NEW_ACE_READ_ACL
|
||||
| NEW_ACE_SYNCHRONIZE;
|
||||
if (mode & 0004)
|
||||
entries[5].a_access_mask |= NEW_ACE_READ_DATA;
|
||||
else
|
||||
entries[4].a_access_mask |= NEW_ACE_READ_DATA;
|
||||
if (mode & 0002)
|
||||
entries[5].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
|
||||
else
|
||||
entries[4].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
|
||||
if (mode & 0001)
|
||||
entries[5].a_access_mask |= NEW_ACE_EXECUTE;
|
||||
else
|
||||
entries[4].a_access_mask |= NEW_ACE_EXECUTE;
|
||||
count = 6;
|
||||
}
|
||||
if (desc != -1)
|
||||
ret = facl (desc, ACE_SETACL, count, entries);
|
||||
else
|
||||
ret = acl (name, ACE_SETACL, count, entries);
|
||||
if (ret < 0 && errno != EINVAL && errno != ENOTSUP)
|
||||
{
|
||||
if (errno == ENOSYS)
|
||||
return chmod_or_fchmod (name, desc, mode);
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0)
|
||||
done_setacl = 1;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (!done_setacl)
|
||||
{
|
||||
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;
|
||||
|
||||
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 */
|
||||
|
||||
struct stat statbuf;
|
||||
int ret;
|
||||
|
||||
if (desc != -1)
|
||||
ret = fstat (desc, &statbuf);
|
||||
else
|
||||
ret = stat (name, &statbuf);
|
||||
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;
|
||||
|
||||
# if HAVE_ACLV_H /* HP-UX >= 11.11 */
|
||||
{
|
||||
struct acl entries[4];
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
|
||||
|
||||
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);
|
||||
|
||||
/* XXX Do we need to clear all types of ACLs for the given file, or is it
|
||||
sufficient to clear the first one? */
|
||||
type = types.entries[0];
|
||||
if (type.u64 == ACL_AIXC)
|
||||
{
|
||||
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 = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS,
|
||||
type, &u.a, u.a.acl_len, mode);
|
||||
else
|
||||
ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS,
|
||||
type, &u.a, u.a.acl_len, mode);
|
||||
if (!(ret < 0 && errno == ENOSYS))
|
||||
return ret;
|
||||
}
|
||||
else if (type.u64 == ACL_NFS4)
|
||||
{
|
||||
union { nfs4_acl_int_t a; char room[128]; } u;
|
||||
nfs4_ace_int_t *ace;
|
||||
int ret;
|
||||
|
||||
u.a.aclVersion = NFS4_ACL_INT_STRUCT_VERSION;
|
||||
u.a.aclEntryN = 0;
|
||||
ace = &u.a.aclEntry[0];
|
||||
{
|
||||
ace->flags = ACE4_ID_SPECIAL;
|
||||
ace->aceWho.special_whoid = ACE4_WHO_OWNER;
|
||||
ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
|
||||
ace->aceFlags = 0;
|
||||
ace->aceMask =
|
||||
(mode & 0400 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
|
||||
| (mode & 0200
|
||||
? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
|
||||
| ACE4_ADD_SUBDIRECTORY
|
||||
: 0)
|
||||
| (mode & 0100 ? ACE4_EXECUTE : 0);
|
||||
ace->aceWhoString[0] = '\0';
|
||||
ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
|
||||
ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
|
||||
u.a.aclEntryN++;
|
||||
}
|
||||
{
|
||||
ace->flags = ACE4_ID_SPECIAL;
|
||||
ace->aceWho.special_whoid = ACE4_WHO_GROUP;
|
||||
ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
|
||||
ace->aceFlags = 0;
|
||||
ace->aceMask =
|
||||
(mode & 0040 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
|
||||
| (mode & 0020
|
||||
? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
|
||||
| ACE4_ADD_SUBDIRECTORY
|
||||
: 0)
|
||||
| (mode & 0010 ? ACE4_EXECUTE : 0);
|
||||
ace->aceWhoString[0] = '\0';
|
||||
ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
|
||||
ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
|
||||
u.a.aclEntryN++;
|
||||
}
|
||||
{
|
||||
ace->flags = ACE4_ID_SPECIAL;
|
||||
ace->aceWho.special_whoid = ACE4_WHO_EVERYONE;
|
||||
ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
|
||||
ace->aceFlags = 0;
|
||||
ace->aceMask =
|
||||
(mode & 0004 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
|
||||
| (mode & 0002
|
||||
? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
|
||||
| ACE4_ADD_SUBDIRECTORY
|
||||
: 0)
|
||||
| (mode & 0001 ? ACE4_EXECUTE : 0);
|
||||
ace->aceWhoString[0] = '\0';
|
||||
ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
|
||||
ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
|
||||
u.a.aclEntryN++;
|
||||
}
|
||||
u.a.aclLength = (char *) ace - (char *) &u.a;
|
||||
|
||||
if (desc != -1)
|
||||
ret = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS,
|
||||
type, &u.a, u.a.aclLength, mode);
|
||||
else
|
||||
ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS,
|
||||
type, &u.a, u.a.aclLength, mode);
|
||||
if (!(ret < 0 && errno == ENOSYS))
|
||||
return ret;
|
||||
}
|
||||
|
||||
return chmod_or_fchmod (name, desc, mode);
|
||||
|
||||
# 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;
|
||||
|
||||
# elif HAVE_ACLSORT /* NonStop Kernel */
|
||||
|
||||
struct acl entries[4];
|
||||
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;
|
||||
|
||||
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
|
||||
}
|
164
m4/acl.m4
Normal file
164
m4/acl.m4
Normal file
|
@ -0,0 +1,164 @@
|
|||
# acl.m4 - check for access control list (ACL) primitives
|
||||
# serial 15
|
||||
|
||||
# Copyright (C) 2002, 2004-2013 Free Software Foundation, Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# Written by Paul Eggert and Jim Meyering.
|
||||
|
||||
AC_DEFUN([gl_FUNC_ACL],
|
||||
[
|
||||
AC_ARG_ENABLE([acl],
|
||||
AS_HELP_STRING([--disable-acl], [do not support ACLs]),
|
||||
, [enable_acl=auto])
|
||||
|
||||
LIB_ACL=
|
||||
use_acl=0
|
||||
if test "x$enable_acl" != "xno"; then
|
||||
dnl On all platforms, the ACL related API is declared in <sys/acl.h>.
|
||||
AC_CHECK_HEADERS([sys/acl.h])
|
||||
if test $ac_cv_header_sys_acl_h = yes; then
|
||||
ac_save_LIBS=$LIBS
|
||||
|
||||
dnl Test for POSIX-draft-like API (Linux, FreeBSD, Mac OS X, IRIX, Tru64).
|
||||
dnl -lacl is needed on Linux, -lpacl is needed on OSF/1.
|
||||
if test $use_acl = 0; then
|
||||
AC_SEARCH_LIBS([acl_get_file], [acl pacl],
|
||||
[if test "$ac_cv_search_acl_get_file" != "none required"; then
|
||||
LIB_ACL=$ac_cv_search_acl_get_file
|
||||
fi
|
||||
AC_CHECK_FUNCS(
|
||||
[acl_get_file acl_get_fd acl_set_file acl_set_fd \
|
||||
acl_free acl_from_mode acl_from_text \
|
||||
acl_delete_def_file acl_extended_file \
|
||||
acl_delete_fd_np acl_delete_file_np \
|
||||
acl_copy_ext_native acl_create_entry_np \
|
||||
acl_to_short_text acl_free_text])
|
||||
# If the acl_get_file bug is detected, don't enable the ACL support.
|
||||
gl_ACL_GET_FILE([use_acl=1], [])
|
||||
if test $use_acl = 1; then
|
||||
dnl On Linux, additional API is declared in <acl/libacl.h>.
|
||||
AC_CHECK_HEADERS([acl/libacl.h])
|
||||
AC_REPLACE_FUNCS([acl_entries])
|
||||
AC_CACHE_CHECK([for ACL_FIRST_ENTRY],
|
||||
[gl_cv_acl_ACL_FIRST_ENTRY],
|
||||
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||||
[[#include <sys/types.h>
|
||||
#include <sys/acl.h>
|
||||
int type = ACL_FIRST_ENTRY;]])],
|
||||
[gl_cv_acl_ACL_FIRST_ENTRY=yes],
|
||||
[gl_cv_acl_ACL_FIRST_ENTRY=no])])
|
||||
if test $gl_cv_acl_ACL_FIRST_ENTRY = yes; then
|
||||
AC_DEFINE([HAVE_ACL_FIRST_ENTRY], [1],
|
||||
[Define to 1 if the constant ACL_FIRST_ENTRY exists.])
|
||||
fi
|
||||
dnl On Mac OS X, other types of ACLs are supported.
|
||||
AC_CACHE_CHECK([for ACL_TYPE_EXTENDED],
|
||||
[gl_cv_acl_ACL_TYPE_EXTENDED],
|
||||
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||||
[[#include <sys/types.h>
|
||||
#include <sys/acl.h>
|
||||
int type = ACL_TYPE_EXTENDED;]])],
|
||||
[gl_cv_acl_ACL_TYPE_EXTENDED=yes],
|
||||
[gl_cv_acl_ACL_TYPE_EXTENDED=no])])
|
||||
if test $gl_cv_acl_ACL_TYPE_EXTENDED = yes; then
|
||||
AC_DEFINE([HAVE_ACL_TYPE_EXTENDED], [1],
|
||||
[Define to 1 if the ACL type ACL_TYPE_EXTENDED exists.])
|
||||
fi
|
||||
else
|
||||
LIB_ACL=
|
||||
fi
|
||||
])
|
||||
fi
|
||||
|
||||
dnl Test for Solaris API (Solaris, Cygwin).
|
||||
if test $use_acl = 0; then
|
||||
AC_CHECK_FUNCS([facl])
|
||||
if test $ac_cv_func_facl = yes; then
|
||||
AC_SEARCH_LIBS([acl_trivial], [sec],
|
||||
[if test "$ac_cv_search_acl_trivial" != "none required"; then
|
||||
LIB_ACL=$ac_cv_search_acl_trivial
|
||||
fi
|
||||
])
|
||||
AC_CHECK_FUNCS([acl_trivial])
|
||||
use_acl=1
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl Test for HP-UX API.
|
||||
if test $use_acl = 0; then
|
||||
AC_CHECK_FUNCS([getacl])
|
||||
if test $ac_cv_func_getacl = yes; then
|
||||
use_acl=1
|
||||
fi
|
||||
dnl Test for HP-UX 11.11 API.
|
||||
AC_CHECK_HEADERS([aclv.h], [], [], [#include <sys/types.h>])
|
||||
fi
|
||||
|
||||
dnl Test for AIX API (AIX 5.3 or newer).
|
||||
if test $use_acl = 0; then
|
||||
AC_CHECK_FUNCS([aclx_get])
|
||||
if test $ac_cv_func_aclx_get = yes; then
|
||||
use_acl=1
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl Test for older AIX API.
|
||||
if test $use_acl = 0 || test "$ac_cv_func_aclx_get" = yes; then
|
||||
AC_CHECK_FUNCS([statacl])
|
||||
if test $ac_cv_func_statacl = yes; then
|
||||
use_acl=1
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl Test for NonStop Kernel API.
|
||||
if test $use_acl = 0; then
|
||||
AC_CHECK_FUNCS([aclsort])
|
||||
if test $ac_cv_func_aclsort = yes; then
|
||||
use_acl=1
|
||||
fi
|
||||
fi
|
||||
|
||||
LIBS=$ac_save_LIBS
|
||||
fi
|
||||
if test "x$enable_acl$use_acl" = "xyes0"; then
|
||||
AC_MSG_ERROR([ACLs enabled but support not detected])
|
||||
elif test "x$enable_acl$use_acl" = "xauto0"; then
|
||||
AC_MSG_WARN([libacl development library was not found or not usable.])
|
||||
AC_MSG_WARN([AC_PACKAGE_NAME will be built without ACL support.])
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([LIB_ACL])
|
||||
AC_DEFINE_UNQUOTED([USE_ACL], [$use_acl],
|
||||
[Define to nonzero if you want access control list support.])
|
||||
USE_ACL=$use_acl
|
||||
AC_SUBST([USE_ACL])
|
||||
])
|
||||
|
||||
# gl_ACL_GET_FILE(IF-WORKS, IF-NOT)
|
||||
# -------------------------------------
|
||||
# If 'acl_get_file' works (does not have a particular bug),
|
||||
# run IF-WORKS, otherwise, IF-NOT.
|
||||
# This tests for a Darwin 8.7.0 bug, whereby acl_get_file returns NULL,
|
||||
# but sets errno = ENOENT for an existing file or directory.
|
||||
AC_DEFUN([gl_ACL_GET_FILE],
|
||||
[
|
||||
AC_CACHE_CHECK([for working acl_get_file], [gl_cv_func_working_acl_get_file],
|
||||
[AC_RUN_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[#include <sys/types.h>
|
||||
#include <sys/acl.h>
|
||||
#include <errno.h>
|
||||
]],
|
||||
[[if (!acl_get_file (".", ACL_TYPE_ACCESS) && errno == ENOENT)
|
||||
return 1;
|
||||
return 0;
|
||||
]])],
|
||||
[gl_cv_func_working_acl_get_file=yes],
|
||||
[gl_cv_func_working_acl_get_file=no],
|
||||
[gl_cv_func_working_acl_get_file=cross-compiling])])
|
||||
|
||||
AS_IF([test $gl_cv_func_working_acl_get_file = yes], [$1], [$2])
|
||||
])
|
137
m4/errno_h.m4
Normal file
137
m4/errno_h.m4
Normal file
|
@ -0,0 +1,137 @@
|
|||
# errno_h.m4 serial 12
|
||||
dnl Copyright (C) 2004, 2006, 2008-2013 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
AC_DEFUN_ONCE([gl_HEADER_ERRNO_H],
|
||||
[
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_CACHE_CHECK([for complete errno.h], [gl_cv_header_errno_h_complete], [
|
||||
AC_EGREP_CPP([booboo],[
|
||||
#include <errno.h>
|
||||
#if !defined ETXTBSY
|
||||
booboo
|
||||
#endif
|
||||
#if !defined ENOMSG
|
||||
booboo
|
||||
#endif
|
||||
#if !defined EIDRM
|
||||
booboo
|
||||
#endif
|
||||
#if !defined ENOLINK
|
||||
booboo
|
||||
#endif
|
||||
#if !defined EPROTO
|
||||
booboo
|
||||
#endif
|
||||
#if !defined EMULTIHOP
|
||||
booboo
|
||||
#endif
|
||||
#if !defined EBADMSG
|
||||
booboo
|
||||
#endif
|
||||
#if !defined EOVERFLOW
|
||||
booboo
|
||||
#endif
|
||||
#if !defined ENOTSUP
|
||||
booboo
|
||||
#endif
|
||||
#if !defined ENETRESET
|
||||
booboo
|
||||
#endif
|
||||
#if !defined ECONNABORTED
|
||||
booboo
|
||||
#endif
|
||||
#if !defined ESTALE
|
||||
booboo
|
||||
#endif
|
||||
#if !defined EDQUOT
|
||||
booboo
|
||||
#endif
|
||||
#if !defined ECANCELED
|
||||
booboo
|
||||
#endif
|
||||
#if !defined EOWNERDEAD
|
||||
booboo
|
||||
#endif
|
||||
#if !defined ENOTRECOVERABLE
|
||||
booboo
|
||||
#endif
|
||||
#if !defined EILSEQ
|
||||
booboo
|
||||
#endif
|
||||
],
|
||||
[gl_cv_header_errno_h_complete=no],
|
||||
[gl_cv_header_errno_h_complete=yes])
|
||||
])
|
||||
if test $gl_cv_header_errno_h_complete = yes; then
|
||||
ERRNO_H=''
|
||||
else
|
||||
gl_NEXT_HEADERS([errno.h])
|
||||
ERRNO_H='errno.h'
|
||||
fi
|
||||
AC_SUBST([ERRNO_H])
|
||||
AM_CONDITIONAL([GL_GENERATE_ERRNO_H], [test -n "$ERRNO_H"])
|
||||
gl_REPLACE_ERRNO_VALUE([EMULTIHOP])
|
||||
gl_REPLACE_ERRNO_VALUE([ENOLINK])
|
||||
gl_REPLACE_ERRNO_VALUE([EOVERFLOW])
|
||||
])
|
||||
|
||||
# Assuming $1 = EOVERFLOW.
|
||||
# The EOVERFLOW errno value ought to be defined in <errno.h>, according to
|
||||
# POSIX. But some systems (like OpenBSD 4.0 or AIX 3) don't define it, and
|
||||
# some systems (like OSF/1) define it when _XOPEN_SOURCE_EXTENDED is defined.
|
||||
# Check for the value of EOVERFLOW.
|
||||
# Set the variables EOVERFLOW_HIDDEN and EOVERFLOW_VALUE.
|
||||
AC_DEFUN([gl_REPLACE_ERRNO_VALUE],
|
||||
[
|
||||
if test -n "$ERRNO_H"; then
|
||||
AC_CACHE_CHECK([for ]$1[ value], [gl_cv_header_errno_h_]$1, [
|
||||
AC_EGREP_CPP([yes],[
|
||||
#include <errno.h>
|
||||
#ifdef ]$1[
|
||||
yes
|
||||
#endif
|
||||
],
|
||||
[gl_cv_header_errno_h_]$1[=yes],
|
||||
[gl_cv_header_errno_h_]$1[=no])
|
||||
if test $gl_cv_header_errno_h_]$1[ = no; then
|
||||
AC_EGREP_CPP([yes],[
|
||||
#define _XOPEN_SOURCE_EXTENDED 1
|
||||
#include <errno.h>
|
||||
#ifdef ]$1[
|
||||
yes
|
||||
#endif
|
||||
], [gl_cv_header_errno_h_]$1[=hidden])
|
||||
if test $gl_cv_header_errno_h_]$1[ = hidden; then
|
||||
dnl The macro exists but is hidden.
|
||||
dnl Define it to the same value.
|
||||
AC_COMPUTE_INT([gl_cv_header_errno_h_]$1, $1, [
|
||||
#define _XOPEN_SOURCE_EXTENDED 1
|
||||
#include <errno.h>
|
||||
/* The following two lines are a workaround against an autoconf-2.52 bug. */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
])
|
||||
fi
|
||||
fi
|
||||
])
|
||||
case $gl_cv_header_errno_h_]$1[ in
|
||||
yes | no)
|
||||
]$1[_HIDDEN=0; ]$1[_VALUE=
|
||||
;;
|
||||
*)
|
||||
]$1[_HIDDEN=1; ]$1[_VALUE="$gl_cv_header_errno_h_]$1["
|
||||
;;
|
||||
esac
|
||||
AC_SUBST($1[_HIDDEN])
|
||||
AC_SUBST($1[_VALUE])
|
||||
fi
|
||||
])
|
||||
|
||||
dnl Autoconf >= 2.61 has AC_COMPUTE_INT built-in.
|
||||
dnl Remove this when we can assume autoconf >= 2.61.
|
||||
m4_ifdef([AC_COMPUTE_INT], [], [
|
||||
AC_DEFUN([AC_COMPUTE_INT], [_AC_COMPUTE_INT([$2],[$1],[$3],[$4])])
|
||||
])
|
|
@ -56,6 +56,7 @@ AC_DEFUN([gl_EARLY],
|
|||
# Code from module dtotimespec:
|
||||
# Code from module dup2:
|
||||
# Code from module environ:
|
||||
# Code from module errno:
|
||||
# Code from module euidaccess:
|
||||
# Code from module execinfo:
|
||||
# Code from module extensions:
|
||||
|
@ -94,6 +95,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 readlink:
|
||||
# Code from module readlinkat:
|
||||
# Code from module root-uid:
|
||||
|
@ -179,6 +181,7 @@ AC_DEFUN([gl_INIT],
|
|||
gl_UNISTD_MODULE_INDICATOR([dup2])
|
||||
gl_ENVIRON
|
||||
gl_UNISTD_MODULE_INDICATOR([environ])
|
||||
gl_HEADER_ERRNO_H
|
||||
gl_EXECINFO_H
|
||||
AC_REQUIRE([gl_EXTERN_INLINE])
|
||||
gl_FUNC_FACCESSAT
|
||||
|
@ -287,6 +290,7 @@ 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])
|
||||
|
@ -733,6 +737,10 @@ AC_DEFUN([gl_FILE_LIST], [
|
|||
build-aux/snippet/arg-nonnull.h
|
||||
build-aux/snippet/c++defs.h
|
||||
build-aux/snippet/warn-on-use.h
|
||||
lib/acl-errno-valid.c
|
||||
lib/acl-internal.h
|
||||
lib/acl.h
|
||||
lib/acl_entries.c
|
||||
lib/alloca.in.h
|
||||
lib/allocator.c
|
||||
lib/allocator.h
|
||||
|
@ -751,6 +759,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
|||
lib/dtoastr.c
|
||||
lib/dtotimespec.c
|
||||
lib/dup2.c
|
||||
lib/errno.in.h
|
||||
lib/euidaccess.c
|
||||
lib/execinfo.c
|
||||
lib/execinfo.in.h
|
||||
|
@ -758,6 +767,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
|||
lib/fcntl.in.h
|
||||
lib/fdatasync.c
|
||||
lib/fdopendir.c
|
||||
lib/file-has-acl.c
|
||||
lib/filemode.c
|
||||
lib/filemode.h
|
||||
lib/fpending.c
|
||||
|
@ -792,6 +802,8 @@ AC_DEFUN([gl_FILE_LIST], [
|
|||
lib/pselect.c
|
||||
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
|
||||
|
@ -843,6 +855,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
|||
lib/verify.h
|
||||
lib/xalloc-oversized.h
|
||||
m4/00gnulib.m4
|
||||
m4/acl.m4
|
||||
m4/alloca.m4
|
||||
m4/c-strtod.m4
|
||||
m4/clock_time.m4
|
||||
|
@ -850,6 +863,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
|||
m4/dirent_h.m4
|
||||
m4/dup2.m4
|
||||
m4/environ.m4
|
||||
m4/errno_h.m4
|
||||
m4/euidaccess.m4
|
||||
m4/execinfo.m4
|
||||
m4/extensions.m4
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2013-05-07 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Use Gnulib ACL implementation, for benefit of Solaris etc. (Bug#14295)
|
||||
* config.nt (HAVE_ACL_SET_FILE): Rename from HAVE_POSIX_ACL.
|
||||
* inc/ms-w32.h (EOPNOTSUPP): New macro.
|
||||
|
||||
2013-04-09 Ken Brown <kbrown@cornell.edu>
|
||||
|
||||
* emacs.rc: Use 64-bit manifest for 64-bit Cygwin build.
|
||||
|
|
|
@ -756,7 +756,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
|||
#undef HAVE_PNG_H
|
||||
|
||||
/* Define to 1 if using POSIX ACL support. */
|
||||
#define HAVE_POSIX_ACL 1
|
||||
#define HAVE_ACL_SET_FILE 1
|
||||
|
||||
/* Define to 1 if you have the `posix_memalign' function. */
|
||||
#undef HAVE_POSIX_MEMALIGN
|
||||
|
|
|
@ -346,6 +346,12 @@ extern struct tm *localtime_r (time_t const * restrict, struct tm * restrict);
|
|||
#define ENOTSUP ENOSYS
|
||||
#endif
|
||||
|
||||
/* WINDOWSNT <errno.h> doesn't define EOPNOTSUPP, and we don't have
|
||||
'configure' working yet so we can't rely on the Gnulib replacement
|
||||
errno.h defining EOPNOTSUPP. Work around the problem by defining
|
||||
it here. */
|
||||
#define EOPNOTSUPP 130
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef int sigset_t;
|
||||
typedef int ssize_t;
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
2013-05-07 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Use Gnulib ACL implementation, for benefit of Solaris etc. (Bug#14295)
|
||||
* Makefile.in (LIB_ACL): New macro.
|
||||
(LIBACL_LIBS): Remove.
|
||||
(LIBES): Use LIB_ACL, not LIBACL_LIBS.
|
||||
* fileio.c: Include <acl.h>.
|
||||
Use HAVE_ACL_SET_FILE rather than HAVE_POSIX_ACL.
|
||||
(ACL_NOT_WELL_SUPPORTED): Remove. All uses replaced by
|
||||
!acl_errno_valid.
|
||||
(Fcopy_file) [!WINDOWSNT]: Use qcopy_acl instead of rolling
|
||||
it ourselves.
|
||||
|
||||
* unexelf.c: Don't assume ElfW (Half) fits in int.
|
||||
(entry_address, find_section, unexec): Use ptrdiff_t, not int,
|
||||
when dealing with ElfW (Half) values, since they can exceed 2**31
|
||||
|
|
|
@ -137,6 +137,7 @@ LIBOTF_LIBS = @LIBOTF_LIBS@
|
|||
M17N_FLT_CFLAGS = @M17N_FLT_CFLAGS@
|
||||
M17N_FLT_LIBS = @M17N_FLT_LIBS@
|
||||
|
||||
LIB_ACL=@LIB_ACL@
|
||||
LIB_CLOCK_GETTIME=@LIB_CLOCK_GETTIME@
|
||||
LIB_EACCESS=@LIB_EACCESS@
|
||||
LIB_FDATASYNC=@LIB_FDATASYNC@
|
||||
|
@ -288,8 +289,6 @@ LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
|
|||
LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
|
||||
LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
|
||||
|
||||
LIBACL_LIBS = @LIBACL_LIBS@
|
||||
|
||||
LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@
|
||||
|
||||
INTERVALS_H = dispextern.h intervals.h composite.h
|
||||
|
@ -397,13 +396,13 @@ ALLOBJS = $(VMLIMIT_OBJ) $(obj) $(otherobj)
|
|||
## Construct full set of libraries to be linked.
|
||||
LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
|
||||
$(LIBX_OTHER) $(LIBSOUND) \
|
||||
$(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_CLOCK_GETTIME) \
|
||||
$(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_ACL) $(LIB_CLOCK_GETTIME) \
|
||||
$(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
|
||||
$(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) \
|
||||
$(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
|
||||
$(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
|
||||
$(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
|
||||
$(LIBACL_LIBS) $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(LIB_PTHREAD_SIGMASK) \
|
||||
$(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(LIB_PTHREAD_SIGMASK) \
|
||||
$(LIB_MATH)
|
||||
|
||||
all: emacs$(EXEEXT) $(OTHER_FILES)
|
||||
|
|
73
src/fileio.c
73
src/fileio.c
|
@ -36,7 +36,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
|||
#include <selinux/context.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POSIX_ACL
|
||||
#ifdef HAVE_ACL_SET_FILE
|
||||
#include <sys/acl.h>
|
||||
#endif
|
||||
|
||||
|
@ -81,26 +81,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
|||
#define DRIVE_LETTER(x) c_tolower (x)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POSIX_ACL
|
||||
/* FIXME: this macro was copied from gnulib's private acl-internal.h
|
||||
header file. */
|
||||
/* Recognize some common errors such as from an NFS mount that does
|
||||
not support ACLs, even when local drives do. */
|
||||
#if defined __APPLE__ && defined __MACH__ /* Mac OS X */
|
||||
#define ACL_NOT_WELL_SUPPORTED(Err) \
|
||||
((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY || (Err) == ENOENT)
|
||||
#elif defined EOPNOTSUPP /* Tru64 NFS */
|
||||
#define ACL_NOT_WELL_SUPPORTED(Err) \
|
||||
((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY || (Err) == EOPNOTSUPP)
|
||||
#elif defined WINDOWSNT
|
||||
#define ACL_NOT_WELL_SUPPORTED(Err) ((Err) == ENOTSUP)
|
||||
#else
|
||||
#define ACL_NOT_WELL_SUPPORTED(Err) \
|
||||
((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY)
|
||||
#endif
|
||||
#endif /* HAVE_POSIX_ACL */
|
||||
|
||||
#include "systime.h"
|
||||
#include <acl.h>
|
||||
#include <allocator.h>
|
||||
#include <careadlinkat.h>
|
||||
#include <stat-time.h>
|
||||
|
@ -1988,7 +1970,7 @@ entries (depending on how Emacs was built). */)
|
|||
security_context_t con;
|
||||
int conlength = 0;
|
||||
#endif
|
||||
#ifdef HAVE_POSIX_ACL
|
||||
#ifdef WINDOWSNT
|
||||
acl_t acl = NULL;
|
||||
#endif
|
||||
|
||||
|
@ -2028,11 +2010,9 @@ entries (depending on how Emacs was built). */)
|
|||
#ifdef WINDOWSNT
|
||||
if (!NILP (preserve_extended_attributes))
|
||||
{
|
||||
#ifdef HAVE_POSIX_ACL
|
||||
acl = acl_get_file (SDATA (encoded_file), ACL_TYPE_ACCESS);
|
||||
if (acl == NULL && !ACL_NOT_WELL_SUPPORTED (errno))
|
||||
if (acl == NULL && acl_errno_valid (errno))
|
||||
report_file_error ("Getting ACL", Fcons (file, Qnil));
|
||||
#endif
|
||||
}
|
||||
if (!CopyFile (SDATA (encoded_file),
|
||||
SDATA (encoded_newname),
|
||||
|
@ -2069,17 +2049,15 @@ entries (depending on how Emacs was built). */)
|
|||
/* Restore original attributes. */
|
||||
SetFileAttributes (filename, attributes);
|
||||
}
|
||||
#ifdef HAVE_POSIX_ACL
|
||||
if (acl != NULL)
|
||||
{
|
||||
bool fail =
|
||||
acl_set_file (SDATA (encoded_newname), ACL_TYPE_ACCESS, acl) != 0;
|
||||
if (fail && !ACL_NOT_WELL_SUPPORTED (errno))
|
||||
if (fail && acl_errno_valid (errno))
|
||||
report_file_error ("Setting ACL", Fcons (newname, Qnil));
|
||||
|
||||
acl_free (acl);
|
||||
}
|
||||
#endif
|
||||
#else /* not WINDOWSNT */
|
||||
immediate_quit = 1;
|
||||
ifd = emacs_open (SSDATA (encoded_file), O_RDONLY, 0);
|
||||
|
@ -2103,12 +2081,6 @@ entries (depending on how Emacs was built). */)
|
|||
report_file_error ("Doing fgetfilecon", Fcons (file, Qnil));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POSIX_ACL
|
||||
acl = acl_get_fd (ifd);
|
||||
if (acl == NULL && !ACL_NOT_WELL_SUPPORTED (errno))
|
||||
report_file_error ("Getting ACL", Fcons (file, Qnil));
|
||||
#endif
|
||||
}
|
||||
|
||||
if (out_st.st_mode != 0
|
||||
|
@ -2156,7 +2128,7 @@ entries (depending on how Emacs was built). */)
|
|||
immediate_quit = 0;
|
||||
|
||||
#ifndef MSDOS
|
||||
/* Preserve the original file modes, and if requested, also its
|
||||
/* Preserve the original file permissions, and if requested, also its
|
||||
owner and group. */
|
||||
{
|
||||
mode_t mode_mask = 07777;
|
||||
|
@ -2173,8 +2145,16 @@ entries (depending on how Emacs was built). */)
|
|||
mode_mask |= 02000;
|
||||
}
|
||||
}
|
||||
if (fchmod (ofd, st.st_mode & mode_mask) != 0)
|
||||
report_file_error ("Doing chmod", Fcons (newname, Qnil));
|
||||
|
||||
switch (!NILP (preserve_extended_attributes)
|
||||
? qcopy_acl (SSDATA (encoded_file), ifd,
|
||||
SSDATA (encoded_newname), ofd,
|
||||
st.st_mode & mode_mask)
|
||||
: fchmod (ofd, st.st_mode & mode_mask))
|
||||
{
|
||||
case -2: report_file_error ("Copying permissions from", list1 (file));
|
||||
case -1: report_file_error ("Copying permissions to", list1 (newname));
|
||||
}
|
||||
}
|
||||
#endif /* not MSDOS */
|
||||
|
||||
|
@ -2191,17 +2171,6 @@ entries (depending on how Emacs was built). */)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POSIX_ACL
|
||||
if (acl != NULL)
|
||||
{
|
||||
bool fail = acl_set_fd (ofd, acl) != 0;
|
||||
if (fail && !ACL_NOT_WELL_SUPPORTED (errno))
|
||||
report_file_error ("Setting ACL", Fcons (newname, Qnil));
|
||||
|
||||
acl_free (acl);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!NILP (keep_time))
|
||||
{
|
||||
EMACS_TIME atime = get_stat_atime (&st);
|
||||
|
@ -3111,7 +3080,7 @@ was unable to determine the ACL entries. */)
|
|||
{
|
||||
Lisp_Object absname;
|
||||
Lisp_Object handler;
|
||||
#ifdef HAVE_POSIX_ACL
|
||||
#ifdef HAVE_ACL_SET_FILE
|
||||
acl_t acl;
|
||||
Lisp_Object acl_string;
|
||||
char *str;
|
||||
|
@ -3126,7 +3095,7 @@ was unable to determine the ACL entries. */)
|
|||
if (!NILP (handler))
|
||||
return call2 (handler, Qfile_acl, absname);
|
||||
|
||||
#ifdef HAVE_POSIX_ACL
|
||||
#ifdef HAVE_ACL_SET_FILE
|
||||
absname = ENCODE_FILE (absname);
|
||||
|
||||
acl = acl_get_file (SSDATA (absname), ACL_TYPE_ACCESS);
|
||||
|
@ -3164,7 +3133,7 @@ support. */)
|
|||
{
|
||||
Lisp_Object absname;
|
||||
Lisp_Object handler;
|
||||
#ifdef HAVE_POSIX_ACL
|
||||
#ifdef HAVE_ACL_SET_FILE
|
||||
Lisp_Object encoded_absname;
|
||||
acl_t acl;
|
||||
bool fail;
|
||||
|
@ -3178,7 +3147,7 @@ support. */)
|
|||
if (!NILP (handler))
|
||||
return call3 (handler, Qset_file_acl, absname, acl_string);
|
||||
|
||||
#ifdef HAVE_POSIX_ACL
|
||||
#ifdef HAVE_ACL_SET_FILE
|
||||
if (STRINGP (acl_string))
|
||||
{
|
||||
acl = acl_from_text (SSDATA (acl_string));
|
||||
|
@ -3193,7 +3162,7 @@ support. */)
|
|||
fail = (acl_set_file (SSDATA (encoded_absname), ACL_TYPE_ACCESS,
|
||||
acl)
|
||||
!= 0);
|
||||
if (fail && !ACL_NOT_WELL_SUPPORTED (errno))
|
||||
if (fail && acl_errno_valid (errno))
|
||||
report_file_error ("Setting ACL", Fcons (absname, Qnil));
|
||||
|
||||
acl_free (acl);
|
||||
|
|
Loading…
Add table
Reference in a new issue