1 /* Get permissions of a file. -*- coding: utf-8 -*-
3 Copyright (C) 2002-2003, 2005-2019 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 <https://www.gnu.org/licenses/>.
18 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
25 #include "acl-internal.h"
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. */
33 get_permissions (const char *name
, int desc
, mode_t mode
,
34 struct permission_context
*ctx
)
36 memset (ctx
, 0, sizeof *ctx
);
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, Cygwin >= 2.5 */
42 # if !HAVE_ACL_TYPE_EXTENDED
43 /* Linux, FreeBSD, IRIX, Tru64, Cygwin >= 2.5 */
45 if (HAVE_ACL_GET_FD
&& desc
!= -1)
46 ctx
->acl
= acl_get_fd (desc
);
48 ctx
->acl
= acl_get_file (name
, ACL_TYPE_ACCESS
);
50 return acl_errno_valid (errno
) ? -1 : 0;
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
58 ctx
->default_acl
= acl_get_file (name
, ACL_TYPE_DEFAULT
);
59 if (ctx
->default_acl
== NULL
)
63 # if HAVE_ACL_TYPE_NFS4 /* FreeBSD */
65 /* TODO (see set_permissions). */
69 # else /* HAVE_ACL_TYPE_EXTENDED */
72 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
73 and acl_get_file (name, ACL_TYPE_DEFAULT)
74 always return NULL / EINVAL. You have to use
75 acl_get_file (name, ACL_TYPE_EXTENDED)
76 or acl_get_fd (open (name, ...))
79 acl_set_file (name, ACL_TYPE_ACCESS, acl)
80 and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
81 have the same effect as
82 acl_set_file (name, ACL_TYPE_EXTENDED, acl):
83 Each of these calls sets the file's ACL. */
85 if (HAVE_ACL_GET_FD
&& desc
!= -1)
86 ctx
->acl
= acl_get_fd (desc
);
88 ctx
->acl
= acl_get_file (name
, ACL_TYPE_EXTENDED
);
90 return acl_errno_valid (errno
) ? -1 : 0;
94 #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
96 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
97 of Unixware. The acl() call returns the access and default ACL both
100 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
101 file systems (whereas the other ones are used in UFS file systems).
103 pathconf (name, _PC_ACL_ENABLED)
104 fpathconf (desc, _PC_ACL_ENABLED)
105 that allows us to determine which of the two kinds of ACLs is supported
106 for the given file. But some file systems may implement this call
107 incorrectly, so better not use it.
108 When fetching the source ACL, we simply fetch both ACL types.
109 When setting the destination ACL, we try either ACL types, assuming
110 that the kernel will translate the ACL from one form to the other.
111 (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
112 the description of ENOTSUP.) */
118 ret
= facl (desc
, ACE_GETACLCNT
, 0, NULL
);
120 ret
= acl (name
, ACE_GETACLCNT
, 0, NULL
);
123 if (errno
== ENOSYS
|| errno
== EINVAL
)
128 ctx
->ace_count
= ret
;
130 if (ctx
->ace_count
== 0)
133 ctx
->ace_entries
= (ace_t
*) malloc (ctx
->ace_count
* sizeof (ace_t
));
134 if (ctx
->ace_entries
== NULL
)
141 ret
= facl (desc
, ACE_GETACL
, ctx
->ace_count
, ctx
->ace_entries
);
143 ret
= acl (name
, ACE_GETACL
, ctx
->ace_count
, ctx
->ace_entries
);
146 if (errno
== ENOSYS
|| errno
== EINVAL
)
148 free (ctx
->ace_entries
);
149 ctx
->ace_entries
= NULL
;
156 if (ret
<= ctx
->ace_count
)
158 ctx
->ace_count
= ret
;
161 /* Huh? The number of ACL entries has increased since the last call.
163 free (ctx
->ace_entries
);
164 ctx
->ace_entries
= NULL
;
173 ret
= facl (desc
, GETACLCNT
, 0, NULL
);
175 ret
= acl (name
, GETACLCNT
, 0, NULL
);
178 if (errno
== ENOSYS
|| errno
== ENOTSUP
|| errno
== EOPNOTSUPP
)
188 ctx
->entries
= (aclent_t
*) malloc (ctx
->count
* sizeof (aclent_t
));
189 if (ctx
->entries
== NULL
)
196 ret
= facl (desc
, GETACL
, ctx
->count
, ctx
->entries
);
198 ret
= acl (name
, GETACL
, ctx
->count
, ctx
->entries
);
201 if (errno
== ENOSYS
|| errno
== ENOTSUP
|| errno
== EOPNOTSUPP
)
211 if (ret
<= ctx
->count
)
216 /* Huh? The number of ACL entries has increased since the last call.
222 #elif USE_ACL && HAVE_GETACL /* HP-UX */
228 ret
= fgetacl (desc
, NACLENTRIES
, ctx
->entries
);
230 ret
= getacl (name
, NACLENTRIES
, ctx
->entries
);
233 if (errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== ENOTSUP
)
238 else if (ret
> NACLENTRIES
)
239 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
244 ret
= acl ((char *) name
, ACL_GET
, NACLVENTRIES
, ctx
->aclv_entries
);
247 if (errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== EINVAL
)
252 else if (ret
> NACLVENTRIES
)
253 /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */
255 ctx
->aclv_count
= ret
;
259 #elif USE_ACL && HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */
261 /* TODO (see set_permissions). */
263 #elif USE_ACL && HAVE_STATACL /* older AIX */
268 ret
= fstatacl (desc
, STX_NORMAL
, &ctx
->u
.a
, sizeof ctx
->u
);
270 ret
= statacl ((char *) name
, STX_NORMAL
, &ctx
->u
.a
, sizeof ctx
->u
);
275 #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
278 int ret
= acl ((char *) name
, ACL_GET
, NACLENTRIES
, ctx
->entries
);
281 else if (ret
> NACLENTRIES
)
282 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */