Merge from origin/emacs-24
[emacs.git] / lib / qset-acl.c
blob7d9af573fbfa611ec92f2d2db0a6c0b2aac2d950
1 /* qset-acl.c - set access control list equivalent to a mode
3 Copyright (C) 2002-2003, 2005-2014 Free Software Foundation, Inc.
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.
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.
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/>.
18 Written by Paul Eggert and Andreas Gruenbacher, and Bruno Haible. */
20 #include <config.h>
22 #define ACL_INTERNAL_INLINE _GL_EXTERN_INLINE
24 #include "acl.h"
26 #include "acl-internal.h"
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. */
35 int
36 chmod_or_fchmod (const char *name, int desc, mode_t mode)
38 if (HAVE_FCHMOD && desc != -1)
39 return fchmod (desc, mode);
40 else
41 return chmod (name, mode);
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. */
52 int
53 qset_acl (char const *name, int desc, mode_t mode)
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 */
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.) */
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
74 acl_t acl;
75 int ret;
77 if (HAVE_ACL_FROM_MODE) /* Linux */
79 acl = acl_from_mode (mode);
80 if (!acl)
81 return -1;
83 else /* FreeBSD, IRIX, Tru64 */
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(). */
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
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';
107 acl = acl_from_text (acl_text);
108 if (!acl)
109 return -1;
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)
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;
124 else
125 acl_free (acl);
127 if (S_ISDIR (mode) && acl_delete_def_file (name))
128 return -1;
130 if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
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);
136 return 0;
138 # else /* HAVE_ACL_TYPE_EXTENDED */
139 /* Mac OS X */
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. */
154 acl_t acl;
155 int ret;
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)
164 acl_free (acl);
166 acl = acl_init (0);
167 if (acl)
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)
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;
182 acl_free (acl);
186 /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
187 return chmod_or_fchmod (name, desc, mode);
188 # endif
190 # elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
192 int done_setacl = 0;
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). */
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;
207 /* Initially, try to read the entries into a stack-allocated buffer.
208 Use malloc if it does not fit. */
209 enum
211 alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
212 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
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;
220 for (;;)
222 count = (desc != -1
223 ? facl (desc, ACE_GETACL, alloc, entries)
224 : acl (name, ACE_GETACL, alloc, entries));
225 if (count < 0 && errno == ENOSPC)
227 /* Increase the size of the buffer. */
228 free (malloced);
229 if (alloc > alloc_max / 2)
231 errno = ENOMEM;
232 return -1;
234 alloc = 2 * alloc; /* <= alloc_max */
235 entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
236 if (entries == NULL)
238 errno = ENOMEM;
239 return -1;
241 continue;
243 break;
246 if (count <= 0)
247 convention = -1;
248 else
250 int i;
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))
256 convention = 1;
257 break;
260 free (malloced);
263 if (convention >= 0)
265 ace_t entries[6];
266 int count;
267 int ret;
269 if (convention)
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;
286 else
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;
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)
367 if (errno == ENOSYS)
368 return chmod_or_fchmod (name, desc, mode);
369 return -1;
371 if (ret == 0)
372 done_setacl = 1;
374 # endif
376 if (!done_setacl)
378 aclent_t entries[3];
379 int ret;
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;
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)
399 if (errno == ENOSYS || errno == EOPNOTSUPP)
400 return chmod_or_fchmod (name, desc, mode);
401 return -1;
405 if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
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);
411 return 0;
413 # elif HAVE_GETACL /* HP-UX */
415 struct stat statbuf;
416 int ret;
418 if (desc != -1)
419 ret = fstat (desc, &statbuf);
420 else
421 ret = stat (name, &statbuf);
422 if (ret < 0)
423 return -1;
426 struct acl_entry entries[3];
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;
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);
443 if (ret < 0)
445 if (!(errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
446 return -1;
448 # if HAVE_ACLV_H /* HP-UX >= 11.11 */
450 struct acl entries[4];
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;
465 ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries);
466 if (ret > 0)
467 abort ();
468 if (ret < 0)
470 if (0)
471 return chmod_or_fchmod (name, desc, mode);
472 return -1;
475 ret = acl ((char *) name, ACL_SET,
476 sizeof (entries) / sizeof (struct acl), entries);
477 if (ret < 0)
479 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
480 return chmod_or_fchmod (name, desc, mode);
481 return -1;
484 # else
485 return chmod_or_fchmod (name, desc, mode);
486 # endif
489 if (mode & (S_ISUID | S_ISGID | S_ISVTX))
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);
495 return 0;
497 # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
499 acl_type_list_t types;
500 size_t types_size = sizeof (types);
501 acl_type_t type;
503 if (aclx_gettypes (name, &types, &types_size) < 0
504 || types.num_entries == 0)
505 return chmod_or_fchmod (name, desc, mode);
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)
512 union { struct acl a; char room[128]; } u;
513 int ret;
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;
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;
530 else if (type.u64 == ACL_NFS4)
532 union { nfs4_acl_int_t a; char room[128]; } u;
533 nfs4_ace_int_t *ace;
534 int ret;
536 u.a.aclVersion = NFS4_ACL_INT_STRUCT_VERSION;
537 u.a.aclEntryN = 0;
538 ace = &u.a.aclEntry[0];
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++;
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++;
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++;
590 u.a.aclLength = (char *) ace - (char *) &u.a;
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;
602 return chmod_or_fchmod (name, desc, mode);
604 # elif HAVE_STATACL /* older AIX */
606 union { struct acl a; char room[128]; } u;
607 int ret;
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;
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);
620 if (ret < 0 && errno == ENOSYS)
621 return chmod_or_fchmod (name, desc, mode);
623 return ret;
625 # elif HAVE_ACLSORT /* NonStop Kernel */
627 struct acl entries[4];
628 int ret;
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;
643 ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries);
644 if (ret > 0)
645 abort ();
646 if (ret < 0)
648 if (0)
649 return chmod_or_fchmod (name, desc, mode);
650 return -1;
653 ret = acl ((char *) name, ACL_SET,
654 sizeof (entries) / sizeof (struct acl), entries);
655 if (ret < 0)
657 if (0)
658 return chmod_or_fchmod (name, desc, mode);
659 return -1;
662 if (mode & (S_ISUID | S_ISGID | S_ISVTX))
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);
668 return 0;
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