1 /* get-permissions.c - get 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. */
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 */
42 # if !HAVE_ACL_TYPE_EXTENDED
43 /* Linux, FreeBSD, IRIX, Tru64 */
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 # else /* HAVE_ACL_TYPE_EXTENDED */
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, ...))
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. */
79 if (HAVE_ACL_GET_FD
&& desc
!= -1)
80 ctx
->acl
= acl_get_fd (desc
);
82 ctx
->acl
= acl_get_file (name
, ACL_TYPE_EXTENDED
);
84 return acl_errno_valid (errno
) ? -1 : 0;
88 #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
90 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
91 of Unixware. The acl() call returns the access and default ACL both
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).
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.) */
112 ret
= facl (desc
, ACE_GETACLCNT
, 0, NULL
);
114 ret
= acl (name
, ACE_GETACLCNT
, 0, NULL
);
117 if (errno
== ENOSYS
|| errno
== EINVAL
)
122 ctx
->ace_count
= ret
;
124 if (ctx
->ace_count
== 0)
127 ctx
->ace_entries
= (ace_t
*) malloc (ctx
->ace_count
* sizeof (ace_t
));
128 if (ctx
->ace_entries
== NULL
)
135 ret
= facl (desc
, ACE_GETACL
, ctx
->ace_count
, ctx
->ace_entries
);
137 ret
= acl (name
, ACE_GETACL
, ctx
->ace_count
, ctx
->ace_entries
);
140 if (errno
== ENOSYS
|| errno
== EINVAL
)
142 free (ctx
->ace_entries
);
143 ctx
->ace_entries
= NULL
;
150 if (ret
<= ctx
->ace_count
)
152 ctx
->ace_count
= ret
;
155 /* Huh? The number of ACL entries has increased since the last call.
157 free (ctx
->ace_entries
);
158 ctx
->ace_entries
= NULL
;
167 ret
= facl (desc
, GETACLCNT
, 0, NULL
);
169 ret
= acl (name
, GETACLCNT
, 0, NULL
);
172 if (errno
== ENOSYS
|| errno
== ENOTSUP
|| errno
== EOPNOTSUPP
)
182 ctx
->entries
= (aclent_t
*) malloc (ctx
->count
* sizeof (aclent_t
));
183 if (ctx
->entries
== NULL
)
190 ret
= facl (desc
, GETACL
, ctx
->count
, ctx
->entries
);
192 ret
= acl (name
, GETACL
, ctx
->count
, ctx
->entries
);
195 if (errno
== ENOSYS
|| errno
== ENOTSUP
|| errno
== EOPNOTSUPP
)
205 if (ret
<= ctx
->count
)
210 /* Huh? The number of ACL entries has increased since the last call.
216 #elif USE_ACL && HAVE_GETACL /* HP-UX */
222 ret
= fgetacl (desc
, NACLENTRIES
, ctx
->entries
);
224 ret
= getacl (name
, NACLENTRIES
, ctx
->entries
);
227 if (errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== ENOTSUP
)
232 else if (ret
> NACLENTRIES
)
233 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
238 ret
= acl ((char *) name
, ACL_GET
, NACLVENTRIES
, ctx
->aclv_entries
);
241 if (errno
== ENOSYS
|| errno
== EOPNOTSUPP
|| errno
== EINVAL
)
246 else if (ret
> NACLVENTRIES
)
247 /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */
249 ctx
->aclv_count
= ret
;
253 #elif USE_ACL && HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */
255 /* TODO (see set_permissions). */
257 #elif USE_ACL && HAVE_STATACL /* older AIX */
262 ret
= fstatacl (desc
, STX_NORMAL
, &ctx
->u
.a
, sizeof ctx
->u
);
264 ret
= statacl ((char *) name
, STX_NORMAL
, &ctx
->u
.a
, sizeof ctx
->u
);
269 #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
272 int ret
= acl ((char *) name
, ACL_GET
, NACLENTRIES
, ctx
->entries
);
275 else if (ret
> NACLENTRIES
)
276 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */