1 /* Set permissions of a file. -*- coding: utf-8 -*-
3 Copyright (C) 2002-2003, 2005-2017 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 */
28 # if HAVE_ACL_GET_FILE && !HAVE_ACL_TYPE_EXTENDED
31 acl_from_mode (mode_t mode
)
33 # if HAVE_ACL_FREE_TEXT /* Tru64 */
34 char acl_text
[] = "u::---,g::---,o::---,";
35 # else /* FreeBSD, IRIX */
36 char acl_text
[] = "u::---,g::---,o::---";
39 if (mode
& S_IRUSR
) acl_text
[ 3] = 'r';
40 if (mode
& S_IWUSR
) acl_text
[ 4] = 'w';
41 if (mode
& S_IXUSR
) acl_text
[ 5] = 'x';
42 if (mode
& S_IRGRP
) acl_text
[10] = 'r';
43 if (mode
& S_IWGRP
) acl_text
[11] = 'w';
44 if (mode
& S_IXGRP
) acl_text
[12] = 'x';
45 if (mode
& S_IROTH
) acl_text
[17] = 'r';
46 if (mode
& S_IWOTH
) acl_text
[18] = 'w';
47 if (mode
& S_IXOTH
) acl_text
[19] = 'x';
49 return acl_from_text (acl_text
);
54 # if HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
56 set_acls_from_mode (const char *name
, int desc
, mode_t mode
, bool *must_chmod
)
59 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
60 file systems (whereas the other ones are used in UFS file systems). */
62 /* The flags in the ace_t structure changed in a binary incompatible way
63 when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
64 How to distinguish the two conventions at runtime?
65 We fetch the existing ACL. In the old convention, usually three ACEs have
66 a_flags = ACE_OWNER / ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400.
67 In the new convention, these values are not used. */
71 /* Initially, try to read the entries into a stack-allocated buffer.
72 Use malloc if it does not fit. */
75 alloc_init
= 4000 / sizeof (ace_t
), /* >= 3 */
76 alloc_max
= MIN (INT_MAX
, SIZE_MAX
/ sizeof (ace_t
))
78 ace_t buf
[alloc_init
];
79 size_t alloc
= alloc_init
;
81 ace_t
*malloced
= NULL
;
87 ? facl (desc
, ACE_GETACL
, alloc
, entries
)
88 : acl (name
, ACE_GETACL
, alloc
, entries
));
89 if (count
< 0 && errno
== ENOSPC
)
91 /* Increase the size of the buffer. */
93 if (alloc
> alloc_max
/ 2)
98 alloc
= 2 * alloc
; /* <= alloc_max */
99 entries
= malloced
= (ace_t
*) malloc (alloc
* sizeof (ace_t
));
117 for (i
= 0; i
< count
; i
++)
118 if (entries
[i
].a_flags
& (OLD_ACE_OWNER
| OLD_ACE_GROUP
| OLD_ACE_OTHER
))
135 /* Running on Solaris 10. */
136 entries
[0].a_type
= OLD_ALLOW
;
137 entries
[0].a_flags
= OLD_ACE_OWNER
;
138 entries
[0].a_who
= 0; /* irrelevant */
139 entries
[0].a_access_mask
= (mode
>> 6) & 7;
140 entries
[1].a_type
= OLD_ALLOW
;
141 entries
[1].a_flags
= OLD_ACE_GROUP
;
142 entries
[1].a_who
= 0; /* irrelevant */
143 entries
[1].a_access_mask
= (mode
>> 3) & 7;
144 entries
[2].a_type
= OLD_ALLOW
;
145 entries
[2].a_flags
= OLD_ACE_OTHER
;
146 entries
[2].a_who
= 0;
147 entries
[2].a_access_mask
= mode
& 7;
152 /* Running on Solaris 10 (newer version) or Solaris 11.
153 The details here were found through "/bin/ls -lvd somefiles". */
154 entries
[0].a_type
= NEW_ACE_ACCESS_DENIED_ACE_TYPE
;
155 entries
[0].a_flags
= NEW_ACE_OWNER
;
156 entries
[0].a_who
= 0; /* irrelevant */
157 entries
[0].a_access_mask
= 0;
158 entries
[1].a_type
= NEW_ACE_ACCESS_ALLOWED_ACE_TYPE
;
159 entries
[1].a_flags
= NEW_ACE_OWNER
;
160 entries
[1].a_who
= 0; /* irrelevant */
161 entries
[1].a_access_mask
= NEW_ACE_WRITE_NAMED_ATTRS
162 | NEW_ACE_WRITE_ATTRIBUTES
164 | NEW_ACE_WRITE_OWNER
;
166 entries
[1].a_access_mask
|= NEW_ACE_READ_DATA
;
168 entries
[0].a_access_mask
|= NEW_ACE_READ_DATA
;
170 entries
[1].a_access_mask
|= NEW_ACE_WRITE_DATA
| NEW_ACE_APPEND_DATA
;
172 entries
[0].a_access_mask
|= NEW_ACE_WRITE_DATA
| NEW_ACE_APPEND_DATA
;
174 entries
[1].a_access_mask
|= NEW_ACE_EXECUTE
;
176 entries
[0].a_access_mask
|= NEW_ACE_EXECUTE
;
177 entries
[2].a_type
= NEW_ACE_ACCESS_DENIED_ACE_TYPE
;
178 entries
[2].a_flags
= NEW_ACE_GROUP
| NEW_ACE_IDENTIFIER_GROUP
;
179 entries
[2].a_who
= 0; /* irrelevant */
180 entries
[2].a_access_mask
= 0;
181 entries
[3].a_type
= NEW_ACE_ACCESS_ALLOWED_ACE_TYPE
;
182 entries
[3].a_flags
= NEW_ACE_GROUP
| NEW_ACE_IDENTIFIER_GROUP
;
183 entries
[3].a_who
= 0; /* irrelevant */
184 entries
[3].a_access_mask
= 0;
186 entries
[3].a_access_mask
|= NEW_ACE_READ_DATA
;
188 entries
[2].a_access_mask
|= NEW_ACE_READ_DATA
;
190 entries
[3].a_access_mask
|= NEW_ACE_WRITE_DATA
| NEW_ACE_APPEND_DATA
;
192 entries
[2].a_access_mask
|= NEW_ACE_WRITE_DATA
| NEW_ACE_APPEND_DATA
;
194 entries
[3].a_access_mask
|= NEW_ACE_EXECUTE
;
196 entries
[2].a_access_mask
|= NEW_ACE_EXECUTE
;
197 entries
[4].a_type
= NEW_ACE_ACCESS_DENIED_ACE_TYPE
;
198 entries
[4].a_flags
= NEW_ACE_EVERYONE
;
199 entries
[4].a_who
= 0;
200 entries
[4].a_access_mask
= NEW_ACE_WRITE_NAMED_ATTRS
201 | NEW_ACE_WRITE_ATTRIBUTES
203 | NEW_ACE_WRITE_OWNER
;
204 entries
[5].a_type
= NEW_ACE_ACCESS_ALLOWED_ACE_TYPE
;
205 entries
[5].a_flags
= NEW_ACE_EVERYONE
;
206 entries
[5].a_who
= 0;
207 entries
[5].a_access_mask
= NEW_ACE_READ_NAMED_ATTRS
208 | NEW_ACE_READ_ATTRIBUTES
210 | NEW_ACE_SYNCHRONIZE
;
212 entries
[5].a_access_mask
|= NEW_ACE_READ_DATA
;
214 entries
[4].a_access_mask
|= NEW_ACE_READ_DATA
;
216 entries
[5].a_access_mask
|= NEW_ACE_WRITE_DATA
| NEW_ACE_APPEND_DATA
;
218 entries
[4].a_access_mask
|= NEW_ACE_WRITE_DATA
| NEW_ACE_APPEND_DATA
;
220 entries
[5].a_access_mask
|= NEW_ACE_EXECUTE
;
222 entries
[4].a_access_mask
|= NEW_ACE_EXECUTE
;
226 ret
= facl (desc
, ACE_SETACL
, count
, entries
);
228 ret
= acl (name
, ACE_SETACL
, count
, entries
);
229 if (ret
< 0 && errno
!= EINVAL
&& errno
!= ENOTSUP
)
247 entries
[0].a_type
= USER_OBJ
;
248 entries
[0].a_id
= 0; /* irrelevant */
249 entries
[0].a_perm
= (mode
>> 6) & 7;
250 entries
[1].a_type
= GROUP_OBJ
;
251 entries
[1].a_id
= 0; /* irrelevant */
252 entries
[1].a_perm
= (mode
>> 3) & 7;
253 entries
[2].a_type
= OTHER_OBJ
;
255 entries
[2].a_perm
= mode
& 7;
258 ret
= facl (desc
, SETACL
,
259 sizeof (entries
) / sizeof (aclent_t
), entries
);
261 ret
= acl (name
, SETACL
,
262 sizeof (entries
) / sizeof (aclent_t
), entries
);
265 if (errno
== ENOSYS
|| errno
== EOPNOTSUPP
)
276 # elif HAVE_GETACL /* HP-UX */
278 context_acl_from_mode (struct permission_context
*ctx
, const char *name
, int desc
)
284 ret
= fstat (desc
, &statbuf
);
286 ret
= stat (name
, &statbuf
);
290 ctx
->entries
[0].uid
= statbuf
.st_uid
;
291 ctx
->entries
[0].gid
= ACL_NSGROUP
;
292 ctx
->entries
[0].mode
= (ctx
->mode
>> 6) & 7;
293 ctx
->entries
[1].uid
= ACL_NSUSER
;
294 ctx
->entries
[1].gid
= statbuf
.st_gid
;
295 ctx
->entries
[1].mode
= (ctx
->mode
>> 3) & 7;
296 ctx
->entries
[2].uid
= ACL_NSUSER
;
297 ctx
->entries
[2].gid
= ACL_NSGROUP
;
298 ctx
->entries
[2].mode
= ctx
->mode
& 7;
303 # if HAVE_ACLV_H /* HP-UX >= 11.11 */
305 context_aclv_from_mode (struct permission_context
*ctx
)
309 ctx
->aclv_entries
[0].a_type
= USER_OBJ
;
310 ctx
->aclv_entries
[0].a_id
= 0; /* irrelevant */
311 ctx
->aclv_entries
[0].a_perm
= (ctx
->mode
>> 6) & 7;
312 ctx
->aclv_entries
[1].a_type
= GROUP_OBJ
;
313 ctx
->aclv_entries
[1].a_id
= 0; /* irrelevant */
314 ctx
->aclv_entries
[1].a_perm
= (ctx
->mode
>> 3) & 7;
315 ctx
->aclv_entries
[2].a_type
= CLASS_OBJ
;
316 ctx
->aclv_entries
[2].a_id
= 0;
317 ctx
->aclv_entries
[2].a_perm
= (ctx
->mode
>> 3) & 7;
318 ctx
->aclv_entries
[3].a_type
= OTHER_OBJ
;
319 ctx
->aclv_entries
[3].a_id
= 0;
320 ctx
->aclv_entries
[3].a_perm
= ctx
->mode
& 7;
323 ret
= aclsort (ctx
->aclv_count
, 1, ctx
->aclv_entries
);
330 # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
332 set_acls_from_mode (const char *name
, int desc
, mode_t mode
, bool *must_chmod
)
334 acl_type_list_t types
;
335 size_t types_size
= sizeof (types
);
338 if (aclx_gettypes (name
, &types
, &types_size
) < 0
339 || types
.num_entries
== 0)
345 /* XXX Do we need to clear all types of ACLs for the given file, or is it
346 sufficient to clear the first one? */
347 type
= types
.entries
[0];
348 if (type
.u64
== ACL_AIXC
)
350 union { struct acl a
; char room
[128]; } u
;
353 u
.a
.acl_len
= (char *) &u
.a
.acl_ext
[0] - (char *) &u
.a
; /* no entries */
354 u
.a
.acl_mode
= mode
& ~(S_IXACL
| 0777);
355 u
.a
.u_access
= (mode
>> 6) & 7;
356 u
.a
.g_access
= (mode
>> 3) & 7;
357 u
.a
.o_access
= mode
& 7;
360 ret
= aclx_fput (desc
, SET_ACL
| SET_MODE_S_BITS
,
361 type
, &u
.a
, u
.a
.acl_len
, mode
);
363 ret
= aclx_put (name
, SET_ACL
| SET_MODE_S_BITS
,
364 type
, &u
.a
, u
.a
.acl_len
, mode
);
365 if (!(ret
< 0 && errno
== ENOSYS
))
368 else if (type
.u64
== ACL_NFS4
)
370 union { nfs4_acl_int_t a
; char room
[128]; } u
;
374 u
.a
.aclVersion
= NFS4_ACL_INT_STRUCT_VERSION
;
376 ace
= &u
.a
.aclEntry
[0];
378 ace
->flags
= ACE4_ID_SPECIAL
;
379 ace
->aceWho
.special_whoid
= ACE4_WHO_OWNER
;
380 ace
->aceType
= ACE4_ACCESS_ALLOWED_ACE_TYPE
;
383 (mode
& 0400 ? ACE4_READ_DATA
| ACE4_LIST_DIRECTORY
: 0)
385 ? ACE4_WRITE_DATA
| ACE4_ADD_FILE
| ACE4_APPEND_DATA
386 | ACE4_ADD_SUBDIRECTORY
388 | (mode
& 0100 ? ACE4_EXECUTE
: 0);
389 ace
->aceWhoString
[0] = '\0';
390 ace
->entryLen
= (char *) &ace
->aceWhoString
[4] - (char *) ace
;
391 ace
= (nfs4_ace_int_t
*) (char *) &ace
->aceWhoString
[4];
395 ace
->flags
= ACE4_ID_SPECIAL
;
396 ace
->aceWho
.special_whoid
= ACE4_WHO_GROUP
;
397 ace
->aceType
= ACE4_ACCESS_ALLOWED_ACE_TYPE
;
400 (mode
& 0040 ? ACE4_READ_DATA
| ACE4_LIST_DIRECTORY
: 0)
402 ? ACE4_WRITE_DATA
| ACE4_ADD_FILE
| ACE4_APPEND_DATA
403 | ACE4_ADD_SUBDIRECTORY
405 | (mode
& 0010 ? ACE4_EXECUTE
: 0);
406 ace
->aceWhoString
[0] = '\0';
407 ace
->entryLen
= (char *) &ace
->aceWhoString
[4] - (char *) ace
;
408 ace
= (nfs4_ace_int_t
*) (char *) &ace
->aceWhoString
[4];
412 ace
->flags
= ACE4_ID_SPECIAL
;
413 ace
->aceWho
.special_whoid
= ACE4_WHO_EVERYONE
;
414 ace
->aceType
= ACE4_ACCESS_ALLOWED_ACE_TYPE
;
417 (mode
& 0004 ? ACE4_READ_DATA
| ACE4_LIST_DIRECTORY
: 0)
419 ? ACE4_WRITE_DATA
| ACE4_ADD_FILE
| ACE4_APPEND_DATA
420 | ACE4_ADD_SUBDIRECTORY
422 | (mode
& 0001 ? ACE4_EXECUTE
: 0);
423 ace
->aceWhoString
[0] = '\0';
424 ace
->entryLen
= (char *) &ace
->aceWhoString
[4] - (char *) ace
;
425 ace
= (nfs4_ace_int_t
*) (char *) &ace
->aceWhoString
[4];
428 u
.a
.aclLength
= (char *) ace
- (char *) &u
.a
;
431 ret
= aclx_fput (desc
, SET_ACL
| SET_MODE_S_BITS
,
432 type
, &u
.a
, u
.a
.aclLength
, mode
);
434 ret
= aclx_put (name
, SET_ACL
| SET_MODE_S_BITS
,
435 type
, &u
.a
, u
.a
.aclLength
, mode
);
436 if (!(ret
< 0 && errno
== ENOSYS
))
444 # elif HAVE_STATACL /* older AIX */
446 context_acl_from_mode (struct permission_context
*ctx
)
448 ctx
->u
.a
.acl_len
= (char *) &ctx
->u
.a
.acl_ext
[0] - (char *) &ctx
->u
.a
; /* no entries */
449 ctx
->u
.a
.acl_mode
= ctx
->mode
& ~(S_IXACL
| 0777);
450 ctx
->u
.a
.u_access
= (ctx
->mode
>> 6) & 7;
451 ctx
->u
.a
.g_access
= (ctx
->mode
>> 3) & 7;
452 ctx
->u
.a
.o_access
= ctx
->mode
& 7;
457 # elif HAVE_ACLSORT /* NonStop Kernel */
459 context_acl_from_mode (struct permission_context
*ctx
)
463 ctx
->entries
[0].a_type
= USER_OBJ
;
464 ctx
->entries
[0].a_id
= 0; /* irrelevant */
465 ctx
->entries
[0].a_perm
= (ctx
->mode
>> 6) & 7;
466 ctx
->entries
[1].a_type
= GROUP_OBJ
;
467 ctx
->entries
[1].a_id
= 0; /* irrelevant */
468 ctx
->entries
[1].a_perm
= (ctx
->mode
>> 3) & 7;
469 ctx
->entries
[2].a_type
= CLASS_OBJ
;
470 ctx
->entries
[2].a_id
= 0;
471 ctx
->entries
[2].a_perm
= (ctx
->mode
>> 3) & 7;
472 ctx
->entries
[3].a_type
= OTHER_OBJ
;
473 ctx
->entries
[3].a_id
= 0;
474 ctx
->entries
[3].a_perm
= ctx
->mode
& 7;
477 ret
= aclsort (ctx
->count
, 1, entries
);
485 set_acls (struct permission_context
*ctx
, const char *name
, int desc
,
486 int from_mode
, bool *must_chmod
, bool *acls_set
)
490 # if HAVE_ACL_GET_FILE
491 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
492 /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
493 # if !HAVE_ACL_TYPE_EXTENDED
494 /* Linux, FreeBSD, IRIX, Tru64 */
496 # ifndef HAVE_ACL_FROM_TEXT
497 # error Must have acl_from_text (see POSIX 1003.1e draft 17).
499 # ifndef HAVE_ACL_DELETE_DEF_FILE
500 # error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
503 if (! ctx
->acls_not_supported
)
505 if (ret
== 0 && from_mode
)
509 ctx
->acl
= acl_from_mode (ctx
->mode
);
510 if (ctx
->acl
== NULL
)
514 if (ret
== 0 && ctx
->acl
)
516 if (HAVE_ACL_SET_FD
&& desc
!= -1)
517 ret
= acl_set_fd (desc
, ctx
->acl
);
519 ret
= acl_set_file (name
, ACL_TYPE_ACCESS
, ctx
->acl
);
522 if (! acl_errno_valid (errno
))
524 ctx
->acls_not_supported
= true;
525 if (from_mode
|| acl_access_nontrivial (ctx
->acl
) == 0)
532 if (S_ISDIR(ctx
->mode
))
534 if (! from_mode
&& ctx
->default_acl
&&
535 acl_default_nontrivial (ctx
->default_acl
))
536 ret
= acl_set_file (name
, ACL_TYPE_DEFAULT
,
539 ret
= acl_delete_def_file (name
);
545 # if HAVE_ACL_TYPE_NFS4 /* FreeBSD */
547 /* File systems either support POSIX ACLs (for example, ufs) or NFS4 ACLs
548 (for example, zfs). */
550 /* TODO: Implement setting ACLs once get_permissions() reads them. */
554 # else /* HAVE_ACL_TYPE_EXTENDED */
557 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
558 and acl_get_file (name, ACL_TYPE_DEFAULT)
559 always return NULL / EINVAL. You have to use
560 acl_get_file (name, ACL_TYPE_EXTENDED)
561 or acl_get_fd (open (name, ...))
564 acl_set_file (name, ACL_TYPE_ACCESS, acl)
565 and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
566 have the same effect as
567 acl_set_file (name, ACL_TYPE_EXTENDED, acl):
568 Each of these calls sets the file's ACL. */
570 if (ctx
->acl
== NULL
)
574 /* Remove ACLs if the file has ACLs. */
575 if (HAVE_ACL_GET_FD
&& desc
!= -1)
576 acl
= acl_get_fd (desc
);
578 acl
= acl_get_file (name
, ACL_TYPE_EXTENDED
);
586 if (HAVE_ACL_SET_FD
&& desc
!= -1)
587 ret
= acl_set_fd (desc
, acl
);
589 ret
= acl_set_file (name
, ACL_TYPE_EXTENDED
, acl
);
598 if (HAVE_ACL_SET_FD
&& desc
!= -1)
599 ret
= acl_set_fd (desc
, ctx
->acl
);
601 ret
= acl_set_file (name
, ACL_TYPE_EXTENDED
, ctx
->acl
);
604 if (! acl_errno_valid (errno
)
605 && ! acl_extended_nontrivial (ctx
->acl
))
613 # elif defined GETACL /* Solaris, Cygwin, not HP-UX */
615 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
616 of Unixware. The acl() call returns the access and default ACL both
619 /* If both ace_entries and entries are available, try SETACL before
620 ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
624 return set_acls_from_mode (name
, desc
, ctx
->mode
, must_chmod
);
626 if (ret
== 0 && ctx
->count
)
629 ret
= facl (desc
, SETACL
, ctx
->count
, ctx
->entries
);
631 ret
= acl (name
, SETACL
, ctx
->count
, ctx
->entries
);
634 if ((errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== EINVAL
)
635 && acl_nontrivial (ctx
->count
, ctx
->entries
) == 0)
643 if (ret
== 0 && ctx
->ace_count
)
646 ret
= facl (desc
, ACE_SETACL
, ctx
->ace_count
, ctx
->ace_entries
);
648 ret
= acl (name
, ACE_SETACL
, ctx
->ace_count
, ctx
->ace_entries
);
651 if ((errno
== ENOSYS
|| errno
== EINVAL
|| errno
== ENOTSUP
)
652 && acl_ace_nontrivial (ctx
->ace_count
, ctx
->ace_entries
) == 0)
660 # elif HAVE_GETACL /* HP-UX */
663 ret
= context_acl_from_mode (ctx
, name
, desc
);
665 if (ret
== 0 && ctx
->count
> 0)
668 ret
= fsetacl (desc
, ctx
->count
, ctx
->entries
);
670 ret
= setacl (name
, ctx
->count
, ctx
->entries
);
673 if ((errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== ENOTSUP
)
674 && (from_mode
|| !acl_nontrivial (ctx
->count
, ctx
->entries
)))
683 ret
= context_aclv_from_mode (ctx
);
685 if (ret
== 0 && ctx
->aclv_count
> 0)
687 ret
= acl ((char *) name
, ACL_SET
, ctx
->aclv_count
, ctx
->aclv_entries
);
690 if ((errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== EINVAL
)
691 && (from_mode
|| !aclv_nontrivial (ctx
->aclv_count
, ctx
->aclv_entries
)))
699 # elif HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */
701 /* TODO: Implement setting ACLs once get_permissions() reads them. */
704 ret
= set_acls_from_mode (name
, desc
, mode
, must_chmod
);
706 # elif HAVE_STATACL /* older AIX */
709 ret
= context_acl_from_mode (ctx
);
711 if (ret
== 0 && ctx
->have_u
)
714 ret
= fchacl (desc
, &ctx
->u
.a
, ctx
->u
.a
.acl_len
);
716 ret
= chacl ((char *) name
, &ctx
->u
.a
, ctx
->u
.a
.acl_len
);
719 if (errno
== ENOSYS
&& from_mode
)
726 # elif HAVE_ACLSORT /* NonStop Kernel */
729 ret
= context_acl_from_mode (ctx
);
731 if (ret
== 0 && ctx
->count
)
733 ret
= acl ((char *) name
, ACL_SET
, ctx
->count
, ctx
->entries
);
736 if (!acl_nontrivial (ctx
->count
, ctx
->entries
))
753 /* If DESC is a valid file descriptor use fchmod to change the
754 file's mode to MODE on systems that have fchmod. On systems
755 that don't have fchmod and if DESC is invalid, use chmod on
757 Return 0 if successful. Return -1 and set errno upon failure. */
760 chmod_or_fchmod (const char *name
, int desc
, mode_t mode
)
762 if (HAVE_FCHMOD
&& desc
!= -1)
763 return fchmod (desc
, mode
);
765 return chmod (name
, mode
);
768 /* Set the permissions in CTX on a file. If DESC is a valid file descriptor,
769 use file descriptor operations, else use filename based operations on NAME.
770 If access control lists are not available, fchmod the target file to the
771 mode in CTX. Also sets the non-permission bits of the destination file
772 (S_ISUID, S_ISGID, S_ISVTX) to those from the mode in CTX if any are set.
773 Return 0 if successful. Return -1 and set errno upon failure. */
776 set_permissions (struct permission_context
*ctx
, const char *name
, int desc
)
778 bool acls_set _GL_UNUSED
= false;
780 bool must_chmod
= false;
786 /* There is no need to call chmod_or_fchmod, since the mode
787 bits S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */
791 /* All other platforms */
792 /* On Cygwin, it is necessary to call chmod before acl, because
793 chmod can change the contents of the ACL (in ways that don't
794 change the allowed accesses, but still visible). */
796 early_chmod
= (! MODE_INSIDE_ACL
|| (ctx
->mode
& (S_ISUID
| S_ISGID
| S_ISVTX
)));
806 ret
= chmod_or_fchmod (name
, desc
, ctx
->mode
);
812 ret
= set_acls (ctx
, name
, desc
, false, &must_chmod
, &acls_set
);
815 int saved_errno
= ret
? errno
: 0;
817 /* If we can't set an acl which we expect to be able to set, try setting
818 the permissions to ctx->mode. Due to possible inherited permissions,
819 we cannot simply chmod. */
821 ret
= set_acls (ctx
, name
, desc
, true, &must_chmod
, &acls_set
);
833 if (must_chmod
&& ! early_chmod
)
835 int saved_errno
= ret
? errno
: 0;
837 ret
= chmod_or_fchmod (name
, desc
, ctx
->mode
);