aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorPaul Eggert2013-05-07 14:34:03 -0700
committerPaul Eggert2013-05-07 14:34:03 -0700
commitffdc270a762ee93261f133632a9f82ea6ace9424 (patch)
treec1eacab0759fb3725a6fc99a089cc8f3f78644ac /lib
parentad64371062c05222227d7d573075c81b1f046630 (diff)
downloademacs-ffdc270a762ee93261f133632a9f82ea6ace9424.tar.gz
emacs-ffdc270a762ee93261f133632a9f82ea6ace9424.zip
Use Gnulib ACL implementation, for benefit of Solaris etc.
* configure.ac: Remove -with-acl option, since Gnulib does that for us now. (LIBACL_LIBS): Remove; no longer needed. * lib/Makefile.am (CLEANFILES, SUFFIXES): New (empty) macros, for the benefit of the new ACL implementation. * lib/makefile.w32-in (GNULIBOBJS): Add $(BLD)/acl-errno-valid.$(O). ($(BLD)/acl-errno-valid.$(O)): New rule. * lib/acl-errno-valid.c, lib/acl-internal.h, lib/acl.h: * lib/acl_entries.c, lib/errno.in.h, lib/file-has-acl.c: * lib/qcopy-acl.c, lib/qset-acl.c, m4/acl.m4, m4/errno_h.m4: New files, taken from gnulib. * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. * admin/merge-gnulib (GNULIB_MODULES): Add qacl. (GNULIB_TOOL_FLAGS): Do not avoid errno. * etc/NEWS: Emacs is no longer limited to POSIX ACLs. --disable-acl, not --without-acl, since we're now using Gnulib's implementation. * nt/config.nt (HAVE_ACL_SET_FILE): Rename from HAVE_POSIX_ACL. * nt/inc/ms-w32.h (EOPNOTSUPP): New macro. * src/Makefile.in (LIB_ACL): New macro. (LIBACL_LIBS): Remove. (LIBES): Use LIB_ACL, not LIBACL_LIBS. * src/fileio.c: Include <acl.h>. Use HAVE_ACL_SET_FILE rather than HAVE_POSIX_ACL. (ACL_NOT_WELL_SUPPORTED): Remove. All uses replaced by !acl_errno_valid. (Fcopy_file) [!WINDOWSNT]: Use qcopy_acl instead of rolling it ourselves. Fixes: debbugs:14295
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/acl-errno-valid.c52
-rw-r--r--lib/acl-internal.h250
-rw-r--r--lib/acl.h30
-rw-r--r--lib/acl_entries.c75
-rw-r--r--lib/errno.in.h279
-rw-r--r--lib/file-has-acl.c918
-rw-r--r--lib/gnulib.mk46
-rw-r--r--lib/makefile.w32-in9
-rw-r--r--lib/qcopy-acl.c583
-rw-r--r--lib/qset-acl.c676
11 files changed, 2918 insertions, 2 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index d8979a1cf74..c72e0904221 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,8 +1,10 @@
1BUILT_SOURCES = 1BUILT_SOURCES =
2CLEANFILES =
2EXTRA_DIST = 3EXTRA_DIST =
3MOSTLYCLEANDIRS = 4MOSTLYCLEANDIRS =
4MOSTLYCLEANFILES = 5MOSTLYCLEANFILES =
5noinst_LIBRARIES = 6noinst_LIBRARIES =
7SUFFIXES =
6 8
7AM_CFLAGS = $(PROFILING_CFLAGS) $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS) 9AM_CFLAGS = $(PROFILING_CFLAGS) $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS)
8DEFAULT_INCLUDES = -I. -I$(top_srcdir)/lib -I../src -I$(top_srcdir)/src 10DEFAULT_INCLUDES = -I. -I$(top_srcdir)/lib -I../src -I$(top_srcdir)/src
diff --git a/lib/acl-errno-valid.c b/lib/acl-errno-valid.c
new file mode 100644
index 00000000000..a391d077f5c
--- /dev/null
+++ b/lib/acl-errno-valid.c
@@ -0,0 +1,52 @@
1/* Test whether ACLs are well supported on this system.
2
3 Copyright 2013 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 Written by Paul Eggert. */
19
20#include <config.h>
21
22#include <acl.h>
23
24#include <errno.h>
25
26/* Return true if errno value ERRNUM indicates that ACLs are well
27 supported on this system. ERRNUM should be an errno value obtained
28 after an ACL-related system call fails. */
29bool
30acl_errno_valid (int errnum)
31{
32 /* Recognize some common errors such as from an NFS mount that does
33 not support ACLs, even when local drives do. */
34 switch (errnum)
35 {
36 case EBUSY: return false;
37 case EINVAL: return false;
38#if defined __APPLE__ && defined __MACH__
39 case ENOENT: return false;
40#endif
41 case ENOSYS: return false;
42
43#if defined ENOTSUP && ENOTSUP != EOPNOTSUPP
44# if ENOTSUP != ENOSYS /* Needed for the MS-Windows port of GNU Emacs. */
45 case ENOTSUP: return false;
46# endif
47#endif
48
49 case EOPNOTSUPP: return false;
50 default: return true;
51 }
52}
diff --git a/lib/acl-internal.h b/lib/acl-internal.h
new file mode 100644
index 00000000000..7e6d77a5fd4
--- /dev/null
+++ b/lib/acl-internal.h
@@ -0,0 +1,250 @@
1/* Internal implementation of access control lists.
2
3 Copyright (C) 2002-2003, 2005-2013 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
19
20#include "acl.h"
21
22#include <stdbool.h>
23#include <stdlib.h>
24
25/* All systems define the ACL related API in <sys/acl.h>. */
26#if HAVE_SYS_ACL_H
27# include <sys/acl.h>
28#endif
29#if defined HAVE_FACL && ! defined GETACLCNT && defined ACL_CNT
30# define GETACLCNT ACL_CNT
31#endif
32
33/* On Linux, additional ACL related API is available in <acl/libacl.h>. */
34#ifdef HAVE_ACL_LIBACL_H
35# include <acl/libacl.h>
36#endif
37
38/* On HP-UX >= 11.11, additional ACL API is available in <aclv.h>. */
39#if HAVE_ACLV_H
40# include <sys/types.h>
41# include <aclv.h>
42/* HP-UX 11.11 lacks these declarations. */
43extern int acl (char *, int, int, struct acl *);
44extern int aclsort (int, int, struct acl *);
45#endif
46
47#include <errno.h>
48
49#include <limits.h>
50#ifndef MIN
51# define MIN(a,b) ((a) < (b) ? (a) : (b))
52#endif
53
54#ifndef SIZE_MAX
55# define SIZE_MAX ((size_t) -1)
56#endif
57
58#ifndef HAVE_FCHMOD
59# define HAVE_FCHMOD false
60# define fchmod(fd, mode) (-1)
61#endif
62
63_GL_INLINE_HEADER_BEGIN
64#ifndef ACL_INTERNAL_INLINE
65# define ACL_INTERNAL_INLINE _GL_INLINE
66#endif
67
68#if USE_ACL
69
70# if HAVE_ACL_GET_FILE
71/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
72/* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
73
74# ifndef MIN_ACL_ENTRIES
75# define MIN_ACL_ENTRIES 4
76# endif
77
78/* POSIX 1003.1e (draft 17) */
79# ifdef HAVE_ACL_GET_FD
80/* Most platforms have a 1-argument acl_get_fd, only OSF/1 has a 2-argument
81 macro(!). */
82# if HAVE_ACL_FREE_TEXT /* OSF/1 */
83ACL_INTERNAL_INLINE acl_t
84rpl_acl_get_fd (int fd)
85{
86 return acl_get_fd (fd, ACL_TYPE_ACCESS);
87}
88# undef acl_get_fd
89# define acl_get_fd rpl_acl_get_fd
90# endif
91# else
92# define HAVE_ACL_GET_FD false
93# undef acl_get_fd
94# define acl_get_fd(fd) (NULL)
95# endif
96
97/* POSIX 1003.1e (draft 17) */
98# ifdef HAVE_ACL_SET_FD
99/* Most platforms have a 2-argument acl_set_fd, only OSF/1 has a 3-argument
100 macro(!). */
101# if HAVE_ACL_FREE_TEXT /* OSF/1 */
102ACL_INTERNAL_INLINE int
103rpl_acl_set_fd (int fd, acl_t acl)
104{
105 return acl_set_fd (fd, ACL_TYPE_ACCESS, acl);
106}
107# undef acl_set_fd
108# define acl_set_fd rpl_acl_set_fd
109# endif
110# else
111# define HAVE_ACL_SET_FD false
112# undef acl_set_fd
113# define acl_set_fd(fd, acl) (-1)
114# endif
115
116/* POSIX 1003.1e (draft 13) */
117# if ! HAVE_ACL_FREE_TEXT
118# define acl_free_text(buf) acl_free (buf)
119# endif
120
121/* Linux-specific */
122# ifndef HAVE_ACL_EXTENDED_FILE
123# define HAVE_ACL_EXTENDED_FILE false
124# define acl_extended_file(name) (-1)
125# endif
126
127/* Linux-specific */
128# ifndef HAVE_ACL_FROM_MODE
129# define HAVE_ACL_FROM_MODE false
130# define acl_from_mode(mode) (NULL)
131# endif
132
133/* Set to 1 if a file's mode is implicit by the ACL.
134 Set to 0 if a file's mode is stored independently from the ACL. */
135# if (HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP) || defined __sgi /* Mac OS X, IRIX */
136# define MODE_INSIDE_ACL 0
137# else
138# define MODE_INSIDE_ACL 1
139# endif
140
141/* Return the number of entries in ACL.
142 Return -1 and set errno upon failure to determine it. */
143/* Define a replacement for acl_entries if needed. (Only Linux has it.) */
144# if !HAVE_ACL_ENTRIES
145# define acl_entries rpl_acl_entries
146extern int acl_entries (acl_t);
147# endif
148
149# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
150/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
151 Return 1 if the given ACL is non-trivial.
152 Return 0 if it is trivial. */
153extern int acl_extended_nontrivial (acl_t);
154# else
155/* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS.
156 Return 1 if the given ACL is non-trivial.
157 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
158 Return -1 and set errno upon failure to determine it. */
159extern int acl_access_nontrivial (acl_t);
160# endif
161
162# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
163
164/* Set to 1 if a file's mode is implicit by the ACL.
165 Set to 0 if a file's mode is stored independently from the ACL. */
166# if defined __CYGWIN__ /* Cygwin */
167# define MODE_INSIDE_ACL 0
168# else /* Solaris */
169# define MODE_INSIDE_ACL 1
170# endif
171
172/* Return 1 if the given ACL is non-trivial.
173 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
174extern int acl_nontrivial (int count, aclent_t *entries);
175
176# ifdef ACE_GETACL /* Solaris 10 */
177
178/* Test an ACL retrieved with ACE_GETACL.
179 Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
180 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
181extern int acl_ace_nontrivial (int count, ace_t *entries);
182
183/* Definitions for when the built executable is executed on Solaris 10
184 (newer version) or Solaris 11. */
185/* For a_type. */
186# define OLD_ALLOW 0
187# define OLD_DENY 1
188# define NEW_ACE_ACCESS_ALLOWED_ACE_TYPE 0 /* replaces ALLOW */
189# define NEW_ACE_ACCESS_DENIED_ACE_TYPE 1 /* replaces DENY */
190/* For a_flags. */
191# define OLD_ACE_OWNER 0x0100
192# define OLD_ACE_GROUP 0x0200
193# define OLD_ACE_OTHER 0x0400
194# define NEW_ACE_OWNER 0x1000
195# define NEW_ACE_GROUP 0x2000
196# define NEW_ACE_IDENTIFIER_GROUP 0x0040
197# define NEW_ACE_EVERYONE 0x4000
198/* For a_access_mask. */
199# define NEW_ACE_READ_DATA 0x001 /* corresponds to 'r' */
200# define NEW_ACE_WRITE_DATA 0x002 /* corresponds to 'w' */
201# define NEW_ACE_APPEND_DATA 0x004
202# define NEW_ACE_READ_NAMED_ATTRS 0x008
203# define NEW_ACE_WRITE_NAMED_ATTRS 0x010
204# define NEW_ACE_EXECUTE 0x020
205# define NEW_ACE_DELETE_CHILD 0x040
206# define NEW_ACE_READ_ATTRIBUTES 0x080
207# define NEW_ACE_WRITE_ATTRIBUTES 0x100
208# define NEW_ACE_DELETE 0x10000
209# define NEW_ACE_READ_ACL 0x20000
210# define NEW_ACE_WRITE_ACL 0x40000
211# define NEW_ACE_WRITE_OWNER 0x80000
212# define NEW_ACE_SYNCHRONIZE 0x100000
213
214# endif
215
216# elif HAVE_GETACL /* HP-UX */
217
218/* Return 1 if the given ACL is non-trivial.
219 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
220extern int acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb);
221
222# if HAVE_ACLV_H /* HP-UX >= 11.11 */
223
224/* Return 1 if the given ACL is non-trivial.
225 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
226extern int aclv_nontrivial (int count, struct acl *entries);
227
228# endif
229
230# elif HAVE_ACLX_GET && 0 /* AIX */
231
232/* TODO */
233
234# elif HAVE_STATACL /* older AIX */
235
236/* Return 1 if the given ACL is non-trivial.
237 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
238extern int acl_nontrivial (struct acl *a);
239
240# elif HAVE_ACLSORT /* NonStop Kernel */
241
242/* Return 1 if the given ACL is non-trivial.
243 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
244extern int acl_nontrivial (int count, struct acl *entries);
245
246# endif
247
248#endif
249
250_GL_INLINE_HEADER_END
diff --git a/lib/acl.h b/lib/acl.h
new file mode 100644
index 00000000000..056bf7f30fb
--- /dev/null
+++ b/lib/acl.h
@@ -0,0 +1,30 @@
1/* acl.c - access control lists
2
3 Copyright (C) 2002, 2008-2013 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 Written by Paul Eggert. */
19
20#include <stdbool.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23
24bool acl_errno_valid (int) _GL_ATTRIBUTE_CONST;
25int file_has_acl (char const *, struct stat const *);
26int qset_acl (char const *, int, mode_t);
27int set_acl (char const *, int, mode_t);
28int qcopy_acl (char const *, int, char const *, int, mode_t);
29int copy_acl (char const *, int, char const *, int, mode_t);
30int chmod_or_fchmod (char const *, int, mode_t);
diff --git a/lib/acl_entries.c b/lib/acl_entries.c
new file mode 100644
index 00000000000..7ca7b9d5b40
--- /dev/null
+++ b/lib/acl_entries.c
@@ -0,0 +1,75 @@
1/* Return the number of entries in an ACL.
2
3 Copyright (C) 2002-2003, 2005-2013 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 Written by Paul Eggert and Andreas Gruenbacher. */
19
20#include <config.h>
21
22#include "acl-internal.h"
23
24/* This file assumes POSIX-draft like ACLs
25 (Linux, FreeBSD, Mac OS X, IRIX, Tru64). */
26
27/* Return the number of entries in ACL.
28 Return -1 and set errno upon failure to determine it. */
29
30int
31acl_entries (acl_t acl)
32{
33 int count = 0;
34
35 if (acl != NULL)
36 {
37#if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD, Mac OS X */
38# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
39 /* acl_get_entry returns 0 when it successfully fetches an entry,
40 and -1/EINVAL at the end. */
41 acl_entry_t ace;
42 int got_one;
43
44 for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
45 got_one >= 0;
46 got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
47 count++;
48# else /* Linux, FreeBSD */
49 /* acl_get_entry returns 1 when it successfully fetches an entry,
50 and 0 at the end. */
51 acl_entry_t ace;
52 int got_one;
53
54 for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
55 got_one > 0;
56 got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
57 count++;
58 if (got_one < 0)
59 return -1;
60# endif
61#else /* IRIX, Tru64 */
62# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */
63 /* Don't use acl_get_entry: it is undocumented. */
64 count = acl->acl_cnt;
65# endif
66# if HAVE_ACL_FREE_TEXT /* Tru64 */
67 /* Don't use acl_get_entry: it takes only one argument and does not
68 work. */
69 count = acl->acl_num;
70# endif
71#endif
72 }
73
74 return count;
75}
diff --git a/lib/errno.in.h b/lib/errno.in.h
new file mode 100644
index 00000000000..49b35464b91
--- /dev/null
+++ b/lib/errno.in.h
@@ -0,0 +1,279 @@
1/* A POSIX-like <errno.h>.
2
3 Copyright (C) 2008-2013 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>. */
17
18#ifndef _@GUARD_PREFIX@_ERRNO_H
19
20#if __GNUC__ >= 3
21@PRAGMA_SYSTEM_HEADER@
22#endif
23@PRAGMA_COLUMNS@
24
25/* The include_next requires a split double-inclusion guard. */
26#@INCLUDE_NEXT@ @NEXT_ERRNO_H@
27
28#ifndef _@GUARD_PREFIX@_ERRNO_H
29#define _@GUARD_PREFIX@_ERRNO_H
30
31
32/* On native Windows platforms, many macros are not defined. */
33# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
34
35/* These are the same values as defined by MSVC 10, for interoperability. */
36
37# ifndef ENOMSG
38# define ENOMSG 122
39# define GNULIB_defined_ENOMSG 1
40# endif
41
42# ifndef EIDRM
43# define EIDRM 111
44# define GNULIB_defined_EIDRM 1
45# endif
46
47# ifndef ENOLINK
48# define ENOLINK 121
49# define GNULIB_defined_ENOLINK 1
50# endif
51
52# ifndef EPROTO
53# define EPROTO 134
54# define GNULIB_defined_EPROTO 1
55# endif
56
57# ifndef EBADMSG
58# define EBADMSG 104
59# define GNULIB_defined_EBADMSG 1
60# endif
61
62# ifndef EOVERFLOW
63# define EOVERFLOW 132
64# define GNULIB_defined_EOVERFLOW 1
65# endif
66
67# ifndef ENOTSUP
68# define ENOTSUP 129
69# define GNULIB_defined_ENOTSUP 1
70# endif
71
72# ifndef ENETRESET
73# define ENETRESET 117
74# define GNULIB_defined_ENETRESET 1
75# endif
76
77# ifndef ECONNABORTED
78# define ECONNABORTED 106
79# define GNULIB_defined_ECONNABORTED 1
80# endif
81
82# ifndef ECANCELED
83# define ECANCELED 105
84# define GNULIB_defined_ECANCELED 1
85# endif
86
87# ifndef EOWNERDEAD
88# define EOWNERDEAD 133
89# define GNULIB_defined_EOWNERDEAD 1
90# endif
91
92# ifndef ENOTRECOVERABLE
93# define ENOTRECOVERABLE 127
94# define GNULIB_defined_ENOTRECOVERABLE 1
95# endif
96
97# ifndef EINPROGRESS
98# define EINPROGRESS 112
99# define EALREADY 103
100# define ENOTSOCK 128
101# define EDESTADDRREQ 109
102# define EMSGSIZE 115
103# define EPROTOTYPE 136
104# define ENOPROTOOPT 123
105# define EPROTONOSUPPORT 135
106# define EOPNOTSUPP 130
107# define EAFNOSUPPORT 102
108# define EADDRINUSE 100
109# define EADDRNOTAVAIL 101
110# define ENETDOWN 116
111# define ENETUNREACH 118
112# define ECONNRESET 108
113# define ENOBUFS 119
114# define EISCONN 113
115# define ENOTCONN 126
116# define ETIMEDOUT 138
117# define ECONNREFUSED 107
118# define ELOOP 114
119# define EHOSTUNREACH 110
120# define EWOULDBLOCK 140
121# define GNULIB_defined_ESOCK 1
122# endif
123
124# ifndef ETXTBSY
125# define ETXTBSY 139
126# define ENODATA 120 /* not required by POSIX */
127# define ENOSR 124 /* not required by POSIX */
128# define ENOSTR 125 /* not required by POSIX */
129# define ETIME 137 /* not required by POSIX */
130# define EOTHER 131 /* not required by POSIX */
131# define GNULIB_defined_ESTREAMS 1
132# endif
133
134/* These are intentionally the same values as the WSA* error numbers, defined
135 in <winsock2.h>. */
136# define ESOCKTNOSUPPORT 10044 /* not required by POSIX */
137# define EPFNOSUPPORT 10046 /* not required by POSIX */
138# define ESHUTDOWN 10058 /* not required by POSIX */
139# define ETOOMANYREFS 10059 /* not required by POSIX */
140# define EHOSTDOWN 10064 /* not required by POSIX */
141# define EPROCLIM 10067 /* not required by POSIX */
142# define EUSERS 10068 /* not required by POSIX */
143# define EDQUOT 10069
144# define ESTALE 10070
145# define EREMOTE 10071 /* not required by POSIX */
146# define GNULIB_defined_EWINSOCK 1
147
148# endif
149
150
151/* On OSF/1 5.1, when _XOPEN_SOURCE_EXTENDED is not defined, the macros
152 EMULTIHOP, ENOLINK, EOVERFLOW are not defined. */
153# if @EMULTIHOP_HIDDEN@
154# define EMULTIHOP @EMULTIHOP_VALUE@
155# define GNULIB_defined_EMULTIHOP 1
156# endif
157# if @ENOLINK_HIDDEN@
158# define ENOLINK @ENOLINK_VALUE@
159# define GNULIB_defined_ENOLINK 1
160# endif
161# if @EOVERFLOW_HIDDEN@
162# define EOVERFLOW @EOVERFLOW_VALUE@
163# define GNULIB_defined_EOVERFLOW 1
164# endif
165
166
167/* On OpenBSD 4.0 and on native Windows, the macros ENOMSG, EIDRM, ENOLINK,
168 EPROTO, EMULTIHOP, EBADMSG, EOVERFLOW, ENOTSUP, ECANCELED are not defined.
169 Likewise, on NonStop Kernel, EDQUOT is not defined.
170 Define them here. Values >= 2000 seem safe to use: Solaris ESTALE = 151,
171 HP-UX EWOULDBLOCK = 246, IRIX EDQUOT = 1133.
172
173 Note: When one of these systems defines some of these macros some day,
174 binaries will have to be recompiled so that they recognizes the new
175 errno values from the system. */
176
177# ifndef ENOMSG
178# define ENOMSG 2000
179# define GNULIB_defined_ENOMSG 1
180# endif
181
182# ifndef EIDRM
183# define EIDRM 2001
184# define GNULIB_defined_EIDRM 1
185# endif
186
187# ifndef ENOLINK
188# define ENOLINK 2002
189# define GNULIB_defined_ENOLINK 1
190# endif
191
192# ifndef EPROTO
193# define EPROTO 2003
194# define GNULIB_defined_EPROTO 1
195# endif
196
197# ifndef EMULTIHOP
198# define EMULTIHOP 2004
199# define GNULIB_defined_EMULTIHOP 1
200# endif
201
202# ifndef EBADMSG
203# define EBADMSG 2005
204# define GNULIB_defined_EBADMSG 1
205# endif
206
207# ifndef EOVERFLOW
208# define EOVERFLOW 2006
209# define GNULIB_defined_EOVERFLOW 1
210# endif
211
212# ifndef ENOTSUP
213# define ENOTSUP 2007
214# define GNULIB_defined_ENOTSUP 1
215# endif
216
217# ifndef ENETRESET
218# define ENETRESET 2011
219# define GNULIB_defined_ENETRESET 1
220# endif
221
222# ifndef ECONNABORTED
223# define ECONNABORTED 2012
224# define GNULIB_defined_ECONNABORTED 1
225# endif
226
227# ifndef ESTALE
228# define ESTALE 2009
229# define GNULIB_defined_ESTALE 1
230# endif
231
232# ifndef EDQUOT
233# define EDQUOT 2010
234# define GNULIB_defined_EDQUOT 1
235# endif
236
237# ifndef ECANCELED
238# define ECANCELED 2008
239# define GNULIB_defined_ECANCELED 1
240# endif
241
242/* On many platforms, the macros EOWNERDEAD and ENOTRECOVERABLE are not
243 defined. */
244
245# ifndef EOWNERDEAD
246# if defined __sun
247 /* Use the same values as defined for Solaris >= 8, for
248 interoperability. */
249# define EOWNERDEAD 58
250# define ENOTRECOVERABLE 59
251# elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
252 /* We have a conflict here: pthreads-win32 defines these values
253 differently than MSVC 10. It's hairy to decide which one to use. */
254# if defined __MINGW32__ && !defined USE_WINDOWS_THREADS
255 /* Use the same values as defined by pthreads-win32, for
256 interoperability. */
257# define EOWNERDEAD 43
258# define ENOTRECOVERABLE 44
259# else
260 /* Use the same values as defined by MSVC 10, for
261 interoperability. */
262# define EOWNERDEAD 133
263# define ENOTRECOVERABLE 127
264# endif
265# else
266# define EOWNERDEAD 2013
267# define ENOTRECOVERABLE 2014
268# endif
269# define GNULIB_defined_EOWNERDEAD 1
270# define GNULIB_defined_ENOTRECOVERABLE 1
271# endif
272
273# ifndef EILSEQ
274# define EILSEQ 2015
275# define GNULIB_defined_EILSEQ 1
276# endif
277
278#endif /* _@GUARD_PREFIX@_ERRNO_H */
279#endif /* _@GUARD_PREFIX@_ERRNO_H */
diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c
new file mode 100644
index 00000000000..bb8bae12861
--- /dev/null
+++ b/lib/file-has-acl.c
@@ -0,0 +1,918 @@
1/* Test whether a file has a nontrivial access control list.
2
3 Copyright (C) 2002-2003, 2005-2013 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
19
20/* Without this pragma, gcc 4.7.0 20120126 may suggest that the
21 file_has_acl function might be candidate for attribute 'const' */
22#if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
23# pragma GCC diagnostic ignored "-Wsuggest-attribute=const"
24#endif
25
26#include <config.h>
27
28#include "acl.h"
29
30#include "acl-internal.h"
31
32
33#if USE_ACL && HAVE_ACL_GET_FILE
34
35# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
36
37/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
38 Return 1 if the given ACL is non-trivial.
39 Return 0 if it is trivial. */
40int
41acl_extended_nontrivial (acl_t acl)
42{
43 /* acl is non-trivial if it is non-empty. */
44 return (acl_entries (acl) > 0);
45}
46
47# else /* Linux, FreeBSD, IRIX, Tru64 */
48
49/* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS.
50 Return 1 if the given ACL is non-trivial.
51 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
52 Return -1 and set errno upon failure to determine it. */
53int
54acl_access_nontrivial (acl_t acl)
55{
56 /* acl is non-trivial if it has some entries other than for "user::",
57 "group::", and "other::". Normally these three should be present
58 at least, allowing us to write
59 return (3 < acl_entries (acl));
60 but the following code is more robust. */
61# if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD */
62
63 acl_entry_t ace;
64 int got_one;
65
66 for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
67 got_one > 0;
68 got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
69 {
70 acl_tag_t tag;
71 if (acl_get_tag_type (ace, &tag) < 0)
72 return -1;
73 if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
74 return 1;
75 }
76 return got_one;
77
78# else /* IRIX, Tru64 */
79# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */
80 /* Don't use acl_get_entry: it is undocumented. */
81
82 int count = acl->acl_cnt;
83 int i;
84
85 for (i = 0; i < count; i++)
86 {
87 acl_entry_t ace = &acl->acl_entry[i];
88 acl_tag_t tag = ace->ae_tag;
89
90 if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ
91 || tag == ACL_OTHER_OBJ))
92 return 1;
93 }
94 return 0;
95
96# endif
97# if HAVE_ACL_FREE_TEXT /* Tru64 */
98 /* Don't use acl_get_entry: it takes only one argument and does not work. */
99
100 int count = acl->acl_num;
101 acl_entry_t ace;
102
103 for (ace = acl->acl_first; count > 0; ace = ace->next, count--)
104 {
105 acl_tag_t tag;
106 acl_perm_t perm;
107
108 tag = ace->entry->acl_type;
109 if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
110 return 1;
111
112 perm = ace->entry->acl_perm;
113 /* On Tru64, perm can also contain non-standard bits such as
114 PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ... */
115 if ((perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)) != 0)
116 return 1;
117 }
118 return 0;
119
120# endif
121# endif
122}
123
124# endif
125
126
127#elif USE_ACL && HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
128
129/* Test an ACL retrieved with GETACL.
130 Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
131 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
132int
133acl_nontrivial (int count, aclent_t *entries)
134{
135 int i;
136
137 for (i = 0; i < count; i++)
138 {
139 aclent_t *ace = &entries[i];
140
141 /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
142 If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
143 We don't need to check ace->a_id in these cases. */
144 if (!(ace->a_type == USER_OBJ
145 || ace->a_type == GROUP_OBJ
146 || ace->a_type == OTHER_OBJ
147 /* Note: Cygwin does not return a CLASS_OBJ ("mask:") entry
148 sometimes. */
149 || ace->a_type == CLASS_OBJ))
150 return 1;
151 }
152 return 0;
153}
154
155# ifdef ACE_GETACL
156
157/* A shortcut for a bitmask. */
158# define NEW_ACE_WRITEA_DATA (NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA)
159
160/* Test an ACL retrieved with ACE_GETACL.
161 Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
162 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
163int
164acl_ace_nontrivial (int count, ace_t *entries)
165{
166 int i;
167
168 /* The flags in the ace_t structure changed in a binary incompatible way
169 when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
170 How to distinguish the two conventions at runtime?
171 In the old convention, usually three ACEs have a_flags = ACE_OWNER /
172 ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400. In the new
173 convention, these values are not used. */
174 int old_convention = 0;
175
176 for (i = 0; i < count; i++)
177 if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER))
178 {
179 old_convention = 1;
180 break;
181 }
182
183 if (old_convention)
184 /* Running on Solaris 10. */
185 for (i = 0; i < count; i++)
186 {
187 ace_t *ace = &entries[i];
188
189 /* Note:
190 If ace->a_flags = ACE_OWNER, ace->a_who is the st_uid from stat().
191 If ace->a_flags = ACE_GROUP, ace->a_who is the st_gid from stat().
192 We don't need to check ace->a_who in these cases. */
193 if (!(ace->a_type == OLD_ALLOW
194 && (ace->a_flags == OLD_ACE_OWNER
195 || ace->a_flags == OLD_ACE_GROUP
196 || ace->a_flags == OLD_ACE_OTHER)))
197 return 1;
198 }
199 else
200 {
201 /* Running on Solaris 10 (newer version) or Solaris 11. */
202 unsigned int access_masks[6] =
203 {
204 0, /* owner@ deny */
205 0, /* owner@ allow */
206 0, /* group@ deny */
207 0, /* group@ allow */
208 0, /* everyone@ deny */
209 0 /* everyone@ allow */
210 };
211
212 for (i = 0; i < count; i++)
213 {
214 ace_t *ace = &entries[i];
215 unsigned int index1;
216 unsigned int index2;
217
218 if (ace->a_type == NEW_ACE_ACCESS_ALLOWED_ACE_TYPE)
219 index1 = 1;
220 else if (ace->a_type == NEW_ACE_ACCESS_DENIED_ACE_TYPE)
221 index1 = 0;
222 else
223 return 1;
224
225 if (ace->a_flags == NEW_ACE_OWNER)
226 index2 = 0;
227 else if (ace->a_flags == (NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP))
228 index2 = 2;
229 else if (ace->a_flags == NEW_ACE_EVERYONE)
230 index2 = 4;
231 else
232 return 1;
233
234 access_masks[index1 + index2] |= ace->a_access_mask;
235 }
236
237 /* The same bit shouldn't be both allowed and denied. */
238 if (access_masks[0] & access_masks[1])
239 return 1;
240 if (access_masks[2] & access_masks[3])
241 return 1;
242 if (access_masks[4] & access_masks[5])
243 return 1;
244
245 /* Check minimum masks. */
246 if ((NEW_ACE_WRITE_NAMED_ATTRS
247 | NEW_ACE_WRITE_ATTRIBUTES
248 | NEW_ACE_WRITE_ACL
249 | NEW_ACE_WRITE_OWNER)
250 & ~ access_masks[1])
251 return 1;
252 access_masks[1] &= ~(NEW_ACE_WRITE_NAMED_ATTRS
253 | NEW_ACE_WRITE_ATTRIBUTES
254 | NEW_ACE_WRITE_ACL
255 | NEW_ACE_WRITE_OWNER);
256 if ((NEW_ACE_READ_NAMED_ATTRS
257 | NEW_ACE_READ_ATTRIBUTES
258 | NEW_ACE_READ_ACL
259 | NEW_ACE_SYNCHRONIZE)
260 & ~ access_masks[5])
261 return 1;
262 access_masks[5] &= ~(NEW_ACE_READ_NAMED_ATTRS
263 | NEW_ACE_READ_ATTRIBUTES
264 | NEW_ACE_READ_ACL
265 | NEW_ACE_SYNCHRONIZE);
266
267 /* Check the allowed or denied bits. */
268 switch ((access_masks[0] | access_masks[1])
269 & ~(NEW_ACE_READ_NAMED_ATTRS
270 | NEW_ACE_READ_ATTRIBUTES
271 | NEW_ACE_READ_ACL
272 | NEW_ACE_SYNCHRONIZE))
273 {
274 case 0:
275 case NEW_ACE_READ_DATA:
276 case NEW_ACE_WRITEA_DATA:
277 case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
278 case NEW_ACE_EXECUTE:
279 case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE:
280 case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
281 case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
282 break;
283 default:
284 return 1;
285 }
286 switch ((access_masks[2] | access_masks[3])
287 & ~(NEW_ACE_READ_NAMED_ATTRS
288 | NEW_ACE_READ_ATTRIBUTES
289 | NEW_ACE_READ_ACL
290 | NEW_ACE_SYNCHRONIZE))
291 {
292 case 0:
293 case NEW_ACE_READ_DATA:
294 case NEW_ACE_WRITEA_DATA:
295 case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
296 case NEW_ACE_EXECUTE:
297 case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE:
298 case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
299 case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
300 break;
301 default:
302 return 1;
303 }
304 switch ((access_masks[4] | access_masks[5])
305 & ~(NEW_ACE_WRITE_NAMED_ATTRS
306 | NEW_ACE_WRITE_ATTRIBUTES
307 | NEW_ACE_WRITE_ACL
308 | NEW_ACE_WRITE_OWNER))
309 {
310 case 0:
311 case NEW_ACE_READ_DATA:
312 case NEW_ACE_WRITEA_DATA:
313 case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
314 case NEW_ACE_EXECUTE:
315 case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE:
316 case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
317 case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
318 break;
319 default:
320 return 1;
321 }
322
323 /* Check that the NEW_ACE_WRITE_DATA and NEW_ACE_APPEND_DATA bits are
324 either both allowed or both denied. */
325 if (((access_masks[0] & NEW_ACE_WRITE_DATA) != 0)
326 != ((access_masks[0] & NEW_ACE_APPEND_DATA) != 0))
327 return 1;
328 if (((access_masks[2] & NEW_ACE_WRITE_DATA) != 0)
329 != ((access_masks[2] & NEW_ACE_APPEND_DATA) != 0))
330 return 1;
331 if (((access_masks[4] & NEW_ACE_WRITE_DATA) != 0)
332 != ((access_masks[4] & NEW_ACE_APPEND_DATA) != 0))
333 return 1;
334 }
335
336 return 0;
337}
338
339# endif
340
341#elif USE_ACL && HAVE_GETACL /* HP-UX */
342
343/* Return 1 if the given ACL is non-trivial.
344 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
345int
346acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb)
347{
348 int i;
349
350 for (i = 0; i < count; i++)
351 {
352 struct acl_entry *ace = &entries[i];
353
354 if (!((ace->uid == sb->st_uid && ace->gid == ACL_NSGROUP)
355 || (ace->uid == ACL_NSUSER && ace->gid == sb->st_gid)
356 || (ace->uid == ACL_NSUSER && ace->gid == ACL_NSGROUP)))
357 return 1;
358 }
359 return 0;
360}
361
362# if HAVE_ACLV_H /* HP-UX >= 11.11 */
363
364/* Return 1 if the given ACL is non-trivial.
365 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
366int
367aclv_nontrivial (int count, struct acl *entries)
368{
369 int i;
370
371 for (i = 0; i < count; i++)
372 {
373 struct acl *ace = &entries[i];
374
375 /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
376 If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
377 We don't need to check ace->a_id in these cases. */
378 if (!(ace->a_type == USER_OBJ /* no need to check ace->a_id here */
379 || ace->a_type == GROUP_OBJ /* no need to check ace->a_id here */
380 || ace->a_type == CLASS_OBJ
381 || ace->a_type == OTHER_OBJ))
382 return 1;
383 }
384 return 0;
385}
386
387# endif
388
389#elif USE_ACL && (HAVE_ACLX_GET || HAVE_STATACL) /* AIX */
390
391/* Return 1 if the given ACL is non-trivial.
392 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
393int
394acl_nontrivial (struct acl *a)
395{
396 /* The normal way to iterate through an ACL is like this:
397 struct acl_entry *ace;
398 for (ace = a->acl_ext; ace != acl_last (a); ace = acl_nxt (ace))
399 {
400 struct ace_id *aei;
401 switch (ace->ace_type)
402 {
403 case ACC_PERMIT:
404 case ACC_DENY:
405 case ACC_SPECIFY:
406 ...;
407 }
408 for (aei = ace->ace_id; aei != id_last (ace); aei = id_nxt (aei))
409 ...
410 }
411 */
412 return (acl_last (a) != a->acl_ext ? 1 : 0);
413}
414
415# if HAVE_ACLX_GET && defined ACL_AIX_WIP /* newer AIX */
416
417/* Return 1 if the given ACL is non-trivial.
418 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
419int
420acl_nfs4_nontrivial (nfs4_acl_int_t *a)
421{
422# if 1 /* let's try this first */
423 return (a->aclEntryN > 0 ? 1 : 0);
424# else
425 int count = a->aclEntryN;
426 int i;
427
428 for (i = 0; i < count; i++)
429 {
430 nfs4_ace_int_t *ace = &a->aclEntry[i];
431
432 if (!((ace->flags & ACE4_ID_SPECIAL) != 0
433 && (ace->aceWho.special_whoid == ACE4_WHO_OWNER
434 || ace->aceWho.special_whoid == ACE4_WHO_GROUP
435 || ace->aceWho.special_whoid == ACE4_WHO_EVERYONE)
436 && ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE
437 && ace->aceFlags == 0
438 && (ace->aceMask & ~(ACE4_READ_DATA | ACE4_LIST_DIRECTORY
439 | ACE4_WRITE_DATA | ACE4_ADD_FILE
440 | ACE4_EXECUTE)) == 0))
441 return 1;
442 }
443 return 0;
444# endif
445}
446
447# endif
448
449#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
450
451/* Test an ACL retrieved with ACL_GET.
452 Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
453 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
454int
455acl_nontrivial (int count, struct acl *entries)
456{
457 int i;
458
459 for (i = 0; i < count; i++)
460 {
461 struct acl *ace = &entries[i];
462
463 /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
464 If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
465 We don't need to check ace->a_id in these cases. */
466 if (!(ace->a_type == USER_OBJ /* no need to check ace->a_id here */
467 || ace->a_type == GROUP_OBJ /* no need to check ace->a_id here */
468 || ace->a_type == CLASS_OBJ
469 || ace->a_type == OTHER_OBJ))
470 return 1;
471 }
472 return 0;
473}
474
475#endif
476
477
478/* Return 1 if NAME has a nontrivial access control list, 0 if NAME
479 only has no or a base access control list, and -1 (setting errno)
480 on error. SB must be set to the stat buffer of NAME, obtained
481 through stat() or lstat(). */
482
483int
484file_has_acl (char const *name, struct stat const *sb)
485{
486#if USE_ACL
487 if (! S_ISLNK (sb->st_mode))
488 {
489# if HAVE_ACL_GET_FILE
490
491 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
492 /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
493 int ret;
494
495 if (HAVE_ACL_EXTENDED_FILE) /* Linux */
496 {
497 /* On Linux, acl_extended_file is an optimized function: It only
498 makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
499 ACL_TYPE_DEFAULT. */
500 ret = acl_extended_file (name);
501 }
502 else /* FreeBSD, Mac OS X, IRIX, Tru64 */
503 {
504# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
505 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
506 and acl_get_file (name, ACL_TYPE_DEFAULT)
507 always return NULL / EINVAL. There is no point in making
508 these two useless calls. The real ACL is retrieved through
509 acl_get_file (name, ACL_TYPE_EXTENDED). */
510 acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED);
511 if (acl)
512 {
513 ret = acl_extended_nontrivial (acl);
514 acl_free (acl);
515 }
516 else
517 ret = -1;
518# else /* FreeBSD, IRIX, Tru64 */
519 acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
520 if (acl)
521 {
522 int saved_errno;
523
524 ret = acl_access_nontrivial (acl);
525 saved_errno = errno;
526 acl_free (acl);
527 errno = saved_errno;
528# if HAVE_ACL_FREE_TEXT /* Tru64 */
529 /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
530 returns NULL with errno not set. There is no point in
531 making this call. */
532# else /* FreeBSD, IRIX */
533 /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS)
534 and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
535 either both succeed or both fail; it depends on the
536 file system. Therefore there is no point in making the second
537 call if the first one already failed. */
538 if (ret == 0 && S_ISDIR (sb->st_mode))
539 {
540 acl = acl_get_file (name, ACL_TYPE_DEFAULT);
541 if (acl)
542 {
543 ret = (0 < acl_entries (acl));
544 acl_free (acl);
545 }
546 else
547 ret = -1;
548 }
549# endif
550 }
551 else
552 ret = -1;
553# endif
554 }
555 if (ret < 0)
556 return - acl_errno_valid (errno);
557 return ret;
558
559# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
560
561# if defined ACL_NO_TRIVIAL
562
563 /* Solaris 10 (newer version), which has additional API declared in
564 <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
565 acl_fromtext, ...). */
566 return acl_trivial (name);
567
568# else /* Solaris, Cygwin, general case */
569
570 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
571 of Unixware. The acl() call returns the access and default ACL both
572 at once. */
573 {
574 /* Initially, try to read the entries into a stack-allocated buffer.
575 Use malloc if it does not fit. */
576 enum
577 {
578 alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */
579 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t))
580 };
581 aclent_t buf[alloc_init];
582 size_t alloc = alloc_init;
583 aclent_t *entries = buf;
584 aclent_t *malloced = NULL;
585 int count;
586
587 for (;;)
588 {
589 count = acl (name, GETACL, alloc, entries);
590 if (count < 0 && errno == ENOSPC)
591 {
592 /* Increase the size of the buffer. */
593 free (malloced);
594 if (alloc > alloc_max / 2)
595 {
596 errno = ENOMEM;
597 return -1;
598 }
599 alloc = 2 * alloc; /* <= alloc_max */
600 entries = malloced =
601 (aclent_t *) malloc (alloc * sizeof (aclent_t));
602 if (entries == NULL)
603 {
604 errno = ENOMEM;
605 return -1;
606 }
607 continue;
608 }
609 break;
610 }
611 if (count < 0)
612 {
613 if (errno == ENOSYS || errno == ENOTSUP)
614 ;
615 else
616 {
617 int saved_errno = errno;
618 free (malloced);
619 errno = saved_errno;
620 return -1;
621 }
622 }
623 else if (count == 0)
624 ;
625 else
626 {
627 /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin
628 returns only 3 entries for files with no ACL. But this is safe:
629 If there are more than 4 entries, there cannot be only the
630 "user::", "group::", "other:", and "mask:" entries. */
631 if (count > 4)
632 {
633 free (malloced);
634 return 1;
635 }
636
637 if (acl_nontrivial (count, entries))
638 {
639 free (malloced);
640 return 1;
641 }
642 }
643 free (malloced);
644 }
645
646# ifdef ACE_GETACL
647 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
648 file systems (whereas the other ones are used in UFS file systems). */
649 {
650 /* Initially, try to read the entries into a stack-allocated buffer.
651 Use malloc if it does not fit. */
652 enum
653 {
654 alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
655 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
656 };
657 ace_t buf[alloc_init];
658 size_t alloc = alloc_init;
659 ace_t *entries = buf;
660 ace_t *malloced = NULL;
661 int count;
662
663 for (;;)
664 {
665 count = acl (name, ACE_GETACL, alloc, entries);
666 if (count < 0 && errno == ENOSPC)
667 {
668 /* Increase the size of the buffer. */
669 free (malloced);
670 if (alloc > alloc_max / 2)
671 {
672 errno = ENOMEM;
673 return -1;
674 }
675 alloc = 2 * alloc; /* <= alloc_max */
676 entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
677 if (entries == NULL)
678 {
679 errno = ENOMEM;
680 return -1;
681 }
682 continue;
683 }
684 break;
685 }
686 if (count < 0)
687 {
688 if (errno == ENOSYS || errno == EINVAL)
689 ;
690 else
691 {
692 int saved_errno = errno;
693 free (malloced);
694 errno = saved_errno;
695 return -1;
696 }
697 }
698 else if (count == 0)
699 ;
700 else
701 {
702 /* In the old (original Solaris 10) convention:
703 If there are more than 3 entries, there cannot be only the
704 ACE_OWNER, ACE_GROUP, ACE_OTHER entries.
705 In the newer Solaris 10 and Solaris 11 convention:
706 If there are more than 6 entries, there cannot be only the
707 ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
708 NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
709 NEW_ACE_ACCESS_DENIED_ACE_TYPE. */
710 if (count > 6)
711 {
712 free (malloced);
713 return 1;
714 }
715
716 if (acl_ace_nontrivial (count, entries))
717 {
718 free (malloced);
719 return 1;
720 }
721 }
722 free (malloced);
723 }
724# endif
725
726 return 0;
727# endif
728
729# elif HAVE_GETACL /* HP-UX */
730
731 {
732 struct acl_entry entries[NACLENTRIES];
733 int count;
734
735 count = getacl (name, NACLENTRIES, entries);
736
737 if (count < 0)
738 {
739 /* ENOSYS is seen on newer HP-UX versions.
740 EOPNOTSUPP is typically seen on NFS mounts.
741 ENOTSUP was seen on Quantum StorNext file systems (cvfs). */
742 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
743 ;
744 else
745 return -1;
746 }
747 else if (count == 0)
748 return 0;
749 else /* count > 0 */
750 {
751 if (count > NACLENTRIES)
752 /* If NACLENTRIES cannot be trusted, use dynamic memory
753 allocation. */
754 abort ();
755
756 /* If there are more than 3 entries, there cannot be only the
757 (uid,%), (%,gid), (%,%) entries. */
758 if (count > 3)
759 return 1;
760
761 {
762 struct stat statbuf;
763
764 if (stat (name, &statbuf) < 0)
765 return -1;
766
767 return acl_nontrivial (count, entries, &statbuf);
768 }
769 }
770 }
771
772# if HAVE_ACLV_H /* HP-UX >= 11.11 */
773
774 {
775 struct acl entries[NACLVENTRIES];
776 int count;
777
778 count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries);
779
780 if (count < 0)
781 {
782 /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
783 EINVAL is seen on NFS in HP-UX 11.31. */
784 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
785 ;
786 else
787 return -1;
788 }
789 else if (count == 0)
790 return 0;
791 else /* count > 0 */
792 {
793 if (count > NACLVENTRIES)
794 /* If NACLVENTRIES cannot be trusted, use dynamic memory
795 allocation. */
796 abort ();
797
798 /* If there are more than 4 entries, there cannot be only the
799 four base ACL entries. */
800 if (count > 4)
801 return 1;
802
803 return aclv_nontrivial (count, entries);
804 }
805 }
806
807# endif
808
809# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
810
811 acl_type_t type;
812 char aclbuf[1024];
813 void *acl = aclbuf;
814 size_t aclsize = sizeof (aclbuf);
815 mode_t mode;
816
817 for (;;)
818 {
819 /* The docs say that type being 0 is equivalent to ACL_ANY, but it
820 is not true, in AIX 5.3. */
821 type.u64 = ACL_ANY;
822 if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)
823 break;
824 if (errno == ENOSYS)
825 return 0;
826 if (errno != ENOSPC)
827 {
828 if (acl != aclbuf)
829 {
830 int saved_errno = errno;
831 free (acl);
832 errno = saved_errno;
833 }
834 return -1;
835 }
836 aclsize = 2 * aclsize;
837 if (acl != aclbuf)
838 free (acl);
839 acl = malloc (aclsize);
840 if (acl == NULL)
841 {
842 errno = ENOMEM;
843 return -1;
844 }
845 }
846
847 if (type.u64 == ACL_AIXC)
848 {
849 int result = acl_nontrivial ((struct acl *) acl);
850 if (acl != aclbuf)
851 free (acl);
852 return result;
853 }
854 else if (type.u64 == ACL_NFS4)
855 {
856 int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl);
857 if (acl != aclbuf)
858 free (acl);
859 return result;
860 }
861 else
862 {
863 /* A newer type of ACL has been introduced in the system.
864 We should better support it. */
865 if (acl != aclbuf)
866 free (acl);
867 errno = EINVAL;
868 return -1;
869 }
870
871# elif HAVE_STATACL /* older AIX */
872
873 union { struct acl a; char room[4096]; } u;
874
875 if (statacl (name, STX_NORMAL, &u.a, sizeof (u)) < 0)
876 return -1;
877
878 return acl_nontrivial (&u.a);
879
880# elif HAVE_ACLSORT /* NonStop Kernel */
881
882 {
883 struct acl entries[NACLENTRIES];
884 int count;
885
886 count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);
887
888 if (count < 0)
889 {
890 if (errno == ENOSYS || errno == ENOTSUP)
891 ;
892 else
893 return -1;
894 }
895 else if (count == 0)
896 return 0;
897 else /* count > 0 */
898 {
899 if (count > NACLENTRIES)
900 /* If NACLENTRIES cannot be trusted, use dynamic memory
901 allocation. */
902 abort ();
903
904 /* If there are more than 4 entries, there cannot be only the
905 four base ACL entries. */
906 if (count > 4)
907 return 1;
908
909 return acl_nontrivial (count, entries);
910 }
911 }
912
913# endif
914 }
915#endif
916
917 return 0;
918}
diff --git a/lib/gnulib.mk b/lib/gnulib.mk
index 4b754ec21dd..4a84b1db261 100644
--- a/lib/gnulib.mk
+++ b/lib/gnulib.mk
@@ -21,7 +21,7 @@
21# the same distribution terms as the rest of that program. 21# the same distribution terms as the rest of that program.
22# 22#
23# Generated by gnulib-tool. 23# Generated by gnulib-tool.
24# 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 24# 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
25 25
26 26
27MOSTLYCLEANFILES += core *.stackdump 27MOSTLYCLEANFILES += core *.stackdump
@@ -217,6 +217,40 @@ EXTRA_libgnu_a_SOURCES += dup2.c
217 217
218## end gnulib module dup2 218## end gnulib module dup2
219 219
220## begin gnulib module errno
221
222BUILT_SOURCES += $(ERRNO_H)
223
224# We need the following in order to create <errno.h> when the system
225# doesn't have one that is POSIX compliant.
226if GL_GENERATE_ERRNO_H
227errno.h: errno.in.h $(top_builddir)/config.status
228 $(AM_V_GEN)rm -f $@-t $@ && \
229 { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \
230 sed -e 's|@''GUARD_PREFIX''@|GL|g' \
231 -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
232 -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
233 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
234 -e 's|@''NEXT_ERRNO_H''@|$(NEXT_ERRNO_H)|g' \
235 -e 's|@''EMULTIHOP_HIDDEN''@|$(EMULTIHOP_HIDDEN)|g' \
236 -e 's|@''EMULTIHOP_VALUE''@|$(EMULTIHOP_VALUE)|g' \
237 -e 's|@''ENOLINK_HIDDEN''@|$(ENOLINK_HIDDEN)|g' \
238 -e 's|@''ENOLINK_VALUE''@|$(ENOLINK_VALUE)|g' \
239 -e 's|@''EOVERFLOW_HIDDEN''@|$(EOVERFLOW_HIDDEN)|g' \
240 -e 's|@''EOVERFLOW_VALUE''@|$(EOVERFLOW_VALUE)|g' \
241 < $(srcdir)/errno.in.h; \
242 } > $@-t && \
243 mv $@-t $@
244else
245errno.h: $(top_builddir)/config.status
246 rm -f $@
247endif
248MOSTLYCLEANFILES += errno.h errno.h-t
249
250EXTRA_DIST += errno.in.h
251
252## end gnulib module errno
253
220## begin gnulib module euidaccess 254## begin gnulib module euidaccess
221 255
222if gl_GNULIB_ENABLED_euidaccess 256if gl_GNULIB_ENABLED_euidaccess
@@ -561,6 +595,16 @@ EXTRA_libgnu_a_SOURCES += putenv.c
561 595
562## end gnulib module putenv 596## end gnulib module putenv
563 597
598## begin gnulib module qacl
599
600libgnu_a_SOURCES += acl-errno-valid.c file-has-acl.c qcopy-acl.c qset-acl.c
601
602EXTRA_DIST += acl-internal.h acl.h acl_entries.c
603
604EXTRA_libgnu_a_SOURCES += acl_entries.c
605
606## end gnulib module qacl
607
564## begin gnulib module readlink 608## begin gnulib module readlink
565 609
566 610
diff --git a/lib/makefile.w32-in b/lib/makefile.w32-in
index cd62fbcd13d..5e2083aed1e 100644
--- a/lib/makefile.w32-in
+++ b/lib/makefile.w32-in
@@ -23,7 +23,8 @@ ALL = gnulib
23LOCAL_FLAGS = -I. -I../nt/inc -I../src 23LOCAL_FLAGS = -I. -I../nt/inc -I../src
24LIBS = 24LIBS =
25 25
26GNULIBOBJS = $(BLD)/c-ctype.$(O) \ 26GNULIBOBJS = $(BLD)/acl-errno-valid.$(O) \
27 $(BLD)/c-ctype.$(O) \
27 $(BLD)/c-strcasecmp.$(O) \ 28 $(BLD)/c-strcasecmp.$(O) \
28 $(BLD)/c-strncasecmp.$(O) \ 29 $(BLD)/c-strncasecmp.$(O) \
29 $(BLD)/close-stream.$(O) \ 30 $(BLD)/close-stream.$(O) \
@@ -109,6 +110,12 @@ SIG2STR_H = $(GNU_LIB)/sig2str.h \
109STAT_TIME_H = $(GNU_LIB)/stat-time.h \ 110STAT_TIME_H = $(GNU_LIB)/stat-time.h \
110 $(NT_INC)/sys/stat.h 111 $(NT_INC)/sys/stat.h
111 112
113$(BLD)/acl-errno-valid.$(O) : \
114 $(GNU_LIB)/acl-errno-valid.c \
115 $(CONFIG_H) \
116 $(GNU_LIB)/acl.h \
117 $(NT_INC)/stdbool.h
118
112$(BLD)/c-ctype.$(O) : \ 119$(BLD)/c-ctype.$(O) : \
113 $(GNU_LIB)/c-ctype.c \ 120 $(GNU_LIB)/c-ctype.c \
114 $(CONFIG_H) \ 121 $(CONFIG_H) \
diff --git a/lib/qcopy-acl.c b/lib/qcopy-acl.c
new file mode 100644
index 00000000000..25a2ff154d2
--- /dev/null
+++ b/lib/qcopy-acl.c
@@ -0,0 +1,583 @@
1/* copy-acl.c - copy access control list from one file to another file
2
3 Copyright (C) 2002-2003, 2005-2013 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
19
20#include <config.h>
21
22#include "acl.h"
23
24#include "acl-internal.h"
25
26
27/* Copy access control lists from one file to another. If SOURCE_DESC is
28 a valid file descriptor, use file descriptor operations, else use
29 filename based operations on SRC_NAME. Likewise for DEST_DESC and
30 DST_NAME.
31 If access control lists are not available, fchmod the target file to
32 MODE. Also sets the non-permission bits of the destination file
33 (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
34 Return 0 if successful.
35 Return -2 and set errno for an error relating to the source file.
36 Return -1 and set errno for an error relating to the destination file. */
37
38int
39qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
40 int dest_desc, mode_t mode)
41{
42#if USE_ACL && HAVE_ACL_GET_FILE
43 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
44 /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
45# if !HAVE_ACL_TYPE_EXTENDED
46 /* Linux, FreeBSD, IRIX, Tru64 */
47
48 acl_t acl;
49 int ret;
50
51 if (HAVE_ACL_GET_FD && source_desc != -1)
52 acl = acl_get_fd (source_desc);
53 else
54 acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
55 if (acl == NULL)
56 {
57 if (! acl_errno_valid (errno))
58 return qset_acl (dst_name, dest_desc, mode);
59 else
60 return -2;
61 }
62
63 if (HAVE_ACL_SET_FD && dest_desc != -1)
64 ret = acl_set_fd (dest_desc, acl);
65 else
66 ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
67 if (ret != 0)
68 {
69 int saved_errno = errno;
70
71 if (! acl_errno_valid (errno) && !acl_access_nontrivial (acl))
72 {
73 acl_free (acl);
74 return chmod_or_fchmod (dst_name, dest_desc, mode);
75 }
76 else
77 {
78 acl_free (acl);
79 chmod_or_fchmod (dst_name, dest_desc, mode);
80 errno = saved_errno;
81 return -1;
82 }
83 }
84 else
85 acl_free (acl);
86
87 if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
88 {
89 /* We did not call chmod so far, and either the mode and the ACL are
90 separate or special bits are to be set which don't fit into ACLs. */
91
92 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
93 return -1;
94 }
95
96 if (S_ISDIR (mode))
97 {
98 acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
99 if (acl == NULL)
100 return -2;
101
102 if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
103 {
104 int saved_errno = errno;
105
106 acl_free (acl);
107 errno = saved_errno;
108 return -1;
109 }
110 else
111 acl_free (acl);
112 }
113 return 0;
114
115# else /* HAVE_ACL_TYPE_EXTENDED */
116 /* Mac OS X */
117
118 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
119 and acl_get_file (name, ACL_TYPE_DEFAULT)
120 always return NULL / EINVAL. You have to use
121 acl_get_file (name, ACL_TYPE_EXTENDED)
122 or acl_get_fd (open (name, ...))
123 to retrieve an ACL.
124 On the other hand,
125 acl_set_file (name, ACL_TYPE_ACCESS, acl)
126 and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
127 have the same effect as
128 acl_set_file (name, ACL_TYPE_EXTENDED, acl):
129 Each of these calls sets the file's ACL. */
130
131 acl_t acl;
132 int ret;
133
134 if (HAVE_ACL_GET_FD && source_desc != -1)
135 acl = acl_get_fd (source_desc);
136 else
137 acl = acl_get_file (src_name, ACL_TYPE_EXTENDED);
138 if (acl == NULL)
139 {
140 if (!acl_errno_valid (errno))
141 return qset_acl (dst_name, dest_desc, mode);
142 else
143 return -2;
144 }
145
146 if (HAVE_ACL_SET_FD && dest_desc != -1)
147 ret = acl_set_fd (dest_desc, acl);
148 else
149 ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl);
150 if (ret != 0)
151 {
152 int saved_errno = errno;
153
154 if (!acl_errno_valid (saved_errno) && !acl_extended_nontrivial (acl))
155 {
156 acl_free (acl);
157 return chmod_or_fchmod (dst_name, dest_desc, mode);
158 }
159 else
160 {
161 acl_free (acl);
162 chmod_or_fchmod (dst_name, dest_desc, mode);
163 errno = saved_errno;
164 return -1;
165 }
166 }
167 else
168 acl_free (acl);
169
170 /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
171 return chmod_or_fchmod (dst_name, dest_desc, mode);
172
173# endif
174
175#elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
176
177 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
178 of Unixware. The acl() call returns the access and default ACL both
179 at once. */
180# ifdef ACE_GETACL
181 int ace_count;
182 ace_t *ace_entries;
183# endif
184 int count;
185 aclent_t *entries;
186 int did_chmod;
187 int saved_errno;
188 int ret;
189
190# ifdef ACE_GETACL
191 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
192 file systems (whereas the other ones are used in UFS file systems).
193 There is an API
194 pathconf (name, _PC_ACL_ENABLED)
195 fpathconf (desc, _PC_ACL_ENABLED)
196 that allows to determine which of the two kinds of ACLs is supported
197 for the given file. But some file systems may implement this call
198 incorrectly, so better not use it.
199 When fetching the source ACL, we simply fetch both ACL types.
200 When setting the destination ACL, we try either ACL types, assuming
201 that the kernel will translate the ACL from one form to the other.
202 (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
203 the description of ENOTSUP.) */
204 for (;;)
205 {
206 ace_count = (source_desc != -1
207 ? facl (source_desc, ACE_GETACLCNT, 0, NULL)
208 : acl (src_name, ACE_GETACLCNT, 0, NULL));
209
210 if (ace_count < 0)
211 {
212 if (errno == ENOSYS || errno == EINVAL)
213 {
214 ace_count = 0;
215 ace_entries = NULL;
216 break;
217 }
218 else
219 return -2;
220 }
221
222 if (ace_count == 0)
223 {
224 ace_entries = NULL;
225 break;
226 }
227
228 ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t));
229 if (ace_entries == NULL)
230 {
231 errno = ENOMEM;
232 return -2;
233 }
234
235 ret = (source_desc != -1
236 ? facl (source_desc, ACE_GETACL, ace_count, ace_entries)
237 : acl (src_name, ACE_GETACL, ace_count, ace_entries));
238 if (ret < 0)
239 {
240 free (ace_entries);
241 if (errno == ENOSYS || errno == EINVAL)
242 {
243 ace_count = 0;
244 ace_entries = NULL;
245 break;
246 }
247 else
248 return -2;
249 }
250 if (ret == ace_count)
251 break;
252 /* Huh? The number of ACL entries changed since the last call.
253 Repeat. */
254 }
255# endif
256
257 for (;;)
258 {
259 count = (source_desc != -1
260 ? facl (source_desc, GETACLCNT, 0, NULL)
261 : acl (src_name, GETACLCNT, 0, NULL));
262
263 if (count < 0)
264 {
265 if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
266 {
267 count = 0;
268 entries = NULL;
269 break;
270 }
271 else
272 return -2;
273 }
274
275 if (count == 0)
276 {
277 entries = NULL;
278 break;
279 }
280
281 entries = (aclent_t *) malloc (count * sizeof (aclent_t));
282 if (entries == NULL)
283 {
284 errno = ENOMEM;
285 return -2;
286 }
287
288 if ((source_desc != -1
289 ? facl (source_desc, GETACL, count, entries)
290 : acl (src_name, GETACL, count, entries))
291 == count)
292 break;
293 /* Huh? The number of ACL entries changed since the last call.
294 Repeat. */
295 }
296
297 /* Is there an ACL of either kind? */
298# ifdef ACE_GETACL
299 if (ace_count == 0)
300# endif
301 if (count == 0)
302 return qset_acl (dst_name, dest_desc, mode);
303
304 did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
305 saved_errno = 0; /* the first non-ignorable error code */
306
307 if (!MODE_INSIDE_ACL)
308 {
309 /* On Cygwin, it is necessary to call chmod before acl, because
310 chmod can change the contents of the ACL (in ways that don't
311 change the allowed accesses, but still visible). */
312 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
313 saved_errno = errno;
314 did_chmod = 1;
315 }
316
317 /* If both ace_entries and entries are available, try SETACL before
318 ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
319 can. */
320
321 if (count > 0)
322 {
323 ret = (dest_desc != -1
324 ? facl (dest_desc, SETACL, count, entries)
325 : acl (dst_name, SETACL, count, entries));
326 if (ret < 0 && saved_errno == 0)
327 {
328 saved_errno = errno;
329 if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
330 && !acl_nontrivial (count, entries))
331 saved_errno = 0;
332 }
333 else
334 did_chmod = 1;
335 }
336 free (entries);
337
338# ifdef ACE_GETACL
339 if (ace_count > 0)
340 {
341 ret = (dest_desc != -1
342 ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries)
343 : acl (dst_name, ACE_SETACL, ace_count, ace_entries));
344 if (ret < 0 && saved_errno == 0)
345 {
346 saved_errno = errno;
347 if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
348 && !acl_ace_nontrivial (ace_count, ace_entries))
349 saved_errno = 0;
350 }
351 }
352 free (ace_entries);
353# endif
354
355 if (MODE_INSIDE_ACL
356 && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
357 {
358 /* We did not call chmod so far, and either the mode and the ACL are
359 separate or special bits are to be set which don't fit into ACLs. */
360
361 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
362 {
363 if (saved_errno == 0)
364 saved_errno = errno;
365 }
366 }
367
368 if (saved_errno)
369 {
370 errno = saved_errno;
371 return -1;
372 }
373 return 0;
374
375#elif USE_ACL && HAVE_GETACL /* HP-UX */
376
377 struct acl_entry entries[NACLENTRIES];
378 int count;
379# if HAVE_ACLV_H
380 struct acl aclv_entries[NACLVENTRIES];
381 int aclv_count;
382# endif
383 int did_chmod;
384 int saved_errno;
385 int ret;
386
387 count = (source_desc != -1
388 ? fgetacl (source_desc, NACLENTRIES, entries)
389 : getacl (src_name, NACLENTRIES, entries));
390
391 if (count < 0)
392 {
393 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
394 count = 0;
395 else
396 return -2;
397 }
398 else if (count > 0)
399 {
400 if (count > NACLENTRIES)
401 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
402 abort ();
403 }
404
405# if HAVE_ACLV_H
406 aclv_count = acl ((char *) src_name, ACL_GET, NACLVENTRIES, aclv_entries);
407
408 if (aclv_count < 0)
409 {
410 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
411 count = 0;
412 else
413 return -2;
414 }
415 else if (aclv_count > 0)
416 {
417 if (aclv_count > NACLVENTRIES)
418 /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */
419 abort ();
420 }
421# endif
422
423 if (count == 0)
424# if HAVE_ACLV_H
425 if (aclv_count == 0)
426# endif
427 return qset_acl (dst_name, dest_desc, mode);
428
429 did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
430 saved_errno = 0; /* the first non-ignorable error code */
431
432 if (count > 0)
433 {
434 ret = (dest_desc != -1
435 ? fsetacl (dest_desc, count, entries)
436 : setacl (dst_name, count, entries));
437 if (ret < 0 && saved_errno == 0)
438 {
439 saved_errno = errno;
440 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
441 {
442 struct stat source_statbuf;
443
444 if ((source_desc != -1
445 ? fstat (source_desc, &source_statbuf)
446 : stat (src_name, &source_statbuf)) == 0)
447 {
448 if (!acl_nontrivial (count, entries, &source_statbuf))
449 saved_errno = 0;
450 }
451 else
452 saved_errno = errno;
453 }
454 }
455 else
456 did_chmod = 1;
457 }
458
459# if HAVE_ACLV_H
460 if (aclv_count > 0)
461 {
462 ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries);
463 if (ret < 0 && saved_errno == 0)
464 {
465 saved_errno = errno;
466 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
467 {
468 if (!aclv_nontrivial (aclv_count, aclv_entries))
469 saved_errno = 0;
470 }
471 }
472 else
473 did_chmod = 1;
474 }
475# endif
476
477 if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
478 {
479 /* We did not call chmod so far, and special bits are to be set which
480 don't fit into ACLs. */
481
482 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
483 {
484 if (saved_errno == 0)
485 saved_errno = errno;
486 }
487 }
488
489 if (saved_errno)
490 {
491 errno = saved_errno;
492 return -1;
493 }
494 return 0;
495
496#elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */
497
498 /* TODO */
499
500#elif USE_ACL && HAVE_STATACL /* older AIX */
501
502 union { struct acl a; char room[4096]; } u;
503 int ret;
504
505 if ((source_desc != -1
506 ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u))
507 : statacl (src_name, STX_NORMAL, &u.a, sizeof (u)))
508 < 0)
509 return -2;
510
511 ret = (dest_desc != -1
512 ? fchacl (dest_desc, &u.a, u.a.acl_len)
513 : chacl (dst_name, &u.a, u.a.acl_len));
514 if (ret < 0)
515 {
516 int saved_errno = errno;
517
518 chmod_or_fchmod (dst_name, dest_desc, mode);
519 errno = saved_errno;
520 return -1;
521 }
522
523 /* No need to call chmod_or_fchmod at this point, since the mode bits
524 S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */
525
526 return 0;
527
528#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
529
530 struct acl entries[NACLENTRIES];
531 int count;
532 int ret;
533
534 count = acl ((char *) src_name, ACL_GET, NACLENTRIES, entries);
535
536 if (count < 0)
537 {
538 if (0)
539 count = 0;
540 else
541 return -2;
542 }
543 else if (count > 0)
544 {
545 if (count > NACLENTRIES)
546 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
547 abort ();
548 }
549
550 if (count == 0)
551 return qset_acl (dst_name, dest_desc, mode);
552
553 ret = acl ((char *) dst_name, ACL_SET, count, entries);
554 if (ret < 0)
555 {
556 int saved_errno = errno;
557
558 if (0)
559 {
560 if (!acl_nontrivial (count, entries))
561 return chmod_or_fchmod (dst_name, dest_desc, mode);
562 }
563
564 chmod_or_fchmod (dst_name, dest_desc, mode);
565 errno = saved_errno;
566 return -1;
567 }
568
569 if (mode & (S_ISUID | S_ISGID | S_ISVTX))
570 {
571 /* We did not call chmod so far, and either the mode and the ACL are
572 separate or special bits are to be set which don't fit into ACLs. */
573
574 return chmod_or_fchmod (dst_name, dest_desc, mode);
575 }
576 return 0;
577
578#else
579
580 return qset_acl (dst_name, dest_desc, mode);
581
582#endif
583}
diff --git a/lib/qset-acl.c b/lib/qset-acl.c
new file mode 100644
index 00000000000..7bde2c15b0d
--- /dev/null
+++ b/lib/qset-acl.c
@@ -0,0 +1,676 @@
1/* qset-acl.c - set access control list equivalent to a mode
2
3 Copyright (C) 2002-2003, 2005-2013 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 Written by Paul Eggert and Andreas Gruenbacher, and Bruno Haible. */
19
20#include <config.h>
21
22#define ACL_INTERNAL_INLINE _GL_EXTERN_INLINE
23
24#include "acl.h"
25
26#include "acl-internal.h"
27
28
29/* If DESC is a valid file descriptor use fchmod to change the
30 file's mode to MODE on systems that have fchmod. On systems
31 that don't have fchmod and if DESC is invalid, use chmod on
32 NAME instead.
33 Return 0 if successful. Return -1 and set errno upon failure. */
34
35int
36chmod_or_fchmod (const char *name, int desc, mode_t mode)
37{
38 if (HAVE_FCHMOD && desc != -1)
39 return fchmod (desc, mode);
40 else
41 return chmod (name, mode);
42}
43
44/* Set the access control lists of a file. If DESC is a valid file
45 descriptor, use file descriptor operations where available, else use
46 filename based operations on NAME. If access control lists are not
47 available, fchmod the target file to MODE. Also sets the
48 non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX)
49 to those from MODE if any are set.
50 Return 0 if successful. Return -1 and set errno upon failure. */
51
52int
53qset_acl (char const *name, int desc, mode_t mode)
54{
55#if USE_ACL
56# if HAVE_ACL_GET_FILE
57 /* POSIX 1003.1e draft 17 (abandoned) specific version. */
58 /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
59# if !HAVE_ACL_TYPE_EXTENDED
60 /* Linux, FreeBSD, IRIX, Tru64 */
61
62 /* We must also have acl_from_text and acl_delete_def_file.
63 (acl_delete_def_file could be emulated with acl_init followed
64 by acl_set_file, but acl_set_file with an empty acl is
65 unspecified.) */
66
67# ifndef HAVE_ACL_FROM_TEXT
68# error Must have acl_from_text (see POSIX 1003.1e draft 17).
69# endif
70# ifndef HAVE_ACL_DELETE_DEF_FILE
71# error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
72# endif
73
74 acl_t acl;
75 int ret;
76
77 if (HAVE_ACL_FROM_MODE) /* Linux */
78 {
79 acl = acl_from_mode (mode);
80 if (!acl)
81 return -1;
82 }
83 else /* FreeBSD, IRIX, Tru64 */
84 {
85 /* If we were to create the ACL using the functions acl_init(),
86 acl_create_entry(), acl_set_tag_type(), acl_set_qualifier(),
87 acl_get_permset(), acl_clear_perm[s](), acl_add_perm(), we
88 would need to create a qualifier. I don't know how to do this.
89 So create it using acl_from_text(). */
90
91# if HAVE_ACL_FREE_TEXT /* Tru64 */
92 char acl_text[] = "u::---,g::---,o::---,";
93# else /* FreeBSD, IRIX */
94 char acl_text[] = "u::---,g::---,o::---";
95# endif
96
97 if (mode & S_IRUSR) acl_text[ 3] = 'r';
98 if (mode & S_IWUSR) acl_text[ 4] = 'w';
99 if (mode & S_IXUSR) acl_text[ 5] = 'x';
100 if (mode & S_IRGRP) acl_text[10] = 'r';
101 if (mode & S_IWGRP) acl_text[11] = 'w';
102 if (mode & S_IXGRP) acl_text[12] = 'x';
103 if (mode & S_IROTH) acl_text[17] = 'r';
104 if (mode & S_IWOTH) acl_text[18] = 'w';
105 if (mode & S_IXOTH) acl_text[19] = 'x';
106
107 acl = acl_from_text (acl_text);
108 if (!acl)
109 return -1;
110 }
111 if (HAVE_ACL_SET_FD && desc != -1)
112 ret = acl_set_fd (desc, acl);
113 else
114 ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
115 if (ret != 0)
116 {
117 int saved_errno = errno;
118 acl_free (acl);
119 if (! acl_errno_valid (errno))
120 return chmod_or_fchmod (name, desc, mode);
121 errno = saved_errno;
122 return -1;
123 }
124 else
125 acl_free (acl);
126
127 if (S_ISDIR (mode) && acl_delete_def_file (name))
128 return -1;
129
130 if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
131 {
132 /* We did not call chmod so far, and either the mode and the ACL are
133 separate or special bits are to be set which don't fit into ACLs. */
134 return chmod_or_fchmod (name, desc, mode);
135 }
136 return 0;
137
138# else /* HAVE_ACL_TYPE_EXTENDED */
139 /* Mac OS X */
140
141 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
142 and acl_get_file (name, ACL_TYPE_DEFAULT)
143 always return NULL / EINVAL. You have to use
144 acl_get_file (name, ACL_TYPE_EXTENDED)
145 or acl_get_fd (open (name, ...))
146 to retrieve an ACL.
147 On the other hand,
148 acl_set_file (name, ACL_TYPE_ACCESS, acl)
149 and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
150 have the same effect as
151 acl_set_file (name, ACL_TYPE_EXTENDED, acl):
152 Each of these calls sets the file's ACL. */
153
154 acl_t acl;
155 int ret;
156
157 /* Remove the ACL if the file has ACLs. */
158 if (HAVE_ACL_GET_FD && desc != -1)
159 acl = acl_get_fd (desc);
160 else
161 acl = acl_get_file (name, ACL_TYPE_EXTENDED);
162 if (acl)
163 {
164 acl_free (acl);
165
166 acl = acl_init (0);
167 if (acl)
168 {
169 if (HAVE_ACL_SET_FD && desc != -1)
170 ret = acl_set_fd (desc, acl);
171 else
172 ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl);
173 if (ret != 0)
174 {
175 int saved_errno = errno;
176 acl_free (acl);
177 if (! acl_errno_valid (saved_errno))
178 return chmod_or_fchmod (name, desc, mode);
179 errno = saved_errno;
180 return -1;
181 }
182 acl_free (acl);
183 }
184 }
185
186 /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
187 return chmod_or_fchmod (name, desc, mode);
188# endif
189
190# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
191
192 int done_setacl = 0;
193
194# ifdef ACE_GETACL
195 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
196 file systems (whereas the other ones are used in UFS file systems). */
197
198 /* The flags in the ace_t structure changed in a binary incompatible way
199 when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
200 How to distinguish the two conventions at runtime?
201 We fetch the existing ACL. In the old convention, usually three ACEs have
202 a_flags = ACE_OWNER / ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400.
203 In the new convention, these values are not used. */
204 int convention;
205
206 {
207 /* Initially, try to read the entries into a stack-allocated buffer.
208 Use malloc if it does not fit. */
209 enum
210 {
211 alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
212 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
213 };
214 ace_t buf[alloc_init];
215 size_t alloc = alloc_init;
216 ace_t *entries = buf;
217 ace_t *malloced = NULL;
218 int count;
219
220 for (;;)
221 {
222 count = (desc != -1
223 ? facl (desc, ACE_GETACL, alloc, entries)
224 : acl (name, ACE_GETACL, alloc, entries));
225 if (count < 0 && errno == ENOSPC)
226 {
227 /* Increase the size of the buffer. */
228 free (malloced);
229 if (alloc > alloc_max / 2)
230 {
231 errno = ENOMEM;
232 return -1;
233 }
234 alloc = 2 * alloc; /* <= alloc_max */
235 entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
236 if (entries == NULL)
237 {
238 errno = ENOMEM;
239 return -1;
240 }
241 continue;
242 }
243 break;
244 }
245
246 if (count <= 0)
247 convention = -1;
248 else
249 {
250 int i;
251
252 convention = 0;
253 for (i = 0; i < count; i++)
254 if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER))
255 {
256 convention = 1;
257 break;
258 }
259 }
260 free (malloced);
261 }
262
263 if (convention >= 0)
264 {
265 ace_t entries[6];
266 int count;
267 int ret;
268
269 if (convention)
270 {
271 /* Running on Solaris 10. */
272 entries[0].a_type = OLD_ALLOW;
273 entries[0].a_flags = OLD_ACE_OWNER;
274 entries[0].a_who = 0; /* irrelevant */
275 entries[0].a_access_mask = (mode >> 6) & 7;
276 entries[1].a_type = OLD_ALLOW;
277 entries[1].a_flags = OLD_ACE_GROUP;
278 entries[1].a_who = 0; /* irrelevant */
279 entries[1].a_access_mask = (mode >> 3) & 7;
280 entries[2].a_type = OLD_ALLOW;
281 entries[2].a_flags = OLD_ACE_OTHER;
282 entries[2].a_who = 0;
283 entries[2].a_access_mask = mode & 7;
284 count = 3;
285 }
286 else
287 {
288 /* Running on Solaris 10 (newer version) or Solaris 11.
289 The details here were found through "/bin/ls -lvd somefiles". */
290 entries[0].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
291 entries[0].a_flags = NEW_ACE_OWNER;
292 entries[0].a_who = 0; /* irrelevant */
293 entries[0].a_access_mask = 0;
294 entries[1].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
295 entries[1].a_flags = NEW_ACE_OWNER;
296 entries[1].a_who = 0; /* irrelevant */
297 entries[1].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS
298 | NEW_ACE_WRITE_ATTRIBUTES
299 | NEW_ACE_WRITE_ACL
300 | NEW_ACE_WRITE_OWNER;
301 if (mode & 0400)
302 entries[1].a_access_mask |= NEW_ACE_READ_DATA;
303 else
304 entries[0].a_access_mask |= NEW_ACE_READ_DATA;
305 if (mode & 0200)
306 entries[1].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
307 else
308 entries[0].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
309 if (mode & 0100)
310 entries[1].a_access_mask |= NEW_ACE_EXECUTE;
311 else
312 entries[0].a_access_mask |= NEW_ACE_EXECUTE;
313 entries[2].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
314 entries[2].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP;
315 entries[2].a_who = 0; /* irrelevant */
316 entries[2].a_access_mask = 0;
317 entries[3].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
318 entries[3].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP;
319 entries[3].a_who = 0; /* irrelevant */
320 entries[3].a_access_mask = 0;
321 if (mode & 0040)
322 entries[3].a_access_mask |= NEW_ACE_READ_DATA;
323 else
324 entries[2].a_access_mask |= NEW_ACE_READ_DATA;
325 if (mode & 0020)
326 entries[3].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
327 else
328 entries[2].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
329 if (mode & 0010)
330 entries[3].a_access_mask |= NEW_ACE_EXECUTE;
331 else
332 entries[2].a_access_mask |= NEW_ACE_EXECUTE;
333 entries[4].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
334 entries[4].a_flags = NEW_ACE_EVERYONE;
335 entries[4].a_who = 0;
336 entries[4].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS
337 | NEW_ACE_WRITE_ATTRIBUTES
338 | NEW_ACE_WRITE_ACL
339 | NEW_ACE_WRITE_OWNER;
340 entries[5].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
341 entries[5].a_flags = NEW_ACE_EVERYONE;
342 entries[5].a_who = 0;
343 entries[5].a_access_mask = NEW_ACE_READ_NAMED_ATTRS
344 | NEW_ACE_READ_ATTRIBUTES
345 | NEW_ACE_READ_ACL
346 | NEW_ACE_SYNCHRONIZE;
347 if (mode & 0004)
348 entries[5].a_access_mask |= NEW_ACE_READ_DATA;
349 else
350 entries[4].a_access_mask |= NEW_ACE_READ_DATA;
351 if (mode & 0002)
352 entries[5].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
353 else
354 entries[4].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
355 if (mode & 0001)
356 entries[5].a_access_mask |= NEW_ACE_EXECUTE;
357 else
358 entries[4].a_access_mask |= NEW_ACE_EXECUTE;
359 count = 6;
360 }
361 if (desc != -1)
362 ret = facl (desc, ACE_SETACL, count, entries);
363 else
364 ret = acl (name, ACE_SETACL, count, entries);
365 if (ret < 0 && errno != EINVAL && errno != ENOTSUP)
366 {
367 if (errno == ENOSYS)
368 return chmod_or_fchmod (name, desc, mode);
369 return -1;
370 }
371 if (ret == 0)
372 done_setacl = 1;
373 }
374# endif
375
376 if (!done_setacl)
377 {
378 aclent_t entries[3];
379 int ret;
380
381 entries[0].a_type = USER_OBJ;
382 entries[0].a_id = 0; /* irrelevant */
383 entries[0].a_perm = (mode >> 6) & 7;
384 entries[1].a_type = GROUP_OBJ;
385 entries[1].a_id = 0; /* irrelevant */
386 entries[1].a_perm = (mode >> 3) & 7;
387 entries[2].a_type = OTHER_OBJ;
388 entries[2].a_id = 0;
389 entries[2].a_perm = mode & 7;
390
391 if (desc != -1)
392 ret = facl (desc, SETACL,
393 sizeof (entries) / sizeof (aclent_t), entries);
394 else
395 ret = acl (name, SETACL,
396 sizeof (entries) / sizeof (aclent_t), entries);
397 if (ret < 0)
398 {
399 if (errno == ENOSYS || errno == EOPNOTSUPP)
400 return chmod_or_fchmod (name, desc, mode);
401 return -1;
402 }
403 }
404
405 if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
406 {
407 /* We did not call chmod so far, so the special bits have not yet
408 been set. */
409 return chmod_or_fchmod (name, desc, mode);
410 }
411 return 0;
412
413# elif HAVE_GETACL /* HP-UX */
414
415 struct stat statbuf;
416 int ret;
417
418 if (desc != -1)
419 ret = fstat (desc, &statbuf);
420 else
421 ret = stat (name, &statbuf);
422 if (ret < 0)
423 return -1;
424
425 {
426 struct acl_entry entries[3];
427
428 entries[0].uid = statbuf.st_uid;
429 entries[0].gid = ACL_NSGROUP;
430 entries[0].mode = (mode >> 6) & 7;
431 entries[1].uid = ACL_NSUSER;
432 entries[1].gid = statbuf.st_gid;
433 entries[1].mode = (mode >> 3) & 7;
434 entries[2].uid = ACL_NSUSER;
435 entries[2].gid = ACL_NSGROUP;
436 entries[2].mode = mode & 7;
437
438 if (desc != -1)
439 ret = fsetacl (desc, sizeof (entries) / sizeof (struct acl_entry), entries);
440 else
441 ret = setacl (name, sizeof (entries) / sizeof (struct acl_entry), entries);
442 }
443 if (ret < 0)
444 {
445 if (!(errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
446 return -1;
447
448# if HAVE_ACLV_H /* HP-UX >= 11.11 */
449 {
450 struct acl entries[4];
451
452 entries[0].a_type = USER_OBJ;
453 entries[0].a_id = 0; /* irrelevant */
454 entries[0].a_perm = (mode >> 6) & 7;
455 entries[1].a_type = GROUP_OBJ;
456 entries[1].a_id = 0; /* irrelevant */
457 entries[1].a_perm = (mode >> 3) & 7;
458 entries[2].a_type = CLASS_OBJ;
459 entries[2].a_id = 0;
460 entries[2].a_perm = (mode >> 3) & 7;
461 entries[3].a_type = OTHER_OBJ;
462 entries[3].a_id = 0;
463 entries[3].a_perm = mode & 7;
464
465 ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries);
466 if (ret > 0)
467 abort ();
468 if (ret < 0)
469 {
470 if (0)
471 return chmod_or_fchmod (name, desc, mode);
472 return -1;
473 }
474
475 ret = acl ((char *) name, ACL_SET,
476 sizeof (entries) / sizeof (struct acl), entries);
477 if (ret < 0)
478 {
479 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
480 return chmod_or_fchmod (name, desc, mode);
481 return -1;
482 }
483 }
484# else
485 return chmod_or_fchmod (name, desc, mode);
486# endif
487 }
488
489 if (mode & (S_ISUID | S_ISGID | S_ISVTX))
490 {
491 /* We did not call chmod so far, so the special bits have not yet
492 been set. */
493 return chmod_or_fchmod (name, desc, mode);
494 }
495 return 0;
496
497# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
498
499 acl_type_list_t types;
500 size_t types_size = sizeof (types);
501 acl_type_t type;
502
503 if (aclx_gettypes (name, &types, &types_size) < 0
504 || types.num_entries == 0)
505 return chmod_or_fchmod (name, desc, mode);
506
507 /* XXX Do we need to clear all types of ACLs for the given file, or is it
508 sufficient to clear the first one? */
509 type = types.entries[0];
510 if (type.u64 == ACL_AIXC)
511 {
512 union { struct acl a; char room[128]; } u;
513 int ret;
514
515 u.a.acl_len = (char *) &u.a.acl_ext[0] - (char *) &u.a; /* no entries */
516 u.a.acl_mode = mode & ~(S_IXACL | 0777);
517 u.a.u_access = (mode >> 6) & 7;
518 u.a.g_access = (mode >> 3) & 7;
519 u.a.o_access = mode & 7;
520
521 if (desc != -1)
522 ret = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS,
523 type, &u.a, u.a.acl_len, mode);
524 else
525 ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS,
526 type, &u.a, u.a.acl_len, mode);
527 if (!(ret < 0 && errno == ENOSYS))
528 return ret;
529 }
530 else if (type.u64 == ACL_NFS4)
531 {
532 union { nfs4_acl_int_t a; char room[128]; } u;
533 nfs4_ace_int_t *ace;
534 int ret;
535
536 u.a.aclVersion = NFS4_ACL_INT_STRUCT_VERSION;
537 u.a.aclEntryN = 0;
538 ace = &u.a.aclEntry[0];
539 {
540 ace->flags = ACE4_ID_SPECIAL;
541 ace->aceWho.special_whoid = ACE4_WHO_OWNER;
542 ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
543 ace->aceFlags = 0;
544 ace->aceMask =
545 (mode & 0400 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
546 | (mode & 0200
547 ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
548 | ACE4_ADD_SUBDIRECTORY
549 : 0)
550 | (mode & 0100 ? ACE4_EXECUTE : 0);
551 ace->aceWhoString[0] = '\0';
552 ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
553 ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
554 u.a.aclEntryN++;
555 }
556 {
557 ace->flags = ACE4_ID_SPECIAL;
558 ace->aceWho.special_whoid = ACE4_WHO_GROUP;
559 ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
560 ace->aceFlags = 0;
561 ace->aceMask =
562 (mode & 0040 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
563 | (mode & 0020
564 ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
565 | ACE4_ADD_SUBDIRECTORY
566 : 0)
567 | (mode & 0010 ? ACE4_EXECUTE : 0);
568 ace->aceWhoString[0] = '\0';
569 ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
570 ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
571 u.a.aclEntryN++;
572 }
573 {
574 ace->flags = ACE4_ID_SPECIAL;
575 ace->aceWho.special_whoid = ACE4_WHO_EVERYONE;
576 ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
577 ace->aceFlags = 0;
578 ace->aceMask =
579 (mode & 0004 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
580 | (mode & 0002
581 ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
582 | ACE4_ADD_SUBDIRECTORY
583 : 0)
584 | (mode & 0001 ? ACE4_EXECUTE : 0);
585 ace->aceWhoString[0] = '\0';
586 ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
587 ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
588 u.a.aclEntryN++;
589 }
590 u.a.aclLength = (char *) ace - (char *) &u.a;
591
592 if (desc != -1)
593 ret = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS,
594 type, &u.a, u.a.aclLength, mode);
595 else
596 ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS,
597 type, &u.a, u.a.aclLength, mode);
598 if (!(ret < 0 && errno == ENOSYS))
599 return ret;
600 }
601
602 return chmod_or_fchmod (name, desc, mode);
603
604# elif HAVE_STATACL /* older AIX */
605
606 union { struct acl a; char room[128]; } u;
607 int ret;
608
609 u.a.acl_len = (char *) &u.a.acl_ext[0] - (char *) &u.a; /* no entries */
610 u.a.acl_mode = mode & ~(S_IXACL | 0777);
611 u.a.u_access = (mode >> 6) & 7;
612 u.a.g_access = (mode >> 3) & 7;
613 u.a.o_access = mode & 7;
614
615 if (desc != -1)
616 ret = fchacl (desc, &u.a, u.a.acl_len);
617 else
618 ret = chacl (name, &u.a, u.a.acl_len);
619
620 if (ret < 0 && errno == ENOSYS)
621 return chmod_or_fchmod (name, desc, mode);
622
623 return ret;
624
625# elif HAVE_ACLSORT /* NonStop Kernel */
626
627 struct acl entries[4];
628 int ret;
629
630 entries[0].a_type = USER_OBJ;
631 entries[0].a_id = 0; /* irrelevant */
632 entries[0].a_perm = (mode >> 6) & 7;
633 entries[1].a_type = GROUP_OBJ;
634 entries[1].a_id = 0; /* irrelevant */
635 entries[1].a_perm = (mode >> 3) & 7;
636 entries[2].a_type = CLASS_OBJ;
637 entries[2].a_id = 0;
638 entries[2].a_perm = (mode >> 3) & 7;
639 entries[3].a_type = OTHER_OBJ;
640 entries[3].a_id = 0;
641 entries[3].a_perm = mode & 7;
642
643 ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries);
644 if (ret > 0)
645 abort ();
646 if (ret < 0)
647 {
648 if (0)
649 return chmod_or_fchmod (name, desc, mode);
650 return -1;
651 }
652
653 ret = acl ((char *) name, ACL_SET,
654 sizeof (entries) / sizeof (struct acl), entries);
655 if (ret < 0)
656 {
657 if (0)
658 return chmod_or_fchmod (name, desc, mode);
659 return -1;
660 }
661
662 if (mode & (S_ISUID | S_ISGID | S_ISVTX))
663 {
664 /* We did not call chmod so far, so the special bits have not yet
665 been set. */
666 return chmod_or_fchmod (name, desc, mode);
667 }
668 return 0;
669
670# else /* Unknown flavor of ACLs */
671 return chmod_or_fchmod (name, desc, mode);
672# endif
673#else /* !USE_ACL */
674 return chmod_or_fchmod (name, desc, mode);
675#endif
676}