=== modified file 'ChangeLog' --- ChangeLog 2013-04-29 04:48:30 +0000 +++ ChangeLog 2013-04-29 06:07:42 +0000 @@ -1,5 +1,19 @@ 2013-04-29 Paul Eggert + 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. + Merge from gnulib, incorporating: 2013-04-28 extern-inline: work around bug in Sun c99 === modified file 'admin/ChangeLog' --- admin/ChangeLog 2013-04-02 01:18:40 +0000 +++ admin/ChangeLog 2013-04-29 06:07:42 +0000 @@ -1,3 +1,9 @@ +2013-04-29 Paul Eggert + + 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 Use UTF-8 for most files with non-ASCII characters (Bug#13936). === modified file 'admin/merge-gnulib' --- admin/merge-gnulib 2013-03-13 18:42:22 +0000 +++ admin/merge-gnulib 2013-04-29 06:07:42 +0000 @@ -33,7 +33,7 @@ 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_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 === modified file 'configure.ac' --- configure.ac 2013-04-26 19:31:09 +0000 +++ configure.ac 2013-04-27 19:40:49 +0000 @@ -199,7 +199,6 @@ 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 @@ 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 === modified file 'etc/ChangeLog' --- etc/ChangeLog 2013-04-24 16:50:14 +0000 +++ etc/ChangeLog 2013-04-29 04:50:26 +0000 @@ -1,3 +1,9 @@ +2013-04-29 Paul Eggert + + 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-04-24 Tassilo Horn * themes/tsdh-dark-theme.el (tsdh-dark): Add ido faces and remove === modified file 'etc/NEWS' --- etc/NEWS 2013-04-27 20:55:00 +0000 +++ etc/NEWS 2013-04-28 00:00:19 +0000 @@ -23,10 +23,10 @@ * 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. === modified file 'lib/Makefile.am' --- lib/Makefile.am 2013-04-07 06:21:40 +0000 +++ lib/Makefile.am 2013-04-17 05:21:33 +0000 @@ -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 === added file 'lib/acl-errno-valid.c' --- lib/acl-errno-valid.c 1970-01-01 00:00:00 +0000 +++ lib/acl-errno-valid.c 2013-04-17 05:21:33 +0000 @@ -0,0 +1,48 @@ +/* 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 . + + Written by Paul Eggert. */ + +#include + +#include + +#include + +/* 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 + case ENOTSUP: return false; +#endif + case EOPNOTSUPP: return false; + default: return true; + } +} === added file 'lib/acl-internal.h' --- lib/acl-internal.h 1970-01-01 00:00:00 +0000 +++ lib/acl-internal.h 2013-04-17 05:21:33 +0000 @@ -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 . + + Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */ + +#include "acl.h" + +#include +#include + +/* All systems define the ACL related API in . */ +#if HAVE_SYS_ACL_H +# include +#endif +#if defined HAVE_FACL && ! defined GETACLCNT && defined ACL_CNT +# define GETACLCNT ACL_CNT +#endif + +/* On Linux, additional ACL related API is available in . */ +#ifdef HAVE_ACL_LIBACL_H +# include +#endif + +/* On HP-UX >= 11.11, additional ACL API is available in . */ +#if HAVE_ACLV_H +# include +# include +/* HP-UX 11.11 lacks these declarations. */ +extern int acl (char *, int, int, struct acl *); +extern int aclsort (int, int, struct acl *); +#endif + +#include + +#include +#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 === added file 'lib/acl.h' --- lib/acl.h 1970-01-01 00:00:00 +0000 +++ lib/acl.h 2013-04-17 05:21:33 +0000 @@ -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 . + + Written by Paul Eggert. */ + +#include +#include +#include + +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); === added file 'lib/acl_entries.c' --- lib/acl_entries.c 1970-01-01 00:00:00 +0000 +++ lib/acl_entries.c 2013-04-17 05:21:33 +0000 @@ -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 . + + Written by Paul Eggert and Andreas Gruenbacher. */ + +#include + +#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; +} === added file 'lib/errno.in.h' --- lib/errno.in.h 1970-01-01 00:00:00 +0000 +++ lib/errno.in.h 2013-04-29 06:07:42 +0000 @@ -0,0 +1,279 @@ +/* A POSIX-like . + + 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 . */ + +#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 . */ +# 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 */ === added file 'lib/file-has-acl.c' --- lib/file-has-acl.c 1970-01-01 00:00:00 +0000 +++ lib/file-has-acl.c 2013-04-18 01:35:08 +0000 @@ -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 . + + 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 + +#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 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 + (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; +} === modified file 'lib/gnulib.mk' --- lib/gnulib.mk 2013-03-13 18:42:22 +0000 +++ lib/gnulib.mk 2013-04-29 06:07:42 +0000 @@ -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 @@ ## end gnulib module dup2 +## begin gnulib module errno + +BUILT_SOURCES += $(ERRNO_H) + +# We need the following in order to create 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 @@ ## 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 === modified file 'lib/makefile.w32-in' --- lib/makefile.w32-in 2013-02-12 03:52:04 +0000 +++ lib/makefile.w32-in 2013-04-29 06:07:42 +0000 @@ -23,7 +23,8 @@ 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 @@ 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) \ === added file 'lib/qcopy-acl.c' --- lib/qcopy-acl.c 1970-01-01 00:00:00 +0000 +++ lib/qcopy-acl.c 2013-04-17 05:21:33 +0000 @@ -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 . + + Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */ + +#include + +#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 + 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 +} === added file 'lib/qset-acl.c' --- lib/qset-acl.c 1970-01-01 00:00:00 +0000 +++ lib/qset-acl.c 2013-04-28 00:46:36 +0000 @@ -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 . + + Written by Paul Eggert and Andreas Gruenbacher, and Bruno Haible. */ + +#include + +#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 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 +} === added file 'm4/acl.m4' --- m4/acl.m4 1970-01-01 00:00:00 +0000 +++ m4/acl.m4 2013-04-17 05:21:33 +0000 @@ -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 . + 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 . + 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 +#include +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 +#include +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 ]) + 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 + #include + #include + ]], + [[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]) +]) === added file 'm4/errno_h.m4' --- m4/errno_h.m4 1970-01-01 00:00:00 +0000 +++ m4/errno_h.m4 2013-04-29 06:07:42 +0000 @@ -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 +#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 , 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 +#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 +#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 +/* The following two lines are a workaround against an autoconf-2.52 bug. */ +#include +#include +]) + 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])]) +]) === modified file 'm4/gnulib-comp.m4' --- m4/gnulib-comp.m4 2013-03-13 18:42:22 +0000 +++ m4/gnulib-comp.m4 2013-04-29 06:07:42 +0000 @@ -56,6 +56,7 @@ # 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 @@ # 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ m4/dirent_h.m4 m4/dup2.m4 m4/environ.m4 + m4/errno_h.m4 m4/euidaccess.m4 m4/execinfo.m4 m4/extensions.m4 === modified file 'nt/ChangeLog' --- nt/ChangeLog 2013-04-09 02:38:56 +0000 +++ nt/ChangeLog 2013-04-29 06:07:42 +0000 @@ -1,3 +1,9 @@ +2013-04-29 Paul Eggert + + Use Gnulib ACL implementation, for benefit of Solaris etc. (Bug#14295) + * config.nt (HAVE_ACL_SET_FILE): Rename from HAVE_POSIX_ACL. + (EOPNOTSUP): New macro. + 2013-04-09 Ken Brown * emacs.rc: Use 64-bit manifest for 64-bit Cygwin build. === modified file 'nt/config.nt' --- nt/config.nt 2013-03-30 07:10:58 +0000 +++ nt/config.nt 2013-04-29 06:07:42 +0000 @@ -756,7 +756,7 @@ #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 @@ -1723,6 +1723,12 @@ /* Define as `fork' if `vfork' does not work. */ #undef vfork +/* WINDOWSNT 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 + #include #endif /* EMACS_CONFIG_H */ === modified file 'src/ChangeLog' --- src/ChangeLog 2013-04-28 18:21:01 +0000 +++ src/ChangeLog 2013-04-29 06:07:42 +0000 @@ -1,3 +1,16 @@ +2013-04-29 Paul Eggert + + 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 . + 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. + 2013-04-28 Eli Zaretskii * coding.c (decode_coding_gap): Don't remove the character before === modified file 'src/Makefile.in' --- src/Makefile.in 2013-04-22 05:18:30 +0000 +++ src/Makefile.in 2013-04-27 19:40:49 +0000 @@ -137,6 +137,7 @@ 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@ @@ -282,8 +283,6 @@ 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 @@ -391,13 +390,13 @@ ## 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) \ $(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) === modified file 'src/fileio.c' --- src/fileio.c 2013-04-07 16:18:41 +0000 +++ src/fileio.c 2013-04-29 06:07:42 +0000 @@ -36,7 +36,7 @@ #include #endif -#ifdef HAVE_POSIX_ACL +#ifdef HAVE_ACL_SET_FILE #include #endif @@ -81,26 +81,8 @@ #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 #include #include #include @@ -1988,7 +1970,7 @@ security_context_t con; int conlength = 0; #endif -#ifdef HAVE_POSIX_ACL +#ifdef WINDOWSNT acl_t acl = NULL; #endif @@ -2028,11 +2010,9 @@ #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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ } #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 @@ { 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 @@ 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 @@ { 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 @@ 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 @@ 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);