diff options
| -rwxr-xr-x | admin/merge-gnulib | 2 | ||||
| -rw-r--r-- | doc/misc/texinfo.tex | 3 | ||||
| -rw-r--r-- | lib/acl-internal.c | 31 | ||||
| -rw-r--r-- | lib/acl-internal.h | 57 | ||||
| -rw-r--r-- | lib/get-permissions.c | 280 | ||||
| -rw-r--r-- | lib/gnulib.mk | 23 | ||||
| -rw-r--r-- | lib/inttypes.in.h | 4 | ||||
| -rw-r--r-- | lib/qcopy-acl.c | 531 | ||||
| -rw-r--r-- | lib/set-permissions.c (renamed from lib/qset-acl.c) | 805 | ||||
| -rw-r--r-- | lib/string.in.h | 21 | ||||
| -rw-r--r-- | m4/acl.m4 | 24 | ||||
| -rw-r--r-- | m4/gnulib-comp.m4 | 8 | ||||
| -rw-r--r-- | m4/stdio_h.m4 | 20 | ||||
| -rw-r--r-- | nt/gnulib.mk | 23 |
14 files changed, 924 insertions, 908 deletions
diff --git a/admin/merge-gnulib b/admin/merge-gnulib index e63422b0d5e..e7910a642c7 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib | |||
| @@ -34,7 +34,7 @@ GNULIB_MODULES=' | |||
| 34 | getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog | 34 | getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog |
| 35 | intprops largefile lstat | 35 | intprops largefile lstat |
| 36 | manywarnings memrchr mkostemp mktime | 36 | manywarnings memrchr mkostemp mktime |
| 37 | pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat | 37 | pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat |
| 38 | sig2str socklen stat-time stdalign stddef stdio | 38 | sig2str socklen stat-time stdalign stddef stdio |
| 39 | stpcpy strftime strtoimax strtoumax symlink sys_stat | 39 | stpcpy strftime strtoimax strtoumax symlink sys_stat |
| 40 | sys_time time time_r timer-time timespec-add timespec-sub | 40 | sys_time time time_r timer-time timespec-add timespec-sub |
diff --git a/doc/misc/texinfo.tex b/doc/misc/texinfo.tex index 152e9853485..4b4856469a8 100644 --- a/doc/misc/texinfo.tex +++ b/doc/misc/texinfo.tex | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | % Load plain if necessary, i.e., if running under initex. | 3 | % Load plain if necessary, i.e., if running under initex. |
| 4 | \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi | 4 | \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi |
| 5 | % | 5 | % |
| 6 | \def\texinfoversion{2015-05-06.11} | 6 | \def\texinfoversion{2015-05-26.15} |
| 7 | % | 7 | % |
| 8 | % Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, | 8 | % Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, |
| 9 | % 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, | 9 | % 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, |
| @@ -8954,7 +8954,6 @@ directory should work if nowhere else does.} | |||
| 8954 | \catcode\count255=#1\relax | 8954 | \catcode\count255=#1\relax |
| 8955 | \advance\count255 by 1 | 8955 | \advance\count255 by 1 |
| 8956 | \repeat | 8956 | \repeat |
| 8957 | |||
| 8958 | } | 8957 | } |
| 8959 | 8958 | ||
| 8960 | % @documentencoding sets the definition of non-ASCII characters | 8959 | % @documentencoding sets the definition of non-ASCII characters |
diff --git a/lib/acl-internal.c b/lib/acl-internal.c index d9bd4461ea6..1a2f8c44bf7 100644 --- a/lib/acl-internal.c +++ b/lib/acl-internal.c | |||
| @@ -467,3 +467,34 @@ acl_nontrivial (int count, struct acl *entries) | |||
| 467 | } | 467 | } |
| 468 | 468 | ||
| 469 | #endif | 469 | #endif |
| 470 | |||
| 471 | void | ||
| 472 | free_permission_context (struct permission_context *ctx) | ||
| 473 | { | ||
| 474 | #ifdef USE_ACL | ||
| 475 | # if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ | ||
| 476 | if (ctx->acl) | ||
| 477 | acl_free (ctx->acl); | ||
| 478 | # if !HAVE_ACL_TYPE_EXTENDED | ||
| 479 | if (ctx->default_acl) | ||
| 480 | acl_free (ctx->default_acl); | ||
| 481 | # endif | ||
| 482 | |||
| 483 | # elif defined GETACL /* Solaris, Cygwin */ | ||
| 484 | free (ctx->entries); | ||
| 485 | # ifdef ACE_GETACL | ||
| 486 | free (ctx->ace_entries); | ||
| 487 | # endif | ||
| 488 | |||
| 489 | # elif HAVE_GETACL /* HP-UX */ | ||
| 490 | |||
| 491 | # if HAVE_ACLV_H | ||
| 492 | # endif | ||
| 493 | |||
| 494 | # elif HAVE_STATACL /* older AIX */ | ||
| 495 | |||
| 496 | # elif HAVE_ACLSORT /* NonStop Kernel */ | ||
| 497 | |||
| 498 | # endif | ||
| 499 | #endif | ||
| 500 | } | ||
diff --git a/lib/acl-internal.h b/lib/acl-internal.h index 9b9fae2e9e0..11fdea14042 100644 --- a/lib/acl-internal.h +++ b/lib/acl-internal.h | |||
| @@ -133,12 +133,9 @@ rpl_acl_set_fd (int fd, acl_t acl) | |||
| 133 | # define acl_from_mode(mode) (NULL) | 133 | # define acl_from_mode(mode) (NULL) |
| 134 | # endif | 134 | # endif |
| 135 | 135 | ||
| 136 | /* Set to 1 if a file's mode is implicit by the ACL. | 136 | /* Set to 0 if a file's mode is stored independently from the ACL. */ |
| 137 | Set to 0 if a file's mode is stored independently from the ACL. */ | ||
| 138 | # if (HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP) || defined __sgi /* Mac OS X, IRIX */ | 137 | # if (HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP) || defined __sgi /* Mac OS X, IRIX */ |
| 139 | # define MODE_INSIDE_ACL 0 | 138 | # define MODE_INSIDE_ACL 0 |
| 140 | # else | ||
| 141 | # define MODE_INSIDE_ACL 1 | ||
| 142 | # endif | 139 | # endif |
| 143 | 140 | ||
| 144 | /* Return the number of entries in ACL. | 141 | /* Return the number of entries in ACL. |
| @@ -164,12 +161,9 @@ extern int acl_access_nontrivial (acl_t); | |||
| 164 | 161 | ||
| 165 | # elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ | 162 | # elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ |
| 166 | 163 | ||
| 167 | /* Set to 1 if a file's mode is implicit by the ACL. | 164 | /* Set to 0 if a file's mode is stored independently from the ACL. */ |
| 168 | Set to 0 if a file's mode is stored independently from the ACL. */ | ||
| 169 | # if defined __CYGWIN__ /* Cygwin */ | 165 | # if defined __CYGWIN__ /* Cygwin */ |
| 170 | # define MODE_INSIDE_ACL 0 | 166 | # define MODE_INSIDE_ACL 0 |
| 171 | # else /* Solaris */ | ||
| 172 | # define MODE_INSIDE_ACL 1 | ||
| 173 | # endif | 167 | # endif |
| 174 | 168 | ||
| 175 | /* Return 1 if the given ACL is non-trivial. | 169 | /* Return 1 if the given ACL is non-trivial. |
| @@ -248,6 +242,53 @@ extern int acl_nontrivial (int count, struct acl *entries); | |||
| 248 | 242 | ||
| 249 | # endif | 243 | # endif |
| 250 | 244 | ||
| 245 | /* Set to 1 if a file's mode is implicit by the ACL. */ | ||
| 246 | # ifndef MODE_INSIDE_ACL | ||
| 247 | # define MODE_INSIDE_ACL 1 | ||
| 248 | # endif | ||
| 249 | |||
| 251 | #endif | 250 | #endif |
| 252 | 251 | ||
| 252 | struct permission_context { | ||
| 253 | mode_t mode; | ||
| 254 | #ifdef USE_ACL | ||
| 255 | # if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ | ||
| 256 | acl_t acl; | ||
| 257 | # if !HAVE_ACL_TYPE_EXTENDED | ||
| 258 | acl_t default_acl; | ||
| 259 | # endif | ||
| 260 | bool acls_not_supported; | ||
| 261 | |||
| 262 | # elif defined GETACL /* Solaris, Cygwin */ | ||
| 263 | int count; | ||
| 264 | aclent_t *entries; | ||
| 265 | # ifdef ACE_GETACL | ||
| 266 | int ace_count; | ||
| 267 | ace_t *ace_entries; | ||
| 268 | # endif | ||
| 269 | |||
| 270 | # elif HAVE_GETACL /* HP-UX */ | ||
| 271 | struct acl_entry entries[NACLENTRIES]; | ||
| 272 | int count; | ||
| 273 | # if HAVE_ACLV_H | ||
| 274 | struct acl aclv_entries[NACLVENTRIES]; | ||
| 275 | int aclv_count; | ||
| 276 | # endif | ||
| 277 | |||
| 278 | # elif HAVE_STATACL /* older AIX */ | ||
| 279 | union { struct acl a; char room[4096]; } u; | ||
| 280 | bool have_u; | ||
| 281 | |||
| 282 | # elif HAVE_ACLSORT /* NonStop Kernel */ | ||
| 283 | struct acl entries[NACLENTRIES]; | ||
| 284 | int count; | ||
| 285 | |||
| 286 | # endif | ||
| 287 | #endif | ||
| 288 | }; | ||
| 289 | |||
| 290 | int get_permissions (const char *, int, mode_t, struct permission_context *); | ||
| 291 | int set_permissions (struct permission_context *, const char *, int); | ||
| 292 | void free_permission_context (struct permission_context *); | ||
| 293 | |||
| 253 | _GL_INLINE_HEADER_END | 294 | _GL_INLINE_HEADER_END |
diff --git a/lib/get-permissions.c b/lib/get-permissions.c new file mode 100644 index 00000000000..ccee1f1410e --- /dev/null +++ b/lib/get-permissions.c | |||
| @@ -0,0 +1,280 @@ | |||
| 1 | /* get-permissions.c - get permissions of a file | ||
| 2 | |||
| 3 | Copyright (C) 2002-2003, 2005-2015 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 <string.h> | ||
| 23 | #include "acl.h" | ||
| 24 | |||
| 25 | #include "acl-internal.h" | ||
| 26 | |||
| 27 | /* Read the permissions of a file into CTX. If DESC is a valid file descriptor, | ||
| 28 | use file descriptor operations, else use filename based operations on NAME. | ||
| 29 | MODE is the file mode obtained from a previous stat call. | ||
| 30 | Return 0 if successful. Return -1 and set errno upon failure. */ | ||
| 31 | |||
| 32 | int | ||
| 33 | get_permissions (const char *name, int desc, mode_t mode, | ||
| 34 | struct permission_context *ctx) | ||
| 35 | { | ||
| 36 | memset (ctx, 0, sizeof(*ctx)); | ||
| 37 | ctx->mode = mode; | ||
| 38 | |||
| 39 | #if USE_ACL && HAVE_ACL_GET_FILE | ||
| 40 | /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ | ||
| 41 | /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ | ||
| 42 | # if !HAVE_ACL_TYPE_EXTENDED | ||
| 43 | /* Linux, FreeBSD, IRIX, Tru64 */ | ||
| 44 | |||
| 45 | if (HAVE_ACL_GET_FD && desc != -1) | ||
| 46 | ctx->acl = acl_get_fd (desc); | ||
| 47 | else | ||
| 48 | ctx->acl = acl_get_file (name, ACL_TYPE_ACCESS); | ||
| 49 | if (ctx->acl == NULL) | ||
| 50 | return acl_errno_valid (errno) ? -1 : 0; | ||
| 51 | |||
| 52 | /* With POSIX ACLs, a file cannot have "no" acl; a file without | ||
| 53 | extended permissions has a "minimal" acl which is equivalent to the | ||
| 54 | file mode. */ | ||
| 55 | |||
| 56 | if (S_ISDIR (mode)) | ||
| 57 | { | ||
| 58 | ctx->default_acl = acl_get_file (name, ACL_TYPE_DEFAULT); | ||
| 59 | if (ctx->default_acl == NULL) | ||
| 60 | return -1; | ||
| 61 | } | ||
| 62 | |||
| 63 | # else /* HAVE_ACL_TYPE_EXTENDED */ | ||
| 64 | /* Mac OS X */ | ||
| 65 | |||
| 66 | /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS) | ||
| 67 | and acl_get_file (name, ACL_TYPE_DEFAULT) | ||
| 68 | always return NULL / EINVAL. You have to use | ||
| 69 | acl_get_file (name, ACL_TYPE_EXTENDED) | ||
| 70 | or acl_get_fd (open (name, ...)) | ||
| 71 | to retrieve an ACL. | ||
| 72 | On the other hand, | ||
| 73 | acl_set_file (name, ACL_TYPE_ACCESS, acl) | ||
| 74 | and acl_set_file (name, ACL_TYPE_DEFAULT, acl) | ||
| 75 | have the same effect as | ||
| 76 | acl_set_file (name, ACL_TYPE_EXTENDED, acl): | ||
| 77 | Each of these calls sets the file's ACL. */ | ||
| 78 | |||
| 79 | if (HAVE_ACL_GET_FD && desc != -1) | ||
| 80 | ctx->acl = acl_get_fd (desc); | ||
| 81 | else | ||
| 82 | ctx->acl = acl_get_file (name, ACL_TYPE_EXTENDED); | ||
| 83 | if (ctx->acl == NULL) | ||
| 84 | return acl_errno_valid (errno) ? -1 : 0; | ||
| 85 | |||
| 86 | # endif | ||
| 87 | |||
| 88 | #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ | ||
| 89 | |||
| 90 | /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions | ||
| 91 | of Unixware. The acl() call returns the access and default ACL both | ||
| 92 | at once. */ | ||
| 93 | # ifdef ACE_GETACL | ||
| 94 | /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 | ||
| 95 | file systems (whereas the other ones are used in UFS file systems). | ||
| 96 | There is an API | ||
| 97 | pathconf (name, _PC_ACL_ENABLED) | ||
| 98 | fpathconf (desc, _PC_ACL_ENABLED) | ||
| 99 | that allows to determine which of the two kinds of ACLs is supported | ||
| 100 | for the given file. But some file systems may implement this call | ||
| 101 | incorrectly, so better not use it. | ||
| 102 | When fetching the source ACL, we simply fetch both ACL types. | ||
| 103 | When setting the destination ACL, we try either ACL types, assuming | ||
| 104 | that the kernel will translate the ACL from one form to the other. | ||
| 105 | (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view> | ||
| 106 | the description of ENOTSUP.) */ | ||
| 107 | for (;;) | ||
| 108 | { | ||
| 109 | int ret; | ||
| 110 | |||
| 111 | if (desc != -1) | ||
| 112 | ret = facl (desc, ACE_GETACLCNT, 0, NULL); | ||
| 113 | else | ||
| 114 | ret = acl (name, ACE_GETACLCNT, 0, NULL); | ||
| 115 | if (ret < 0) | ||
| 116 | { | ||
| 117 | if (errno == ENOSYS || errno == EINVAL) | ||
| 118 | ret = 0; | ||
| 119 | else | ||
| 120 | return -1; | ||
| 121 | } | ||
| 122 | ctx->ace_count = ret; | ||
| 123 | |||
| 124 | if (ctx->ace_count == 0) | ||
| 125 | break; | ||
| 126 | |||
| 127 | ctx->ace_entries = (ace_t *) malloc (ctx->ace_count * sizeof (ace_t)); | ||
| 128 | if (ctx->ace_entries == NULL) | ||
| 129 | { | ||
| 130 | errno = ENOMEM; | ||
| 131 | return -1; | ||
| 132 | } | ||
| 133 | |||
| 134 | if (desc != -1) | ||
| 135 | ret = facl (desc, ACE_GETACL, ctx->ace_count, ctx->ace_entries); | ||
| 136 | else | ||
| 137 | ret = acl (name, ACE_GETACL, ctx->ace_count, ctx->ace_entries); | ||
| 138 | if (ret < 0) | ||
| 139 | { | ||
| 140 | if (errno == ENOSYS || errno == EINVAL) | ||
| 141 | { | ||
| 142 | free (ctx->ace_entries); | ||
| 143 | ctx->ace_entries = NULL; | ||
| 144 | ctx->ace_count = 0; | ||
| 145 | break; | ||
| 146 | } | ||
| 147 | else | ||
| 148 | return -1; | ||
| 149 | } | ||
| 150 | if (ret <= ctx->ace_count) | ||
| 151 | { | ||
| 152 | ctx->ace_count = ret; | ||
| 153 | break; | ||
| 154 | } | ||
| 155 | /* Huh? The number of ACL entries has increased since the last call. | ||
| 156 | Repeat. */ | ||
| 157 | free (ctx->ace_entries); | ||
| 158 | ctx->ace_entries = NULL; | ||
| 159 | } | ||
| 160 | # endif | ||
| 161 | |||
| 162 | for (;;) | ||
| 163 | { | ||
| 164 | int ret; | ||
| 165 | |||
| 166 | if (desc != -1) | ||
| 167 | ret = facl (desc, GETACLCNT, 0, NULL); | ||
| 168 | else | ||
| 169 | ret = acl (name, GETACLCNT, 0, NULL); | ||
| 170 | if (ret < 0) | ||
| 171 | { | ||
| 172 | if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP) | ||
| 173 | ret = 0; | ||
| 174 | else | ||
| 175 | return -1; | ||
| 176 | } | ||
| 177 | ctx->count = ret; | ||
| 178 | |||
| 179 | if (ctx->count == 0) | ||
| 180 | break; | ||
| 181 | |||
| 182 | ctx->entries = (aclent_t *) malloc (ctx->count * sizeof (aclent_t)); | ||
| 183 | if (ctx->entries == NULL) | ||
| 184 | { | ||
| 185 | errno = ENOMEM; | ||
| 186 | return -1; | ||
| 187 | } | ||
| 188 | |||
| 189 | if (desc != -1) | ||
| 190 | ret = facl (desc, GETACL, ctx->count, ctx->entries); | ||
| 191 | else | ||
| 192 | ret = acl (name, GETACL, ctx->count, ctx->entries); | ||
| 193 | if (ret < 0) | ||
| 194 | { | ||
| 195 | if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP) | ||
| 196 | { | ||
| 197 | free (ctx->entries); | ||
| 198 | ctx->entries = NULL; | ||
| 199 | ctx->count = 0; | ||
| 200 | break; | ||
| 201 | } | ||
| 202 | else | ||
| 203 | return -1; | ||
| 204 | } | ||
| 205 | if (ret <= ctx->count) | ||
| 206 | { | ||
| 207 | ctx->count = ret; | ||
| 208 | break; | ||
| 209 | } | ||
| 210 | /* Huh? The number of ACL entries has increased since the last call. | ||
| 211 | Repeat. */ | ||
| 212 | free (ctx->entries); | ||
| 213 | ctx->entries = NULL; | ||
| 214 | } | ||
| 215 | |||
| 216 | #elif USE_ACL && HAVE_GETACL /* HP-UX */ | ||
| 217 | |||
| 218 | int ret; | ||
| 219 | |||
| 220 | if (desc != -1) | ||
| 221 | ret = fgetacl (desc, NACLENTRIES, ctx->entries); | ||
| 222 | else | ||
| 223 | ret = getacl (name, NACLENTRIES, ctx->entries); | ||
| 224 | if (ret < 0) | ||
| 225 | { | ||
| 226 | if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) | ||
| 227 | ret = 0; | ||
| 228 | else | ||
| 229 | return -1; | ||
| 230 | } | ||
| 231 | else if (ret > NACLENTRIES) | ||
| 232 | /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ | ||
| 233 | abort (); | ||
| 234 | ctx->count = ret; | ||
| 235 | |||
| 236 | # if HAVE_ACLV_H | ||
| 237 | ret = acl ((char *) name, ACL_GET, NACLVENTRIES, ctx->aclv_entries); | ||
| 238 | if (ret < 0) | ||
| 239 | { | ||
| 240 | if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) | ||
| 241 | ret = 0; | ||
| 242 | else | ||
| 243 | return -2; | ||
| 244 | } | ||
| 245 | else if (ret > NACLVENTRIES) | ||
| 246 | /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */ | ||
| 247 | abort (); | ||
| 248 | ctx->aclv_count = ret; | ||
| 249 | # endif | ||
| 250 | |||
| 251 | #elif USE_ACL && HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */ | ||
| 252 | |||
| 253 | /* TODO (see set_permissions). */ | ||
| 254 | |||
| 255 | #elif USE_ACL && HAVE_STATACL /* older AIX */ | ||
| 256 | |||
| 257 | if (desc != -1) | ||
| 258 | ret = fstatacl (desc, STX_NORMAL, &ctx->u.a, sizeof (ctx->u)); | ||
| 259 | else | ||
| 260 | ret = statacl (name, STX_NORMAL, &ctx->u.a, sizeof (ctx->u)); | ||
| 261 | if (ret == 0) | ||
| 262 | ctx->have_u = true; | ||
| 263 | |||
| 264 | #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */ | ||
| 265 | |||
| 266 | int ret; | ||
| 267 | |||
| 268 | ret = acl ((char *) name, ACL_GET, NACLENTRIES, ctx->entries); | ||
| 269 | if (ret < 0) | ||
| 270 | return -1; | ||
| 271 | else if (ret > NACLENTRIES) | ||
| 272 | /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ | ||
| 273 | abort (); | ||
| 274 | ctx->count = ret; | ||
| 275 | |||
| 276 | #endif | ||
| 277 | |||
| 278 | return 0; | ||
| 279 | |||
| 280 | } | ||
diff --git a/lib/gnulib.mk b/lib/gnulib.mk index bec0d3bb19b..95f2f8b48a6 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=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings | 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=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings |
| 25 | 25 | ||
| 26 | 26 | ||
| 27 | MOSTLYCLEANFILES += core *.stackdump | 27 | MOSTLYCLEANFILES += core *.stackdump |
| @@ -42,6 +42,17 @@ HAVE_INCLUDE_NEXT = (__GNUC__ || 60000000 <= __DECC_VER) | |||
| 42 | 42 | ||
| 43 | ## end gnulib module absolute-header | 43 | ## end gnulib module absolute-header |
| 44 | 44 | ||
| 45 | ## begin gnulib module acl-permissions | ||
| 46 | |||
| 47 | libgnu_a_SOURCES += acl-errno-valid.c acl-internal.c \ | ||
| 48 | get-permissions.c set-permissions.c | ||
| 49 | |||
| 50 | EXTRA_DIST += acl-internal.h acl.h acl_entries.c | ||
| 51 | |||
| 52 | EXTRA_libgnu_a_SOURCES += acl_entries.c | ||
| 53 | |||
| 54 | ## end gnulib module acl-permissions | ||
| 55 | |||
| 45 | ## begin gnulib module alloca-opt | 56 | ## begin gnulib module alloca-opt |
| 46 | 57 | ||
| 47 | BUILT_SOURCES += $(ALLOCA_H) | 58 | BUILT_SOURCES += $(ALLOCA_H) |
| @@ -696,15 +707,11 @@ EXTRA_libgnu_a_SOURCES += putenv.c | |||
| 696 | 707 | ||
| 697 | ## end gnulib module putenv | 708 | ## end gnulib module putenv |
| 698 | 709 | ||
| 699 | ## begin gnulib module qacl | 710 | ## begin gnulib module qcopy-acl |
| 700 | |||
| 701 | libgnu_a_SOURCES += acl-errno-valid.c acl-internal.c qcopy-acl.c qset-acl.c | ||
| 702 | 711 | ||
| 703 | EXTRA_DIST += acl-internal.h acl.h acl_entries.c | 712 | libgnu_a_SOURCES += qcopy-acl.c |
| 704 | |||
| 705 | EXTRA_libgnu_a_SOURCES += acl_entries.c | ||
| 706 | 713 | ||
| 707 | ## end gnulib module qacl | 714 | ## end gnulib module qcopy-acl |
| 708 | 715 | ||
| 709 | ## begin gnulib module readlink | 716 | ## begin gnulib module readlink |
| 710 | 717 | ||
diff --git a/lib/inttypes.in.h b/lib/inttypes.in.h index 13a72bee90c..78846f69683 100644 --- a/lib/inttypes.in.h +++ b/lib/inttypes.in.h | |||
| @@ -51,6 +51,10 @@ | |||
| 51 | #endif | 51 | #endif |
| 52 | /* Get CHAR_BIT. */ | 52 | /* Get CHAR_BIT. */ |
| 53 | #include <limits.h> | 53 | #include <limits.h> |
| 54 | /* On mingw, __USE_MINGW_ANSI_STDIO only works if <stdio.h> is also included */ | ||
| 55 | #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ | ||
| 56 | # include <stdio.h> | ||
| 57 | #endif | ||
| 54 | 58 | ||
| 55 | #if !(INT_MIN == INT32_MIN && INT_MAX == INT32_MAX) | 59 | #if !(INT_MIN == INT32_MIN && INT_MAX == INT32_MAX) |
| 56 | # error "This file assumes that 'int' has exactly 32 bits. Please report your platform and compiler to <bug-gnulib@gnu.org>." | 60 | # error "This file assumes that 'int' has exactly 32 bits. Please report your platform and compiler to <bug-gnulib@gnu.org>." |
diff --git a/lib/qcopy-acl.c b/lib/qcopy-acl.c index bc258ba560b..c4507424719 100644 --- a/lib/qcopy-acl.c +++ b/lib/qcopy-acl.c | |||
| @@ -39,534 +39,13 @@ int | |||
| 39 | qcopy_acl (const char *src_name, int source_desc, const char *dst_name, | 39 | qcopy_acl (const char *src_name, int source_desc, const char *dst_name, |
| 40 | int dest_desc, mode_t mode) | 40 | int dest_desc, mode_t mode) |
| 41 | { | 41 | { |
| 42 | #if USE_ACL && HAVE_ACL_GET_FILE | 42 | struct permission_context ctx; |
| 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; | 43 | int ret; |
| 133 | 44 | ||
| 134 | if (HAVE_ACL_GET_FD && source_desc != -1) | 45 | ret = get_permissions (src_name, source_desc, mode, &ctx); |
| 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) | 46 | 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 | && !acl_nontrivial (count, entries)) | ||
| 442 | saved_errno = 0; | ||
| 443 | } | ||
| 444 | else | ||
| 445 | did_chmod = 1; | ||
| 446 | } | ||
| 447 | |||
| 448 | # if HAVE_ACLV_H | ||
| 449 | if (aclv_count > 0) | ||
| 450 | { | ||
| 451 | ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries); | ||
| 452 | if (ret < 0 && saved_errno == 0) | ||
| 453 | { | ||
| 454 | saved_errno = errno; | ||
| 455 | if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) | ||
| 456 | { | ||
| 457 | if (!aclv_nontrivial (aclv_count, aclv_entries)) | ||
| 458 | saved_errno = 0; | ||
| 459 | } | ||
| 460 | } | ||
| 461 | else | ||
| 462 | did_chmod = 1; | ||
| 463 | } | ||
| 464 | # endif | ||
| 465 | |||
| 466 | if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0)) | ||
| 467 | { | ||
| 468 | /* We did not call chmod so far, and special bits are to be set which | ||
| 469 | don't fit into ACLs. */ | ||
| 470 | |||
| 471 | if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) | ||
| 472 | { | ||
| 473 | if (saved_errno == 0) | ||
| 474 | saved_errno = errno; | ||
| 475 | } | ||
| 476 | } | ||
| 477 | |||
| 478 | if (saved_errno) | ||
| 479 | { | ||
| 480 | errno = saved_errno; | ||
| 481 | return -1; | ||
| 482 | } | ||
| 483 | return 0; | ||
| 484 | |||
| 485 | #elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */ | ||
| 486 | |||
| 487 | /* TODO */ | ||
| 488 | |||
| 489 | #elif USE_ACL && HAVE_STATACL /* older AIX */ | ||
| 490 | |||
| 491 | union { struct acl a; char room[4096]; } u; | ||
| 492 | int ret; | ||
| 493 | |||
| 494 | if ((source_desc != -1 | ||
| 495 | ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u)) | ||
| 496 | : statacl (src_name, STX_NORMAL, &u.a, sizeof (u))) | ||
| 497 | < 0) | ||
| 498 | return -2; | 47 | return -2; |
| 499 | 48 | ret = set_permissions (&ctx, dst_name, dest_desc); | |
| 500 | ret = (dest_desc != -1 | 49 | free_permission_context (&ctx); |
| 501 | ? fchacl (dest_desc, &u.a, u.a.acl_len) | 50 | return ret; |
| 502 | : chacl (dst_name, &u.a, u.a.acl_len)); | ||
| 503 | if (ret < 0) | ||
| 504 | { | ||
| 505 | int saved_errno = errno; | ||
| 506 | |||
| 507 | chmod_or_fchmod (dst_name, dest_desc, mode); | ||
| 508 | errno = saved_errno; | ||
| 509 | return -1; | ||
| 510 | } | ||
| 511 | |||
| 512 | /* No need to call chmod_or_fchmod at this point, since the mode bits | ||
| 513 | S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */ | ||
| 514 | |||
| 515 | return 0; | ||
| 516 | |||
| 517 | #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */ | ||
| 518 | |||
| 519 | struct acl entries[NACLENTRIES]; | ||
| 520 | int count; | ||
| 521 | int ret; | ||
| 522 | |||
| 523 | count = acl ((char *) src_name, ACL_GET, NACLENTRIES, entries); | ||
| 524 | |||
| 525 | if (count < 0) | ||
| 526 | { | ||
| 527 | if (0) | ||
| 528 | count = 0; | ||
| 529 | else | ||
| 530 | return -2; | ||
| 531 | } | ||
| 532 | else if (count > 0) | ||
| 533 | { | ||
| 534 | if (count > NACLENTRIES) | ||
| 535 | /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ | ||
| 536 | abort (); | ||
| 537 | } | ||
| 538 | |||
| 539 | if (count == 0) | ||
| 540 | return qset_acl (dst_name, dest_desc, mode); | ||
| 541 | |||
| 542 | ret = acl ((char *) dst_name, ACL_SET, count, entries); | ||
| 543 | if (ret < 0) | ||
| 544 | { | ||
| 545 | int saved_errno = errno; | ||
| 546 | |||
| 547 | if (0) | ||
| 548 | { | ||
| 549 | if (!acl_nontrivial (count, entries)) | ||
| 550 | return chmod_or_fchmod (dst_name, dest_desc, mode); | ||
| 551 | } | ||
| 552 | |||
| 553 | chmod_or_fchmod (dst_name, dest_desc, mode); | ||
| 554 | errno = saved_errno; | ||
| 555 | return -1; | ||
| 556 | } | ||
| 557 | |||
| 558 | if (mode & (S_ISUID | S_ISGID | S_ISVTX)) | ||
| 559 | { | ||
| 560 | /* We did not call chmod so far, and either the mode and the ACL are | ||
| 561 | separate or special bits are to be set which don't fit into ACLs. */ | ||
| 562 | |||
| 563 | return chmod_or_fchmod (dst_name, dest_desc, mode); | ||
| 564 | } | ||
| 565 | return 0; | ||
| 566 | |||
| 567 | #else | ||
| 568 | |||
| 569 | return qset_acl (dst_name, dest_desc, mode); | ||
| 570 | |||
| 571 | #endif | ||
| 572 | } | 51 | } |
diff --git a/lib/qset-acl.c b/lib/set-permissions.c index bb4b0b261a9..47cb91ca162 100644 --- a/lib/qset-acl.c +++ b/lib/set-permissions.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* qset-acl.c - set access control list equivalent to a mode | 1 | /* set-permissions.c - set permissions of a file |
| 2 | 2 | ||
| 3 | Copyright (C) 2002-2003, 2005-2015 Free Software Foundation, Inc. | 3 | Copyright (C) 2002-2003, 2005-2015 Free Software Foundation, Inc. |
| 4 | 4 | ||
| @@ -15,182 +15,43 @@ | |||
| 15 | You should have received a copy of the GNU General Public License | 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/>. | 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 17 | 17 | ||
| 18 | Written by Paul Eggert and Andreas Gruenbacher, and Bruno Haible. */ | 18 | Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */ |
| 19 | 19 | ||
| 20 | #include <config.h> | 20 | #include <config.h> |
| 21 | 21 | ||
| 22 | #define ACL_INTERNAL_INLINE _GL_EXTERN_INLINE | ||
| 23 | |||
| 24 | #include "acl.h" | 22 | #include "acl.h" |
| 25 | 23 | ||
| 26 | #include "acl-internal.h" | 24 | #include "acl-internal.h" |
| 27 | 25 | ||
| 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 | |||
| 35 | int | ||
| 36 | chmod_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 | |||
| 52 | int | ||
| 53 | qset_acl (char const *name, int desc, mode_t mode) | ||
| 54 | { | ||
| 55 | #if USE_ACL | 26 | #if USE_ACL |
| 56 | # if HAVE_ACL_GET_FILE | 27 | # if ! defined HAVE_ACL_FROM_MODE && defined HAVE_ACL_FROM_TEXT /* FreeBSD, IRIX, Tru64 */ |
| 57 | /* POSIX 1003.1e draft 17 (abandoned) specific version. */ | 28 | static acl_t |
| 58 | /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ | 29 | acl_from_mode (mode_t mode) |
| 59 | # if !HAVE_ACL_TYPE_EXTENDED | 30 | { |
| 60 | /* Linux, FreeBSD, IRIX, Tru64 */ | 31 | # if HAVE_ACL_FREE_TEXT /* Tru64 */ |
| 61 | 32 | char acl_text[] = "u::---,g::---,o::---,"; | |
| 62 | /* We must also have acl_from_text and acl_delete_def_file. | 33 | # else /* FreeBSD, IRIX */ |
| 63 | (acl_delete_def_file could be emulated with acl_init followed | 34 | char acl_text[] = "u::---,g::---,o::---"; |
| 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 | 35 | # endif |
| 189 | 36 | ||
| 190 | # elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ | 37 | if (mode & S_IRUSR) acl_text[ 3] = 'r'; |
| 191 | 38 | if (mode & S_IWUSR) acl_text[ 4] = 'w'; | |
| 192 | int done_setacl = 0; | 39 | if (mode & S_IXUSR) acl_text[ 5] = 'x'; |
| 40 | if (mode & S_IRGRP) acl_text[10] = 'r'; | ||
| 41 | if (mode & S_IWGRP) acl_text[11] = 'w'; | ||
| 42 | if (mode & S_IXGRP) acl_text[12] = 'x'; | ||
| 43 | if (mode & S_IROTH) acl_text[17] = 'r'; | ||
| 44 | if (mode & S_IWOTH) acl_text[18] = 'w'; | ||
| 45 | if (mode & S_IXOTH) acl_text[19] = 'x'; | ||
| 46 | |||
| 47 | return acl_from_text (acl_text); | ||
| 48 | } | ||
| 49 | # endif | ||
| 193 | 50 | ||
| 51 | # if HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ | ||
| 52 | static int | ||
| 53 | set_acls_from_mode (const char *name, int desc, mode_t mode, bool *must_chmod) | ||
| 54 | { | ||
| 194 | # ifdef ACE_GETACL | 55 | # ifdef ACE_GETACL |
| 195 | /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 | 56 | /* 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). */ | 57 | file systems (whereas the other ones are used in UFS file systems). */ |
| @@ -365,53 +226,53 @@ qset_acl (char const *name, int desc, mode_t mode) | |||
| 365 | if (ret < 0 && errno != EINVAL && errno != ENOTSUP) | 226 | if (ret < 0 && errno != EINVAL && errno != ENOTSUP) |
| 366 | { | 227 | { |
| 367 | if (errno == ENOSYS) | 228 | if (errno == ENOSYS) |
| 368 | return chmod_or_fchmod (name, desc, mode); | 229 | { |
| 230 | *must_chmod = true; | ||
| 231 | return 0; | ||
| 232 | } | ||
| 369 | return -1; | 233 | return -1; |
| 370 | } | 234 | } |
| 371 | if (ret == 0) | 235 | if (ret == 0) |
| 372 | done_setacl = 1; | 236 | return 0; |
| 373 | } | 237 | } |
| 374 | # endif | 238 | # endif |
| 375 | 239 | ||
| 376 | if (!done_setacl) | 240 | { |
| 377 | { | 241 | aclent_t entries[3]; |
| 378 | aclent_t entries[3]; | 242 | int ret; |
| 379 | int ret; | 243 | |
| 380 | 244 | entries[0].a_type = USER_OBJ; | |
| 381 | entries[0].a_type = USER_OBJ; | 245 | entries[0].a_id = 0; /* irrelevant */ |
| 382 | entries[0].a_id = 0; /* irrelevant */ | 246 | entries[0].a_perm = (mode >> 6) & 7; |
| 383 | entries[0].a_perm = (mode >> 6) & 7; | 247 | entries[1].a_type = GROUP_OBJ; |
| 384 | entries[1].a_type = GROUP_OBJ; | 248 | entries[1].a_id = 0; /* irrelevant */ |
| 385 | entries[1].a_id = 0; /* irrelevant */ | 249 | entries[1].a_perm = (mode >> 3) & 7; |
| 386 | entries[1].a_perm = (mode >> 3) & 7; | 250 | entries[2].a_type = OTHER_OBJ; |
| 387 | entries[2].a_type = OTHER_OBJ; | 251 | entries[2].a_id = 0; |
| 388 | entries[2].a_id = 0; | 252 | entries[2].a_perm = mode & 7; |
| 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 | 253 | ||
| 413 | # elif HAVE_GETACL /* HP-UX */ | 254 | if (desc != -1) |
| 255 | ret = facl (desc, SETACL, | ||
| 256 | sizeof (entries) / sizeof (aclent_t), entries); | ||
| 257 | else | ||
| 258 | ret = acl (name, SETACL, | ||
| 259 | sizeof (entries) / sizeof (aclent_t), entries); | ||
| 260 | if (ret < 0) | ||
| 261 | { | ||
| 262 | if (errno == ENOSYS || errno == EOPNOTSUPP) | ||
| 263 | { | ||
| 264 | *must_chmod = true; | ||
| 265 | return 0; | ||
| 266 | } | ||
| 267 | return -1; | ||
| 268 | } | ||
| 269 | } | ||
| 270 | } | ||
| 414 | 271 | ||
| 272 | #elif HAVE_GETACL /* HP-UX */ | ||
| 273 | static int | ||
| 274 | context_acl_from_mode (struct permission_context *ctx, const char *name, int desc) | ||
| 275 | { | ||
| 415 | struct stat statbuf; | 276 | struct stat statbuf; |
| 416 | int ret; | 277 | int ret; |
| 417 | 278 | ||
| @@ -422,87 +283,60 @@ qset_acl (char const *name, int desc, mode_t mode) | |||
| 422 | if (ret < 0) | 283 | if (ret < 0) |
| 423 | return -1; | 284 | return -1; |
| 424 | 285 | ||
| 425 | { | 286 | ctx->entries[0].uid = statbuf.st_uid; |
| 426 | struct acl_entry entries[3]; | 287 | ctx->entries[0].gid = ACL_NSGROUP; |
| 427 | 288 | ctx->entries[0].mode = (mode >> 6) & 7; | |
| 428 | entries[0].uid = statbuf.st_uid; | 289 | ctx->entries[1].uid = ACL_NSUSER; |
| 429 | entries[0].gid = ACL_NSGROUP; | 290 | ctx->entries[1].gid = statbuf.st_gid; |
| 430 | entries[0].mode = (mode >> 6) & 7; | 291 | ctx->entries[1].mode = (mode >> 3) & 7; |
| 431 | entries[1].uid = ACL_NSUSER; | 292 | ctx->entries[2].uid = ACL_NSUSER; |
| 432 | entries[1].gid = statbuf.st_gid; | 293 | ctx->entries[2].gid = ACL_NSGROUP; |
| 433 | entries[1].mode = (mode >> 3) & 7; | 294 | ctx->entries[2].mode = mode & 7; |
| 434 | entries[2].uid = ACL_NSUSER; | 295 | ctx->count = 3; |
| 435 | entries[2].gid = ACL_NSGROUP; | 296 | return 0; |
| 436 | entries[2].mode = mode & 7; | 297 | } |
| 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 | 298 | ||
| 448 | # if HAVE_ACLV_H /* HP-UX >= 11.11 */ | 299 | # if HAVE_ACLV_H /* HP-UX >= 11.11 */ |
| 449 | { | 300 | static int |
| 450 | struct acl entries[4]; | 301 | context_aclv_from_mode (struct permission_context *ctx) |
| 451 | 302 | { | |
| 452 | entries[0].a_type = USER_OBJ; | 303 | int ret; |
| 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 | 304 | ||
| 475 | ret = acl ((char *) name, ACL_SET, | 305 | ctx->aclv_entries[0].a_type = USER_OBJ; |
| 476 | sizeof (entries) / sizeof (struct acl), entries); | 306 | ctx->aclv_entries[0].a_id = 0; /* irrelevant */ |
| 477 | if (ret < 0) | 307 | ctx->aclv_entries[0].a_perm = (mode >> 6) & 7; |
| 478 | { | 308 | ctx->aclv_entries[1].a_type = GROUP_OBJ; |
| 479 | if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) | 309 | ctx->aclv_entries[1].a_id = 0; /* irrelevant */ |
| 480 | return chmod_or_fchmod (name, desc, mode); | 310 | ctx->aclv_entries[1].a_perm = (mode >> 3) & 7; |
| 481 | return -1; | 311 | ctx->aclv_entries[2].a_type = CLASS_OBJ; |
| 482 | } | 312 | ctx->aclv_entries[2].a_id = 0; |
| 483 | } | 313 | ctx->aclv_entries[2].a_perm = (mode >> 3) & 7; |
| 484 | # else | 314 | ctx->aclv_entries[3].a_type = OTHER_OBJ; |
| 485 | return chmod_or_fchmod (name, desc, mode); | 315 | ctx->aclv_entries[3].a_id = 0; |
| 486 | # endif | 316 | ctx->aclv_entries[3].a_perm = mode & 7; |
| 487 | } | 317 | ctx->aclv_count = 4; |
| 488 | 318 | ||
| 489 | if (mode & (S_ISUID | S_ISGID | S_ISVTX)) | 319 | ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries); |
| 490 | { | 320 | if (ret > 0) |
| 491 | /* We did not call chmod so far, so the special bits have not yet | 321 | abort (); |
| 492 | been set. */ | 322 | return ret; |
| 493 | return chmod_or_fchmod (name, desc, mode); | 323 | } |
| 494 | } | 324 | #endif |
| 495 | return 0; | ||
| 496 | 325 | ||
| 497 | # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */ | 326 | # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */ |
| 498 | 327 | static int | |
| 328 | set_acls_from_mode (const char *name, int desc, mode_t mode, bool *must_chmod) | ||
| 329 | { | ||
| 499 | acl_type_list_t types; | 330 | acl_type_list_t types; |
| 500 | size_t types_size = sizeof (types); | 331 | size_t types_size = sizeof (types); |
| 501 | acl_type_t type; | 332 | acl_type_t type; |
| 502 | 333 | ||
| 503 | if (aclx_gettypes (name, &types, &types_size) < 0 | 334 | if (aclx_gettypes (name, &types, &types_size) < 0 |
| 504 | || types.num_entries == 0) | 335 | || types.num_entries == 0) |
| 505 | return chmod_or_fchmod (name, desc, mode); | 336 | { |
| 337 | *must_chmod = true; | ||
| 338 | return 0; | ||
| 339 | } | ||
| 506 | 340 | ||
| 507 | /* XXX Do we need to clear all types of ACLs for the given file, or is it | 341 | /* XXX Do we need to clear all types of ACLs for the given file, or is it |
| 508 | sufficient to clear the first one? */ | 342 | sufficient to clear the first one? */ |
| @@ -599,78 +433,401 @@ qset_acl (char const *name, int desc, mode_t mode) | |||
| 599 | return ret; | 433 | return ret; |
| 600 | } | 434 | } |
| 601 | 435 | ||
| 602 | return chmod_or_fchmod (name, desc, mode); | 436 | *must_chmod = true; |
| 437 | return 0; | ||
| 438 | } | ||
| 603 | 439 | ||
| 604 | # elif HAVE_STATACL /* older AIX */ | 440 | # elif HAVE_STATACL /* older AIX */ |
| 441 | static int | ||
| 442 | context_acl_from_mode (struct permission_context *ctx) | ||
| 443 | { | ||
| 444 | ctx->u.a.acl_len = (char *) &ctx->u.a.acl_ext[0] - (char *) &ctx->u.a; /* no entries */ | ||
| 445 | ctx->u.a.acl_mode = ctx->mode & ~(S_IXACL | 0777); | ||
| 446 | ctx->u.a.u_access = (ctx->mode >> 6) & 7; | ||
| 447 | ctx->u.a.g_access = (ctx->mode >> 3) & 7; | ||
| 448 | ctx->u.a.o_access = ctx->mode & 7; | ||
| 449 | ctx->have_u = true; | ||
| 450 | return 0; | ||
| 451 | } | ||
| 605 | 452 | ||
| 606 | union { struct acl a; char room[128]; } u; | 453 | # elif HAVE_ACLSORT /* NonStop Kernel */ |
| 454 | static int | ||
| 455 | context_acl_from_mode (struct permission_context *ctx) | ||
| 456 | { | ||
| 607 | int ret; | 457 | int ret; |
| 608 | 458 | ||
| 609 | u.a.acl_len = (char *) &u.a.acl_ext[0] - (char *) &u.a; /* no entries */ | 459 | ctx->entries[0].a_type = USER_OBJ; |
| 610 | u.a.acl_mode = mode & ~(S_IXACL | 0777); | 460 | ctx->entries[0].a_id = 0; /* irrelevant */ |
| 611 | u.a.u_access = (mode >> 6) & 7; | 461 | ctx->entries[0].a_perm = (mode >> 6) & 7; |
| 612 | u.a.g_access = (mode >> 3) & 7; | 462 | ctx->entries[1].a_type = GROUP_OBJ; |
| 613 | u.a.o_access = mode & 7; | 463 | ctx->entries[1].a_id = 0; /* irrelevant */ |
| 464 | ctx->entries[1].a_perm = (mode >> 3) & 7; | ||
| 465 | ctx->entries[2].a_type = CLASS_OBJ; | ||
| 466 | ctx->entries[2].a_id = 0; | ||
| 467 | ctx->entries[2].a_perm = (mode >> 3) & 7; | ||
| 468 | ctx->entries[3].a_type = OTHER_OBJ; | ||
| 469 | ctx->entries[3].a_id = 0; | ||
| 470 | ctx->entries[3].a_perm = mode & 7; | ||
| 471 | ctx->count = 4; | ||
| 614 | 472 | ||
| 615 | if (desc != -1) | 473 | ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries); |
| 616 | ret = fchacl (desc, &u.a, u.a.acl_len); | 474 | if (ret > 0) |
| 475 | abort (); | ||
| 476 | return ret; | ||
| 477 | } | ||
| 478 | # endif | ||
| 479 | |||
| 480 | static int | ||
| 481 | set_acls (struct permission_context *ctx, const char *name, int desc, | ||
| 482 | int from_mode, bool *must_chmod, bool *acls_set) | ||
| 483 | { | ||
| 484 | int ret = 0; | ||
| 485 | |||
| 486 | #if HAVE_ACL_GET_FILE | ||
| 487 | /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ | ||
| 488 | /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ | ||
| 489 | # if !HAVE_ACL_TYPE_EXTENDED | ||
| 490 | /* Linux, FreeBSD, IRIX, Tru64 */ | ||
| 491 | |||
| 492 | # ifndef HAVE_ACL_FROM_TEXT | ||
| 493 | # error Must have acl_from_text (see POSIX 1003.1e draft 17). | ||
| 494 | # endif | ||
| 495 | # ifndef HAVE_ACL_DELETE_DEF_FILE | ||
| 496 | # error Must have acl_delete_def_file (see POSIX 1003.1e draft 17). | ||
| 497 | # endif | ||
| 498 | |||
| 499 | if (! ctx->acls_not_supported) | ||
| 500 | { | ||
| 501 | if (ret == 0 && from_mode) | ||
| 502 | { | ||
| 503 | if (ctx->acl) | ||
| 504 | acl_free (ctx->acl); | ||
| 505 | ctx->acl = acl_from_mode (ctx->mode); | ||
| 506 | if (ctx->acl == NULL) | ||
| 507 | ret = -1; | ||
| 508 | } | ||
| 509 | |||
| 510 | if (ret == 0 && ctx->acl) | ||
| 511 | { | ||
| 512 | if (HAVE_ACL_SET_FD && desc != -1) | ||
| 513 | ret = acl_set_fd (desc, ctx->acl); | ||
| 514 | else | ||
| 515 | ret = acl_set_file (name, ACL_TYPE_ACCESS, ctx->acl); | ||
| 516 | if (ret != 0) | ||
| 517 | { | ||
| 518 | if (! acl_errno_valid (errno)) | ||
| 519 | { | ||
| 520 | ctx->acls_not_supported = true; | ||
| 521 | if (from_mode || acl_access_nontrivial (ctx->acl) == 0) | ||
| 522 | ret = 0; | ||
| 523 | } | ||
| 524 | } | ||
| 525 | else | ||
| 526 | { | ||
| 527 | *acls_set = true; | ||
| 528 | if (S_ISDIR(ctx->mode)) | ||
| 529 | { | ||
| 530 | if (! from_mode && ctx->default_acl) | ||
| 531 | ret = acl_set_file (name, ACL_TYPE_DEFAULT, | ||
| 532 | ctx->default_acl); | ||
| 533 | else | ||
| 534 | ret = acl_delete_def_file (name); | ||
| 535 | } | ||
| 536 | } | ||
| 537 | } | ||
| 538 | } | ||
| 539 | |||
| 540 | # else /* HAVE_ACL_TYPE_EXTENDED */ | ||
| 541 | /* Mac OS X */ | ||
| 542 | |||
| 543 | /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS) | ||
| 544 | and acl_get_file (name, ACL_TYPE_DEFAULT) | ||
| 545 | always return NULL / EINVAL. You have to use | ||
| 546 | acl_get_file (name, ACL_TYPE_EXTENDED) | ||
| 547 | or acl_get_fd (open (name, ...)) | ||
| 548 | to retrieve an ACL. | ||
| 549 | On the other hand, | ||
| 550 | acl_set_file (name, ACL_TYPE_ACCESS, acl) | ||
| 551 | and acl_set_file (name, ACL_TYPE_DEFAULT, acl) | ||
| 552 | have the same effect as | ||
| 553 | acl_set_file (name, ACL_TYPE_EXTENDED, acl): | ||
| 554 | Each of these calls sets the file's ACL. */ | ||
| 555 | |||
| 556 | if (ctx->acl == NULL) | ||
| 557 | { | ||
| 558 | acl_t acl; | ||
| 559 | |||
| 560 | /* Remove ACLs if the file has ACLs. */ | ||
| 561 | if (HAVE_ACL_GET_FD && desc != -1) | ||
| 562 | acl = acl_get_fd (desc); | ||
| 563 | else | ||
| 564 | acl = acl_get_file (name, ACL_TYPE_EXTENDED); | ||
| 565 | if (acl) | ||
| 566 | { | ||
| 567 | acl_free (acl); | ||
| 568 | |||
| 569 | acl = acl_init (acl); | ||
| 570 | if (acl) | ||
| 571 | { | ||
| 572 | if (HAVE_ACL_SET_FD && desc != -1) | ||
| 573 | ret = acl_set_fd (desc, acl); | ||
| 574 | else | ||
| 575 | ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl); | ||
| 576 | acl_free (acl); | ||
| 577 | } | ||
| 578 | else | ||
| 579 | ret = -1; | ||
| 580 | } | ||
| 581 | } | ||
| 617 | else | 582 | else |
| 618 | ret = chacl (name, &u.a, u.a.acl_len); | 583 | { |
| 584 | if (HAVE_ACL_SET_FD && desc != -1) | ||
| 585 | ret = acl_set_fd (desc, acl); | ||
| 586 | else | ||
| 587 | ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl); | ||
| 588 | if (ret != 0) | ||
| 589 | { | ||
| 590 | if (! acl_errno_valid (saved_errno) && ! acl_extended_nontrivial (acl)) | ||
| 591 | ret = 0; | ||
| 592 | } | ||
| 593 | } | ||
| 594 | *acls_set = true; | ||
| 619 | 595 | ||
| 620 | if (ret < 0 && errno == ENOSYS) | 596 | # endif |
| 621 | return chmod_or_fchmod (name, desc, mode); | ||
| 622 | 597 | ||
| 623 | return ret; | 598 | # elif defined GETACL /* Solaris, Cygwin, not HP-UX */ |
| 624 | 599 | ||
| 625 | # elif HAVE_ACLSORT /* NonStop Kernel */ | 600 | /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions |
| 601 | of Unixware. The acl() call returns the access and default ACL both | ||
| 602 | at once. */ | ||
| 626 | 603 | ||
| 627 | struct acl entries[4]; | 604 | /* If both ace_entries and entries are available, try SETACL before |
| 628 | int ret; | 605 | ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL |
| 606 | can. */ | ||
| 629 | 607 | ||
| 630 | entries[0].a_type = USER_OBJ; | 608 | if (from_mode) |
| 631 | entries[0].a_id = 0; /* irrelevant */ | 609 | return set_acls_from_mode (name, desc, ctx->mode, must_chmod); |
| 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 | 610 | ||
| 643 | ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries); | 611 | if (ret == 0 && ctx->count) |
| 644 | if (ret > 0) | ||
| 645 | abort (); | ||
| 646 | if (ret < 0) | ||
| 647 | { | 612 | { |
| 648 | if (0) | 613 | if (desc != -1) |
| 649 | return chmod_or_fchmod (name, desc, mode); | 614 | ret = facl (desc, SETACL, count, entries); |
| 650 | return -1; | 615 | else |
| 616 | ret = acl (name, SETACL, count, entries); | ||
| 617 | if (ret < 0) | ||
| 618 | { | ||
| 619 | if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) | ||
| 620 | && acl_nontrivial (count, entries) == 0) | ||
| 621 | ret = 0; | ||
| 622 | } | ||
| 623 | else | ||
| 624 | *acls_set = true; | ||
| 651 | } | 625 | } |
| 652 | 626 | ||
| 653 | ret = acl ((char *) name, ACL_SET, | 627 | # ifdef ACE_GETACL |
| 654 | sizeof (entries) / sizeof (struct acl), entries); | 628 | if (ret == 0 && ctx->ace_count) |
| 655 | if (ret < 0) | ||
| 656 | { | 629 | { |
| 657 | if (0) | 630 | if (desc != -1) |
| 658 | return chmod_or_fchmod (name, desc, mode); | 631 | ret = facl (desc, ACE_SETACL, ace_count, ace_entries); |
| 659 | return -1; | 632 | else |
| 633 | ret = acl (name, ACE_SETACL, ace_count, ace_entries); | ||
| 634 | if (ret < 0) | ||
| 635 | { | ||
| 636 | if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP) | ||
| 637 | && acl_ace_nontrivial (ace_count, ace_entries) == 0) | ||
| 638 | ret = 0; | ||
| 639 | } | ||
| 640 | else | ||
| 641 | *acls_set = true; | ||
| 660 | } | 642 | } |
| 643 | # endif | ||
| 644 | |||
| 645 | #elif HAVE_GETACL /* HP-UX */ | ||
| 661 | 646 | ||
| 662 | if (mode & (S_ISUID | S_ISGID | S_ISVTX)) | 647 | if (from_mode) |
| 648 | ret = context_acl_from_mode (ctx, name, desc); | ||
| 649 | |||
| 650 | if (ret == 0 && ctx->count > 0) | ||
| 663 | { | 651 | { |
| 664 | /* We did not call chmod so far, so the special bits have not yet | 652 | if (desc != -1) |
| 665 | been set. */ | 653 | ret = fsetacl (desc, ctx->count, ctx->entries); |
| 666 | return chmod_or_fchmod (name, desc, mode); | 654 | else |
| 655 | ret = setacl (name, ctx->count, ctx->entries); | ||
| 656 | if (ret < 0) | ||
| 657 | { | ||
| 658 | if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) | ||
| 659 | && (from_mode || !acl_nontrivial (ctx->count, ctx->entries, &source_statbuf))) | ||
| 660 | ret = 0; | ||
| 661 | } | ||
| 662 | else | ||
| 663 | *acls_set = true; | ||
| 667 | } | 664 | } |
| 668 | return 0; | ||
| 669 | 665 | ||
| 670 | # else /* Unknown flavor of ACLs */ | 666 | # if HAVE_ACLV_H |
| 671 | return chmod_or_fchmod (name, desc, mode); | 667 | if (from_mode) |
| 668 | ret = context_aclv_from_mode (ctx); | ||
| 669 | |||
| 670 | if (ret == 0 && ctx->aclv_count > 0) | ||
| 671 | { | ||
| 672 | ret = acl ((char *) name, ACL_SET, ctx->aclv_count, ctx->aclv_entries); | ||
| 673 | if (ret < 0) | ||
| 674 | { | ||
| 675 | if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) | ||
| 676 | && (from_mode || !aclv_nontrivial (ctx->aclv_count, ctx->aclv_entries))) | ||
| 677 | ret = 0; | ||
| 678 | } | ||
| 679 | else | ||
| 680 | *acls_set = true; | ||
| 681 | } | ||
| 682 | # endif | ||
| 683 | |||
| 684 | # elif HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */ | ||
| 685 | |||
| 686 | /* TODO: Implement setting ACLs once get_permissions() reads them. */ | ||
| 687 | |||
| 688 | if (from_mode) | ||
| 689 | ret = set_acls_from_mode (name, desc, mode, must_chmod); | ||
| 690 | |||
| 691 | # elif HAVE_STATACL /* older AIX */ | ||
| 692 | |||
| 693 | if (from_mode) | ||
| 694 | ret = context_acl_from_mode (ctx); | ||
| 695 | |||
| 696 | if (ret == 0 && ctx->have_u) | ||
| 697 | { | ||
| 698 | if (desc != -1) | ||
| 699 | ret = fchacl (desc, &u.a, u.a.acl_len); | ||
| 700 | else | ||
| 701 | ret = chacl (name, &u.a, u.a.acl_len); | ||
| 702 | if (ret < 0) | ||
| 703 | { | ||
| 704 | if (errno == ENOSYS && from_mode) | ||
| 705 | ret = 0; | ||
| 706 | } | ||
| 707 | else | ||
| 708 | *acls_set = true; | ||
| 709 | } | ||
| 710 | |||
| 711 | # elif HAVE_ACLSORT /* NonStop Kernel */ | ||
| 712 | |||
| 713 | if (from_mode) | ||
| 714 | ret = context_acl_from_mode (ctx); | ||
| 715 | |||
| 716 | if (ret == 0 && ctx->count) | ||
| 717 | { | ||
| 718 | ret = acl ((char *) name, ACL_SET, ctx->count, ctx->entries); | ||
| 719 | if (ret != 0) | ||
| 720 | { | ||
| 721 | if (!acl_nontrivial (ctx->count, ctx->entries)) | ||
| 722 | ret = 0; | ||
| 723 | } | ||
| 724 | else | ||
| 725 | *acls_set = true; | ||
| 726 | } | ||
| 727 | |||
| 728 | # else /* No ACLs */ | ||
| 729 | |||
| 730 | /* Nothing to do. */ | ||
| 731 | |||
| 732 | #endif | ||
| 733 | |||
| 734 | return ret; | ||
| 735 | } | ||
| 736 | #endif | ||
| 737 | |||
| 738 | /* If DESC is a valid file descriptor use fchmod to change the | ||
| 739 | file's mode to MODE on systems that have fchmod. On systems | ||
| 740 | that don't have fchmod and if DESC is invalid, use chmod on | ||
| 741 | NAME instead. | ||
| 742 | Return 0 if successful. Return -1 and set errno upon failure. */ | ||
| 743 | |||
| 744 | int | ||
| 745 | chmod_or_fchmod (const char *name, int desc, mode_t mode) | ||
| 746 | { | ||
| 747 | if (HAVE_FCHMOD && desc != -1) | ||
| 748 | return fchmod (desc, mode); | ||
| 749 | else | ||
| 750 | return chmod (name, mode); | ||
| 751 | } | ||
| 752 | |||
| 753 | /* Set the permissions in CTX on a file. If DESC is a valid file descriptor, | ||
| 754 | use file descriptor operations, else use filename based operations on NAME. | ||
| 755 | If access control lists are not available, fchmod the target file to the | ||
| 756 | mode in CTX. Also sets the non-permission bits of the destination file | ||
| 757 | (S_ISUID, S_ISGID, S_ISVTX) to those from the mode in CTX if any are set. | ||
| 758 | Return 0 if successful. Return -1 and set errno upon failure. */ | ||
| 759 | |||
| 760 | int | ||
| 761 | set_permissions (struct permission_context *ctx, const char *name, int desc) | ||
| 762 | { | ||
| 763 | bool acls_set _GL_UNUSED = false; | ||
| 764 | bool early_chmod; | ||
| 765 | bool must_chmod = false; | ||
| 766 | int ret = 0; | ||
| 767 | |||
| 768 | #if USE_ACL | ||
| 769 | # if HAVE_STATACL | ||
| 770 | /* older AIX */ | ||
| 771 | /* There is no need to call chmod_or_fchmod, since the mode | ||
| 772 | bits S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */ | ||
| 773 | |||
| 774 | early_chmod = false; | ||
| 775 | # else | ||
| 776 | /* All other plaforms */ | ||
| 777 | /* On Cygwin, it is necessary to call chmod before acl, because | ||
| 778 | chmod can change the contents of the ACL (in ways that don't | ||
| 779 | change the allowed accesses, but still visible). */ | ||
| 780 | |||
| 781 | early_chmod = (! MODE_INSIDE_ACL || (ctx->mode & (S_ISUID | S_ISGID | S_ISVTX))); | ||
| 672 | # endif | 782 | # endif |
| 673 | #else /* !USE_ACL */ | 783 | #else |
| 674 | return chmod_or_fchmod (name, desc, mode); | 784 | /* No ACLs */ |
| 785 | |||
| 786 | early_chmod = true; | ||
| 675 | #endif | 787 | #endif |
| 788 | |||
| 789 | if (early_chmod) | ||
| 790 | { | ||
| 791 | ret = chmod_or_fchmod (name, desc, ctx->mode); | ||
| 792 | if (ret != 0) | ||
| 793 | return -1; | ||
| 794 | } | ||
| 795 | |||
| 796 | #if USE_ACL | ||
| 797 | ret = set_acls (ctx, name, desc, false, &must_chmod, &acls_set); | ||
| 798 | if (! acls_set) | ||
| 799 | { | ||
| 800 | int saved_errno = ret ? errno : 0; | ||
| 801 | |||
| 802 | /* If we can't set an acl which we expect to be able to set, try setting | ||
| 803 | the permissions to ctx->mode. Doe to possible inherited permissions, | ||
| 804 | we cannot simply chmod. */ | ||
| 805 | |||
| 806 | acls_set = false; | ||
| 807 | ret = set_acls (ctx, name, desc, true, &must_chmod, &acls_set); | ||
| 808 | if (! acls_set) | ||
| 809 | must_chmod = true; | ||
| 810 | |||
| 811 | if (saved_errno) | ||
| 812 | { | ||
| 813 | errno = saved_errno; | ||
| 814 | ret = -1; | ||
| 815 | } | ||
| 816 | } | ||
| 817 | #endif | ||
| 818 | |||
| 819 | if (must_chmod && ! early_chmod) | ||
| 820 | { | ||
| 821 | int saved_errno = ret ? errno : 0; | ||
| 822 | |||
| 823 | ret = chmod_or_fchmod (name, desc, ctx->mode); | ||
| 824 | |||
| 825 | if (saved_errno) | ||
| 826 | { | ||
| 827 | errno = saved_errno; | ||
| 828 | ret = -1; | ||
| 829 | } | ||
| 830 | } | ||
| 831 | |||
| 832 | return ret; | ||
| 676 | } | 833 | } |
diff --git a/lib/string.in.h b/lib/string.in.h index ebd727eda14..2abd6bc0e10 100644 --- a/lib/string.in.h +++ b/lib/string.in.h | |||
| @@ -15,16 +15,32 @@ | |||
| 15 | You should have received a copy of the GNU General Public License | 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/>. */ | 16 | along with this program; if not, see <http://www.gnu.org/licenses/>. */ |
| 17 | 17 | ||
| 18 | #ifndef _@GUARD_PREFIX@_STRING_H | ||
| 19 | |||
| 20 | #if __GNUC__ >= 3 | 18 | #if __GNUC__ >= 3 |
| 21 | @PRAGMA_SYSTEM_HEADER@ | 19 | @PRAGMA_SYSTEM_HEADER@ |
| 22 | #endif | 20 | #endif |
| 23 | @PRAGMA_COLUMNS@ | 21 | @PRAGMA_COLUMNS@ |
| 24 | 22 | ||
| 23 | #if defined _GL_ALREADY_INCLUDING_STRING_H | ||
| 24 | /* Special invocation convention: | ||
| 25 | - On OS X/NetBSD we have a sequence of nested includes | ||
| 26 | <string.h> -> <strings.h> -> "string.h" | ||
| 27 | In this situation system _chk variants due to -D_FORTIFY_SOURCE | ||
| 28 | might be used after any replacements defined here. */ | ||
| 29 | |||
| 30 | #@INCLUDE_NEXT@ @NEXT_STRING_H@ | ||
| 31 | |||
| 32 | #else | ||
| 33 | /* Normal invocation convention. */ | ||
| 34 | |||
| 35 | #ifndef _@GUARD_PREFIX@_STRING_H | ||
| 36 | |||
| 37 | #define _GL_ALREADY_INCLUDING_STRING_H | ||
| 38 | |||
| 25 | /* The include_next requires a split double-inclusion guard. */ | 39 | /* The include_next requires a split double-inclusion guard. */ |
| 26 | #@INCLUDE_NEXT@ @NEXT_STRING_H@ | 40 | #@INCLUDE_NEXT@ @NEXT_STRING_H@ |
| 27 | 41 | ||
| 42 | #undef _GL_ALREADY_INCLUDING_STRING_H | ||
| 43 | |||
| 28 | #ifndef _@GUARD_PREFIX@_STRING_H | 44 | #ifndef _@GUARD_PREFIX@_STRING_H |
| 29 | #define _@GUARD_PREFIX@_STRING_H | 45 | #define _@GUARD_PREFIX@_STRING_H |
| 30 | 46 | ||
| @@ -1027,3 +1043,4 @@ _GL_WARN_ON_USE (strverscmp, "strverscmp is unportable - " | |||
| 1027 | 1043 | ||
| 1028 | #endif /* _@GUARD_PREFIX@_STRING_H */ | 1044 | #endif /* _@GUARD_PREFIX@_STRING_H */ |
| 1029 | #endif /* _@GUARD_PREFIX@_STRING_H */ | 1045 | #endif /* _@GUARD_PREFIX@_STRING_H */ |
| 1046 | #endif | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | # acl.m4 - check for access control list (ACL) primitives | 1 | # acl.m4 - check for access control list (ACL) primitives |
| 2 | # serial 19 | 2 | # serial 20 |
| 3 | 3 | ||
| 4 | # Copyright (C) 2002, 2004-2015 Free Software Foundation, Inc. | 4 | # Copyright (C) 2002, 2004-2015 Free Software Foundation, Inc. |
| 5 | # This file is free software; the Free Software Foundation | 5 | # This file is free software; the Free Software Foundation |
| @@ -181,26 +181,12 @@ AC_DEFUN([gl_FILE_HAS_ACL], | |||
| 181 | [ | 181 | [ |
| 182 | AC_REQUIRE([gl_FUNC_ACL_ARG]) | 182 | AC_REQUIRE([gl_FUNC_ACL_ARG]) |
| 183 | if test "$enable_acl" != no; then | 183 | if test "$enable_acl" != no; then |
| 184 | AC_CACHE_CHECK([for getxattr with XATTR_NAME_POSIX_ACL macros], | 184 | AC_CHECK_HEADERS([linux/xattr.h]) |
| 185 | [gl_cv_getxattr_with_posix_acls], | 185 | AC_CHECK_HEADERS([sys/xattr.h], |
| 186 | [gl_cv_getxattr_with_posix_acls=no | 186 | [AC_CHECK_FUNCS([getxattr])]) |
| 187 | AC_LINK_IFELSE( | ||
| 188 | [AC_LANG_PROGRAM( | ||
| 189 | [[#include <sys/types.h> | ||
| 190 | #include <sys/xattr.h> | ||
| 191 | #include <linux/xattr.h> | ||
| 192 | ]], | ||
| 193 | [[ssize_t a = getxattr (".", XATTR_NAME_POSIX_ACL_ACCESS, 0, 0); | ||
| 194 | ssize_t b = getxattr (".", XATTR_NAME_POSIX_ACL_DEFAULT, 0, 0); | ||
| 195 | return a < 0 || b < 0; | ||
| 196 | ]])], | ||
| 197 | [gl_cv_getxattr_with_posix_acls=yes])]) | ||
| 198 | fi | 187 | fi |
| 199 | if test "$gl_cv_getxattr_with_posix_acls" = yes; then | 188 | if test "$ac_cv_header_sys_xattr_h,$ac_cv_func_getxattr" = yes,yes; then |
| 200 | LIB_HAS_ACL= | 189 | LIB_HAS_ACL= |
| 201 | AC_DEFINE([GETXATTR_WITH_POSIX_ACLS], 1, | ||
| 202 | [Define to 1 if getxattr works with XATTR_NAME_POSIX_ACL_ACCESS | ||
| 203 | and XATTR_NAME_POSIX_ACL_DEFAULT.]) | ||
| 204 | else | 190 | else |
| 205 | dnl Set gl_need_lib_has_acl to a nonempty value, so that any | 191 | dnl Set gl_need_lib_has_acl to a nonempty value, so that any |
| 206 | dnl later gl_FUNC_ACL call will set LIB_HAS_ACL=$LIB_ACL. | 192 | dnl later gl_FUNC_ACL call will set LIB_HAS_ACL=$LIB_ACL. |
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index 06636cfe76c..0425d02241a 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 | |||
| @@ -39,6 +39,7 @@ AC_DEFUN([gl_EARLY], | |||
| 39 | m4_pattern_allow([^gl_LTLIBOBJS$])dnl a variable | 39 | m4_pattern_allow([^gl_LTLIBOBJS$])dnl a variable |
| 40 | AC_REQUIRE([gl_PROG_AR_RANLIB]) | 40 | AC_REQUIRE([gl_PROG_AR_RANLIB]) |
| 41 | # Code from module absolute-header: | 41 | # Code from module absolute-header: |
| 42 | # Code from module acl-permissions: | ||
| 42 | # Code from module alloca-opt: | 43 | # Code from module alloca-opt: |
| 43 | # Code from module allocator: | 44 | # Code from module allocator: |
| 44 | # Code from module at-internal: | 45 | # Code from module at-internal: |
| @@ -105,7 +106,7 @@ AC_DEFUN([gl_EARLY], | |||
| 105 | # Code from module pselect: | 106 | # Code from module pselect: |
| 106 | # Code from module pthread_sigmask: | 107 | # Code from module pthread_sigmask: |
| 107 | # Code from module putenv: | 108 | # Code from module putenv: |
| 108 | # Code from module qacl: | 109 | # Code from module qcopy-acl: |
| 109 | # Code from module readlink: | 110 | # Code from module readlink: |
| 110 | # Code from module readlinkat: | 111 | # Code from module readlinkat: |
| 111 | # Code from module root-uid: | 112 | # Code from module root-uid: |
| @@ -172,6 +173,7 @@ AC_DEFUN([gl_INIT], | |||
| 172 | m4_pushdef([gl_LIBSOURCES_DIR], []) | 173 | m4_pushdef([gl_LIBSOURCES_DIR], []) |
| 173 | gl_COMMON | 174 | gl_COMMON |
| 174 | gl_source_base='lib' | 175 | gl_source_base='lib' |
| 176 | gl_FUNC_ACL | ||
| 175 | gl_FUNC_ALLOCA | 177 | gl_FUNC_ALLOCA |
| 176 | gl_BYTESWAP | 178 | gl_BYTESWAP |
| 177 | AC_CHECK_FUNCS_ONCE([readlinkat]) | 179 | AC_CHECK_FUNCS_ONCE([readlinkat]) |
| @@ -317,7 +319,6 @@ AC_DEFUN([gl_INIT], | |||
| 317 | gl_PREREQ_PUTENV | 319 | gl_PREREQ_PUTENV |
| 318 | fi | 320 | fi |
| 319 | gl_STDLIB_MODULE_INDICATOR([putenv]) | 321 | gl_STDLIB_MODULE_INDICATOR([putenv]) |
| 320 | gl_FUNC_ACL | ||
| 321 | gl_FUNC_READLINK | 322 | gl_FUNC_READLINK |
| 322 | if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then | 323 | if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then |
| 323 | AC_LIBOBJ([readlink]) | 324 | AC_LIBOBJ([readlink]) |
| @@ -865,6 +866,7 @@ AC_DEFUN([gl_FILE_LIST], [ | |||
| 865 | lib/fsync.c | 866 | lib/fsync.c |
| 866 | lib/ftoastr.c | 867 | lib/ftoastr.c |
| 867 | lib/ftoastr.h | 868 | lib/ftoastr.h |
| 869 | lib/get-permissions.c | ||
| 868 | lib/getdtablesize.c | 870 | lib/getdtablesize.c |
| 869 | lib/getgroups.c | 871 | lib/getgroups.c |
| 870 | lib/getloadavg.c | 872 | lib/getloadavg.c |
| @@ -895,11 +897,11 @@ AC_DEFUN([gl_FILE_LIST], [ | |||
| 895 | lib/pthread_sigmask.c | 897 | lib/pthread_sigmask.c |
| 896 | lib/putenv.c | 898 | lib/putenv.c |
| 897 | lib/qcopy-acl.c | 899 | lib/qcopy-acl.c |
| 898 | lib/qset-acl.c | ||
| 899 | lib/readlink.c | 900 | lib/readlink.c |
| 900 | lib/readlinkat.c | 901 | lib/readlinkat.c |
| 901 | lib/root-uid.h | 902 | lib/root-uid.h |
| 902 | lib/secure_getenv.c | 903 | lib/secure_getenv.c |
| 904 | lib/set-permissions.c | ||
| 903 | lib/sha1.c | 905 | lib/sha1.c |
| 904 | lib/sha1.h | 906 | lib/sha1.h |
| 905 | lib/sha256.c | 907 | lib/sha256.c |
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4 index e0c4bde1f8e..f60cc2156e0 100644 --- a/m4/stdio_h.m4 +++ b/m4/stdio_h.m4 | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | # stdio_h.m4 serial 44 | 1 | # stdio_h.m4 serial 46 |
| 2 | dnl Copyright (C) 2007-2015 Free Software Foundation, Inc. | 2 | dnl Copyright (C) 2007-2015 Free Software Foundation, Inc. |
| 3 | dnl This file is free software; the Free Software Foundation | 3 | dnl This file is free software; the Free Software Foundation |
| 4 | dnl gives unlimited permission to copy and/or distribute it, | 4 | dnl gives unlimited permission to copy and/or distribute it, |
| @@ -15,15 +15,21 @@ AC_DEFUN([gl_STDIO_H], | |||
| 15 | dnl Determine whether __USE_MINGW_ANSI_STDIO makes printf and | 15 | dnl Determine whether __USE_MINGW_ANSI_STDIO makes printf and |
| 16 | dnl inttypes.h behave like gnu instead of system; we must give our | 16 | dnl inttypes.h behave like gnu instead of system; we must give our |
| 17 | dnl printf wrapper the right attribute to match. | 17 | dnl printf wrapper the right attribute to match. |
| 18 | AC_CACHE_CHECK([whether inttypes macros match system or gnu printf], | 18 | AC_CACHE_CHECK([which flavor of printf attribute matches inttypes macros], |
| 19 | [gl_cv_func_printf_attribute_flavor], | 19 | [gl_cv_func_printf_attribute_flavor], |
| 20 | [AC_EGREP_CPP([findme .(ll|j)d. findme], | 20 | [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ |
| 21 | [#define __STDC_FORMAT_MACROS 1 | 21 | #define __STDC_FORMAT_MACROS 1 |
| 22 | #include <stdio.h> | 22 | #include <stdio.h> |
| 23 | #include <inttypes.h> | 23 | #include <inttypes.h> |
| 24 | findme PRIdMAX findme | 24 | /* For non-mingw systems, compilation will trivially succeed. |
| 25 | ], [gl_cv_func_printf_attribute_flavor=gnu], | 25 | For mingw, compilation will succeed for older mingw (system |
| 26 | [gl_cv_func_printf_attribute_flavor=system])]) | 26 | printf, "I64d") and fail for newer mingw (gnu printf, "lld"). */ |
| 27 | #if ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__) && \ | ||
| 28 | (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) | ||
| 29 | extern char PRIdMAX_probe[sizeof PRIdMAX == sizeof "I64d" ? 1 : -1]; | ||
| 30 | #endif | ||
| 31 | ]])], [gl_cv_func_printf_attribute_flavor=system], | ||
| 32 | [gl_cv_func_printf_attribute_flavor=gnu])]) | ||
| 27 | if test "$gl_cv_func_printf_attribute_flavor" = gnu; then | 33 | if test "$gl_cv_func_printf_attribute_flavor" = gnu; then |
| 28 | AC_DEFINE([GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU], [1], | 34 | AC_DEFINE([GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU], [1], |
| 29 | [Define to 1 if printf and friends should be labeled with | 35 | [Define to 1 if printf and friends should be labeled with |
diff --git a/nt/gnulib.mk b/nt/gnulib.mk index 26a9ea9ad53..cab20d911b8 100644 --- a/nt/gnulib.mk +++ b/nt/gnulib.mk | |||
| @@ -43,7 +43,7 @@ | |||
| 43 | # the same distribution terms as the rest of that program. | 43 | # the same distribution terms as the rest of that program. |
| 44 | # | 44 | # |
| 45 | # Generated by gnulib-tool. | 45 | # Generated by gnulib-tool. |
| 46 | # Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings | 46 | # Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings |
| 47 | 47 | ||
| 48 | 48 | ||
| 49 | MOSTLYCLEANFILES += core *.stackdump | 49 | MOSTLYCLEANFILES += core *.stackdump |
| @@ -64,6 +64,17 @@ HAVE_INCLUDE_NEXT = (__GNUC__ || 60000000 <= __DECC_VER) | |||
| 64 | 64 | ||
| 65 | ## end gnulib module absolute-header | 65 | ## end gnulib module absolute-header |
| 66 | 66 | ||
| 67 | ## begin gnulib module acl-permissions | ||
| 68 | |||
| 69 | libgnu_a_SOURCES += acl-errno-valid.c acl-internal.c \ | ||
| 70 | get-permissions.c set-permissions.c | ||
| 71 | |||
| 72 | EXTRA_DIST += acl-internal.h acl.h acl_entries.c | ||
| 73 | |||
| 74 | EXTRA_libgnu_a_SOURCES += acl_entries.c | ||
| 75 | |||
| 76 | ## end gnulib module acl-permissions | ||
| 77 | |||
| 67 | ## begin gnulib module alloca-opt | 78 | ## begin gnulib module alloca-opt |
| 68 | 79 | ||
| 69 | BUILT_SOURCES += $(ALLOCA_H) | 80 | BUILT_SOURCES += $(ALLOCA_H) |
| @@ -521,15 +532,11 @@ EXTRA_libgnu_a_SOURCES += putenv.c | |||
| 521 | 532 | ||
| 522 | ## end gnulib module putenv | 533 | ## end gnulib module putenv |
| 523 | 534 | ||
| 524 | ## begin gnulib module qacl | 535 | ## begin gnulib module qcopy-acl |
| 525 | |||
| 526 | libgnu_a_SOURCES += acl-errno-valid.c acl-internal.c qcopy-acl.c | ||
| 527 | 536 | ||
| 528 | EXTRA_DIST += acl-internal.h acl.h acl_entries.c | 537 | libgnu_a_SOURCES += qcopy-acl.c |
| 529 | |||
| 530 | EXTRA_libgnu_a_SOURCES += acl_entries.c | ||
| 531 | 538 | ||
| 532 | ## end gnulib module qacl | 539 | ## end gnulib module qcopy-acl |
| 533 | 540 | ||
| 534 | ## begin gnulib module readlink | 541 | ## begin gnulib module readlink |
| 535 | 542 | ||