1 /* set-permissions.c - set permissions of a file
3 Copyright (C) 2002-2003, 2005-2015 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, Andreas Grünbacher, and Bruno Haible. */
24 #include "acl-internal.h"
27 # if ! defined HAVE_ACL_FROM_MODE && defined HAVE_ACL_FROM_TEXT /* FreeBSD, IRIX, Tru64 */
29 acl_from_mode (mode_t mode
)
31 # if HAVE_ACL_FREE_TEXT /* Tru64 */
32 char acl_text
[] = "u::---,g::---,o::---,";
33 # else /* FreeBSD, IRIX */
34 char acl_text
[] = "u::---,g::---,o::---";
37 if (mode
& S_IRUSR
) acl_text
[ 3] = 'r';
38 if (mode
& S_IWUSR
) acl_text
[ 4] = 'w';
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';
47 return acl_from_text (acl_text
);
51 # if HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
53 set_acls_from_mode (const char *name
, int desc
, mode_t mode
, bool *must_chmod
)
56 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
57 file systems (whereas the other ones are used in UFS file systems). */
59 /* The flags in the ace_t structure changed in a binary incompatible way
60 when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
61 How to distinguish the two conventions at runtime?
62 We fetch the existing ACL. In the old convention, usually three ACEs have
63 a_flags = ACE_OWNER / ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400.
64 In the new convention, these values are not used. */
68 /* Initially, try to read the entries into a stack-allocated buffer.
69 Use malloc if it does not fit. */
72 alloc_init
= 4000 / sizeof (ace_t
), /* >= 3 */
73 alloc_max
= MIN (INT_MAX
, SIZE_MAX
/ sizeof (ace_t
))
75 ace_t buf
[alloc_init
];
76 size_t alloc
= alloc_init
;
78 ace_t
*malloced
= NULL
;
84 ? facl (desc
, ACE_GETACL
, alloc
, entries
)
85 : acl (name
, ACE_GETACL
, alloc
, entries
));
86 if (count
< 0 && errno
== ENOSPC
)
88 /* Increase the size of the buffer. */
90 if (alloc
> alloc_max
/ 2)
95 alloc
= 2 * alloc
; /* <= alloc_max */
96 entries
= malloced
= (ace_t
*) malloc (alloc
* sizeof (ace_t
));
114 for (i
= 0; i
< count
; i
++)
115 if (entries
[i
].a_flags
& (OLD_ACE_OWNER
| OLD_ACE_GROUP
| OLD_ACE_OTHER
))
132 /* Running on Solaris 10. */
133 entries
[0].a_type
= OLD_ALLOW
;
134 entries
[0].a_flags
= OLD_ACE_OWNER
;
135 entries
[0].a_who
= 0; /* irrelevant */
136 entries
[0].a_access_mask
= (mode
>> 6) & 7;
137 entries
[1].a_type
= OLD_ALLOW
;
138 entries
[1].a_flags
= OLD_ACE_GROUP
;
139 entries
[1].a_who
= 0; /* irrelevant */
140 entries
[1].a_access_mask
= (mode
>> 3) & 7;
141 entries
[2].a_type
= OLD_ALLOW
;
142 entries
[2].a_flags
= OLD_ACE_OTHER
;
143 entries
[2].a_who
= 0;
144 entries
[2].a_access_mask
= mode
& 7;
149 /* Running on Solaris 10 (newer version) or Solaris 11.
150 The details here were found through "/bin/ls -lvd somefiles". */
151 entries
[0].a_type
= NEW_ACE_ACCESS_DENIED_ACE_TYPE
;
152 entries
[0].a_flags
= NEW_ACE_OWNER
;
153 entries
[0].a_who
= 0; /* irrelevant */
154 entries
[0].a_access_mask
= 0;
155 entries
[1].a_type
= NEW_ACE_ACCESS_ALLOWED_ACE_TYPE
;
156 entries
[1].a_flags
= NEW_ACE_OWNER
;
157 entries
[1].a_who
= 0; /* irrelevant */
158 entries
[1].a_access_mask
= NEW_ACE_WRITE_NAMED_ATTRS
159 | NEW_ACE_WRITE_ATTRIBUTES
161 | NEW_ACE_WRITE_OWNER
;
163 entries
[1].a_access_mask
|= NEW_ACE_READ_DATA
;
165 entries
[0].a_access_mask
|= NEW_ACE_READ_DATA
;
167 entries
[1].a_access_mask
|= NEW_ACE_WRITE_DATA
| NEW_ACE_APPEND_DATA
;
169 entries
[0].a_access_mask
|= NEW_ACE_WRITE_DATA
| NEW_ACE_APPEND_DATA
;
171 entries
[1].a_access_mask
|= NEW_ACE_EXECUTE
;
173 entries
[0].a_access_mask
|= NEW_ACE_EXECUTE
;
174 entries
[2].a_type
= NEW_ACE_ACCESS_DENIED_ACE_TYPE
;
175 entries
[2].a_flags
= NEW_ACE_GROUP
| NEW_ACE_IDENTIFIER_GROUP
;
176 entries
[2].a_who
= 0; /* irrelevant */
177 entries
[2].a_access_mask
= 0;
178 entries
[3].a_type
= NEW_ACE_ACCESS_ALLOWED_ACE_TYPE
;
179 entries
[3].a_flags
= NEW_ACE_GROUP
| NEW_ACE_IDENTIFIER_GROUP
;
180 entries
[3].a_who
= 0; /* irrelevant */
181 entries
[3].a_access_mask
= 0;
183 entries
[3].a_access_mask
|= NEW_ACE_READ_DATA
;
185 entries
[2].a_access_mask
|= NEW_ACE_READ_DATA
;
187 entries
[3].a_access_mask
|= NEW_ACE_WRITE_DATA
| NEW_ACE_APPEND_DATA
;
189 entries
[2].a_access_mask
|= NEW_ACE_WRITE_DATA
| NEW_ACE_APPEND_DATA
;
191 entries
[3].a_access_mask
|= NEW_ACE_EXECUTE
;
193 entries
[2].a_access_mask
|= NEW_ACE_EXECUTE
;
194 entries
[4].a_type
= NEW_ACE_ACCESS_DENIED_ACE_TYPE
;
195 entries
[4].a_flags
= NEW_ACE_EVERYONE
;
196 entries
[4].a_who
= 0;
197 entries
[4].a_access_mask
= NEW_ACE_WRITE_NAMED_ATTRS
198 | NEW_ACE_WRITE_ATTRIBUTES
200 | NEW_ACE_WRITE_OWNER
;
201 entries
[5].a_type
= NEW_ACE_ACCESS_ALLOWED_ACE_TYPE
;
202 entries
[5].a_flags
= NEW_ACE_EVERYONE
;
203 entries
[5].a_who
= 0;
204 entries
[5].a_access_mask
= NEW_ACE_READ_NAMED_ATTRS
205 | NEW_ACE_READ_ATTRIBUTES
207 | NEW_ACE_SYNCHRONIZE
;
209 entries
[5].a_access_mask
|= NEW_ACE_READ_DATA
;
211 entries
[4].a_access_mask
|= NEW_ACE_READ_DATA
;
213 entries
[5].a_access_mask
|= NEW_ACE_WRITE_DATA
| NEW_ACE_APPEND_DATA
;
215 entries
[4].a_access_mask
|= NEW_ACE_WRITE_DATA
| NEW_ACE_APPEND_DATA
;
217 entries
[5].a_access_mask
|= NEW_ACE_EXECUTE
;
219 entries
[4].a_access_mask
|= NEW_ACE_EXECUTE
;
223 ret
= facl (desc
, ACE_SETACL
, count
, entries
);
225 ret
= acl (name
, ACE_SETACL
, count
, entries
);
226 if (ret
< 0 && errno
!= EINVAL
&& errno
!= ENOTSUP
)
244 entries
[0].a_type
= USER_OBJ
;
245 entries
[0].a_id
= 0; /* irrelevant */
246 entries
[0].a_perm
= (mode
>> 6) & 7;
247 entries
[1].a_type
= GROUP_OBJ
;
248 entries
[1].a_id
= 0; /* irrelevant */
249 entries
[1].a_perm
= (mode
>> 3) & 7;
250 entries
[2].a_type
= OTHER_OBJ
;
252 entries
[2].a_perm
= mode
& 7;
255 ret
= facl (desc
, SETACL
,
256 sizeof (entries
) / sizeof (aclent_t
), entries
);
258 ret
= acl (name
, SETACL
,
259 sizeof (entries
) / sizeof (aclent_t
), entries
);
262 if (errno
== ENOSYS
|| errno
== EOPNOTSUPP
)
272 #elif HAVE_GETACL /* HP-UX */
274 context_acl_from_mode (struct permission_context
*ctx
, const char *name
, int desc
)
280 ret
= fstat (desc
, &statbuf
);
282 ret
= stat (name
, &statbuf
);
286 ctx
->entries
[0].uid
= statbuf
.st_uid
;
287 ctx
->entries
[0].gid
= ACL_NSGROUP
;
288 ctx
->entries
[0].mode
= (mode
>> 6) & 7;
289 ctx
->entries
[1].uid
= ACL_NSUSER
;
290 ctx
->entries
[1].gid
= statbuf
.st_gid
;
291 ctx
->entries
[1].mode
= (mode
>> 3) & 7;
292 ctx
->entries
[2].uid
= ACL_NSUSER
;
293 ctx
->entries
[2].gid
= ACL_NSGROUP
;
294 ctx
->entries
[2].mode
= mode
& 7;
299 # if HAVE_ACLV_H /* HP-UX >= 11.11 */
301 context_aclv_from_mode (struct permission_context
*ctx
)
305 ctx
->aclv_entries
[0].a_type
= USER_OBJ
;
306 ctx
->aclv_entries
[0].a_id
= 0; /* irrelevant */
307 ctx
->aclv_entries
[0].a_perm
= (mode
>> 6) & 7;
308 ctx
->aclv_entries
[1].a_type
= GROUP_OBJ
;
309 ctx
->aclv_entries
[1].a_id
= 0; /* irrelevant */
310 ctx
->aclv_entries
[1].a_perm
= (mode
>> 3) & 7;
311 ctx
->aclv_entries
[2].a_type
= CLASS_OBJ
;
312 ctx
->aclv_entries
[2].a_id
= 0;
313 ctx
->aclv_entries
[2].a_perm
= (mode
>> 3) & 7;
314 ctx
->aclv_entries
[3].a_type
= OTHER_OBJ
;
315 ctx
->aclv_entries
[3].a_id
= 0;
316 ctx
->aclv_entries
[3].a_perm
= mode
& 7;
319 ret
= aclsort (sizeof (entries
) / sizeof (struct acl
), 1, entries
);
326 # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
328 set_acls_from_mode (const char *name
, int desc
, mode_t mode
, bool *must_chmod
)
330 acl_type_list_t types
;
331 size_t types_size
= sizeof (types
);
334 if (aclx_gettypes (name
, &types
, &types_size
) < 0
335 || types
.num_entries
== 0)
341 /* XXX Do we need to clear all types of ACLs for the given file, or is it
342 sufficient to clear the first one? */
343 type
= types
.entries
[0];
344 if (type
.u64
== ACL_AIXC
)
346 union { struct acl a
; char room
[128]; } u
;
349 u
.a
.acl_len
= (char *) &u
.a
.acl_ext
[0] - (char *) &u
.a
; /* no entries */
350 u
.a
.acl_mode
= mode
& ~(S_IXACL
| 0777);
351 u
.a
.u_access
= (mode
>> 6) & 7;
352 u
.a
.g_access
= (mode
>> 3) & 7;
353 u
.a
.o_access
= mode
& 7;
356 ret
= aclx_fput (desc
, SET_ACL
| SET_MODE_S_BITS
,
357 type
, &u
.a
, u
.a
.acl_len
, mode
);
359 ret
= aclx_put (name
, SET_ACL
| SET_MODE_S_BITS
,
360 type
, &u
.a
, u
.a
.acl_len
, mode
);
361 if (!(ret
< 0 && errno
== ENOSYS
))
364 else if (type
.u64
== ACL_NFS4
)
366 union { nfs4_acl_int_t a
; char room
[128]; } u
;
370 u
.a
.aclVersion
= NFS4_ACL_INT_STRUCT_VERSION
;
372 ace
= &u
.a
.aclEntry
[0];
374 ace
->flags
= ACE4_ID_SPECIAL
;
375 ace
->aceWho
.special_whoid
= ACE4_WHO_OWNER
;
376 ace
->aceType
= ACE4_ACCESS_ALLOWED_ACE_TYPE
;
379 (mode
& 0400 ? ACE4_READ_DATA
| ACE4_LIST_DIRECTORY
: 0)
381 ? ACE4_WRITE_DATA
| ACE4_ADD_FILE
| ACE4_APPEND_DATA
382 | ACE4_ADD_SUBDIRECTORY
384 | (mode
& 0100 ? ACE4_EXECUTE
: 0);
385 ace
->aceWhoString
[0] = '\0';
386 ace
->entryLen
= (char *) &ace
->aceWhoString
[4] - (char *) ace
;
387 ace
= (nfs4_ace_int_t
*) (char *) &ace
->aceWhoString
[4];
391 ace
->flags
= ACE4_ID_SPECIAL
;
392 ace
->aceWho
.special_whoid
= ACE4_WHO_GROUP
;
393 ace
->aceType
= ACE4_ACCESS_ALLOWED_ACE_TYPE
;
396 (mode
& 0040 ? ACE4_READ_DATA
| ACE4_LIST_DIRECTORY
: 0)
398 ? ACE4_WRITE_DATA
| ACE4_ADD_FILE
| ACE4_APPEND_DATA
399 | ACE4_ADD_SUBDIRECTORY
401 | (mode
& 0010 ? ACE4_EXECUTE
: 0);
402 ace
->aceWhoString
[0] = '\0';
403 ace
->entryLen
= (char *) &ace
->aceWhoString
[4] - (char *) ace
;
404 ace
= (nfs4_ace_int_t
*) (char *) &ace
->aceWhoString
[4];
408 ace
->flags
= ACE4_ID_SPECIAL
;
409 ace
->aceWho
.special_whoid
= ACE4_WHO_EVERYONE
;
410 ace
->aceType
= ACE4_ACCESS_ALLOWED_ACE_TYPE
;
413 (mode
& 0004 ? ACE4_READ_DATA
| ACE4_LIST_DIRECTORY
: 0)
415 ? ACE4_WRITE_DATA
| ACE4_ADD_FILE
| ACE4_APPEND_DATA
416 | ACE4_ADD_SUBDIRECTORY
418 | (mode
& 0001 ? ACE4_EXECUTE
: 0);
419 ace
->aceWhoString
[0] = '\0';
420 ace
->entryLen
= (char *) &ace
->aceWhoString
[4] - (char *) ace
;
421 ace
= (nfs4_ace_int_t
*) (char *) &ace
->aceWhoString
[4];
424 u
.a
.aclLength
= (char *) ace
- (char *) &u
.a
;
427 ret
= aclx_fput (desc
, SET_ACL
| SET_MODE_S_BITS
,
428 type
, &u
.a
, u
.a
.aclLength
, mode
);
430 ret
= aclx_put (name
, SET_ACL
| SET_MODE_S_BITS
,
431 type
, &u
.a
, u
.a
.aclLength
, mode
);
432 if (!(ret
< 0 && errno
== ENOSYS
))
440 # elif HAVE_STATACL /* older AIX */
442 context_acl_from_mode (struct permission_context
*ctx
)
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;
453 # elif HAVE_ACLSORT /* NonStop Kernel */
455 context_acl_from_mode (struct permission_context
*ctx
)
459 ctx
->entries
[0].a_type
= USER_OBJ
;
460 ctx
->entries
[0].a_id
= 0; /* irrelevant */
461 ctx
->entries
[0].a_perm
= (mode
>> 6) & 7;
462 ctx
->entries
[1].a_type
= GROUP_OBJ
;
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;
473 ret
= aclsort (sizeof (entries
) / sizeof (struct acl
), 1, entries
);
481 set_acls (struct permission_context
*ctx
, const char *name
, int desc
,
482 int from_mode
, bool *must_chmod
, bool *acls_set
)
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 */
492 # ifndef HAVE_ACL_FROM_TEXT
493 # error Must have acl_from_text (see POSIX 1003.1e draft 17).
495 # ifndef HAVE_ACL_DELETE_DEF_FILE
496 # error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
499 if (! ctx
->acls_not_supported
)
501 if (ret
== 0 && from_mode
)
505 ctx
->acl
= acl_from_mode (ctx
->mode
);
506 if (ctx
->acl
== NULL
)
510 if (ret
== 0 && ctx
->acl
)
512 if (HAVE_ACL_SET_FD
&& desc
!= -1)
513 ret
= acl_set_fd (desc
, ctx
->acl
);
515 ret
= acl_set_file (name
, ACL_TYPE_ACCESS
, ctx
->acl
);
518 if (! acl_errno_valid (errno
))
520 ctx
->acls_not_supported
= true;
521 if (from_mode
|| acl_access_nontrivial (ctx
->acl
) == 0)
528 if (S_ISDIR(ctx
->mode
))
530 if (! from_mode
&& ctx
->default_acl
)
531 ret
= acl_set_file (name
, ACL_TYPE_DEFAULT
,
534 ret
= acl_delete_def_file (name
);
540 # else /* HAVE_ACL_TYPE_EXTENDED */
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, ...))
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. */
556 if (ctx
->acl
== NULL
)
560 /* Remove ACLs if the file has ACLs. */
561 if (HAVE_ACL_GET_FD
&& desc
!= -1)
562 acl
= acl_get_fd (desc
);
564 acl
= acl_get_file (name
, ACL_TYPE_EXTENDED
);
572 if (HAVE_ACL_SET_FD
&& desc
!= -1)
573 ret
= acl_set_fd (desc
, acl
);
575 ret
= acl_set_file (name
, ACL_TYPE_EXTENDED
, acl
);
584 if (HAVE_ACL_SET_FD
&& desc
!= -1)
585 ret
= acl_set_fd (desc
, ctx
->acl
);
587 ret
= acl_set_file (name
, ACL_TYPE_EXTENDED
, ctx
->acl
);
590 if (! acl_errno_valid (errno
)
591 && ! acl_extended_nontrivial (ctx
->acl
))
599 # elif defined GETACL /* Solaris, Cygwin, not HP-UX */
601 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
602 of Unixware. The acl() call returns the access and default ACL both
605 /* If both ace_entries and entries are available, try SETACL before
606 ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
610 return set_acls_from_mode (name
, desc
, ctx
->mode
, must_chmod
);
612 if (ret
== 0 && ctx
->count
)
615 ret
= facl (desc
, SETACL
, ctx
->count
, ctx
->entries
);
617 ret
= acl (name
, SETACL
, ctx
->count
, ctx
->entries
);
620 if ((errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== EINVAL
)
621 && acl_nontrivial (ctx
->count
, ctx
->entries
) == 0)
629 if (ret
== 0 && ctx
->ace_count
)
632 ret
= facl (desc
, ACE_SETACL
, ctx
->ace_count
, ctx
->ace_entries
);
634 ret
= acl (name
, ACE_SETACL
, ctx
->ace_count
, ctx
->ace_entries
);
637 if ((errno
== ENOSYS
|| errno
== EINVAL
|| errno
== ENOTSUP
)
638 && acl_ace_nontrivial (ctx
->ace_count
, ctx
->ace_entries
) == 0)
646 #elif HAVE_GETACL /* HP-UX */
649 ret
= context_acl_from_mode (ctx
, name
, desc
);
651 if (ret
== 0 && ctx
->count
> 0)
654 ret
= fsetacl (desc
, ctx
->count
, ctx
->entries
);
656 ret
= setacl (name
, ctx
->count
, ctx
->entries
);
659 if ((errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== ENOTSUP
)
660 && (from_mode
|| !acl_nontrivial (ctx
->count
, ctx
->entries
, &source_statbuf
)))
669 ret
= context_aclv_from_mode (ctx
);
671 if (ret
== 0 && ctx
->aclv_count
> 0)
673 ret
= acl ((char *) name
, ACL_SET
, ctx
->aclv_count
, ctx
->aclv_entries
);
676 if ((errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== EINVAL
)
677 && (from_mode
|| !aclv_nontrivial (ctx
->aclv_count
, ctx
->aclv_entries
)))
685 # elif HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */
687 /* TODO: Implement setting ACLs once get_permissions() reads them. */
690 ret
= set_acls_from_mode (name
, desc
, mode
, must_chmod
);
692 # elif HAVE_STATACL /* older AIX */
695 ret
= context_acl_from_mode (ctx
);
697 if (ret
== 0 && ctx
->have_u
)
700 ret
= fchacl (desc
, &ctx
->u
.a
, ctx
->u
.a
.acl_len
);
702 ret
= chacl ((char *) name
, &ctx
->u
.a
, ctx
->u
.a
.acl_len
);
705 if (errno
== ENOSYS
&& from_mode
)
712 # elif HAVE_ACLSORT /* NonStop Kernel */
715 ret
= context_acl_from_mode (ctx
);
717 if (ret
== 0 && ctx
->count
)
719 ret
= acl ((char *) name
, ACL_SET
, ctx
->count
, ctx
->entries
);
722 if (!acl_nontrivial (ctx
->count
, ctx
->entries
))
739 /* If DESC is a valid file descriptor use fchmod to change the
740 file's mode to MODE on systems that have fchmod. On systems
741 that don't have fchmod and if DESC is invalid, use chmod on
743 Return 0 if successful. Return -1 and set errno upon failure. */
746 chmod_or_fchmod (const char *name
, int desc
, mode_t mode
)
748 if (HAVE_FCHMOD
&& desc
!= -1)
749 return fchmod (desc
, mode
);
751 return chmod (name
, mode
);
754 /* Set the permissions in CTX on a file. If DESC is a valid file descriptor,
755 use file descriptor operations, else use filename based operations on NAME.
756 If access control lists are not available, fchmod the target file to the
757 mode in CTX. Also sets the non-permission bits of the destination file
758 (S_ISUID, S_ISGID, S_ISVTX) to those from the mode in CTX if any are set.
759 Return 0 if successful. Return -1 and set errno upon failure. */
762 set_permissions (struct permission_context
*ctx
, const char *name
, int desc
)
764 bool acls_set _GL_UNUSED
= false;
766 bool must_chmod
= false;
772 /* There is no need to call chmod_or_fchmod, since the mode
773 bits S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */
777 /* All other platforms */
778 /* On Cygwin, it is necessary to call chmod before acl, because
779 chmod can change the contents of the ACL (in ways that don't
780 change the allowed accesses, but still visible). */
782 early_chmod
= (! MODE_INSIDE_ACL
|| (ctx
->mode
& (S_ISUID
| S_ISGID
| S_ISVTX
)));
792 ret
= chmod_or_fchmod (name
, desc
, ctx
->mode
);
798 ret
= set_acls (ctx
, name
, desc
, false, &must_chmod
, &acls_set
);
801 int saved_errno
= ret
? errno
: 0;
803 /* If we can't set an acl which we expect to be able to set, try setting
804 the permissions to ctx->mode. Doe to possible inherited permissions,
805 we cannot simply chmod. */
808 ret
= set_acls (ctx
, name
, desc
, true, &must_chmod
, &acls_set
);
820 if (must_chmod
&& ! early_chmod
)
822 int saved_errno
= ret
? errno
: 0;
824 ret
= chmod_or_fchmod (name
, desc
, ctx
->mode
);