]> code.delx.au - gnu-emacs/blob - lib/get-permissions.c
Merge from origin/emacs-24
[gnu-emacs] / lib / get-permissions.c
1 /* get-permissions.c - get permissions of a file
2
3 Copyright (C) 2002-2003, 2005-2015 Free Software Foundation, Inc.
4
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.
9
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.
14
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/>.
17
18 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
19
20 #include <config.h>
21
22 #include <string.h>
23 #include "acl.h"
24
25 #include "acl-internal.h"
26
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. */
31
32 int
33 get_permissions (const char *name, int desc, mode_t mode,
34 struct permission_context *ctx)
35 {
36 memset (ctx, 0, sizeof(*ctx));
37 ctx->mode = mode;
38
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 */
44
45 if (HAVE_ACL_GET_FD && desc != -1)
46 ctx->acl = acl_get_fd (desc);
47 else
48 ctx->acl = acl_get_file (name, ACL_TYPE_ACCESS);
49 if (ctx->acl == NULL)
50 return acl_errno_valid (errno) ? -1 : 0;
51
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
54 file mode. */
55
56 if (S_ISDIR (mode))
57 {
58 ctx->default_acl = acl_get_file (name, ACL_TYPE_DEFAULT);
59 if (ctx->default_acl == NULL)
60 return -1;
61 }
62
63 # else /* HAVE_ACL_TYPE_EXTENDED */
64 /* Mac OS X */
65
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, ...))
71 to retrieve an ACL.
72 On the other hand,
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. */
78
79 if (HAVE_ACL_GET_FD && desc != -1)
80 ctx->acl = acl_get_fd (desc);
81 else
82 ctx->acl = acl_get_file (name, ACL_TYPE_EXTENDED);
83 if (ctx->acl == NULL)
84 return acl_errno_valid (errno) ? -1 : 0;
85
86 # endif
87
88 #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
89
90 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
91 of Unixware. The acl() call returns the access and default ACL both
92 at once. */
93 # ifdef ACE_GETACL
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).
96 There is an API
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.) */
107 for (;;)
108 {
109 int ret;
110
111 if (desc != -1)
112 ret = facl (desc, ACE_GETACLCNT, 0, NULL);
113 else
114 ret = acl (name, ACE_GETACLCNT, 0, NULL);
115 if (ret < 0)
116 {
117 if (errno == ENOSYS || errno == EINVAL)
118 ret = 0;
119 else
120 return -1;
121 }
122 ctx->ace_count = ret;
123
124 if (ctx->ace_count == 0)
125 break;
126
127 ctx->ace_entries = (ace_t *) malloc (ctx->ace_count * sizeof (ace_t));
128 if (ctx->ace_entries == NULL)
129 {
130 errno = ENOMEM;
131 return -1;
132 }
133
134 if (desc != -1)
135 ret = facl (desc, ACE_GETACL, ctx->ace_count, ctx->ace_entries);
136 else
137 ret = acl (name, ACE_GETACL, ctx->ace_count, ctx->ace_entries);
138 if (ret < 0)
139 {
140 if (errno == ENOSYS || errno == EINVAL)
141 {
142 free (ctx->ace_entries);
143 ctx->ace_entries = NULL;
144 ctx->ace_count = 0;
145 break;
146 }
147 else
148 return -1;
149 }
150 if (ret <= ctx->ace_count)
151 {
152 ctx->ace_count = ret;
153 break;
154 }
155 /* Huh? The number of ACL entries has increased since the last call.
156 Repeat. */
157 free (ctx->ace_entries);
158 ctx->ace_entries = NULL;
159 }
160 # endif
161
162 for (;;)
163 {
164 int ret;
165
166 if (desc != -1)
167 ret = facl (desc, GETACLCNT, 0, NULL);
168 else
169 ret = acl (name, GETACLCNT, 0, NULL);
170 if (ret < 0)
171 {
172 if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
173 ret = 0;
174 else
175 return -1;
176 }
177 ctx->count = ret;
178
179 if (ctx->count == 0)
180 break;
181
182 ctx->entries = (aclent_t *) malloc (ctx->count * sizeof (aclent_t));
183 if (ctx->entries == NULL)
184 {
185 errno = ENOMEM;
186 return -1;
187 }
188
189 if (desc != -1)
190 ret = facl (desc, GETACL, ctx->count, ctx->entries);
191 else
192 ret = acl (name, GETACL, ctx->count, ctx->entries);
193 if (ret < 0)
194 {
195 if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
196 {
197 free (ctx->entries);
198 ctx->entries = NULL;
199 ctx->count = 0;
200 break;
201 }
202 else
203 return -1;
204 }
205 if (ret <= ctx->count)
206 {
207 ctx->count = ret;
208 break;
209 }
210 /* Huh? The number of ACL entries has increased since the last call.
211 Repeat. */
212 free (ctx->entries);
213 ctx->entries = NULL;
214 }
215
216 #elif USE_ACL && HAVE_GETACL /* HP-UX */
217
218 int ret;
219
220 if (desc != -1)
221 ret = fgetacl (desc, NACLENTRIES, ctx->entries);
222 else
223 ret = getacl (name, NACLENTRIES, ctx->entries);
224 if (ret < 0)
225 {
226 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
227 ret = 0;
228 else
229 return -1;
230 }
231 else if (ret > NACLENTRIES)
232 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
233 abort ();
234 ctx->count = ret;
235
236 # if HAVE_ACLV_H
237 ret = acl ((char *) name, ACL_GET, NACLVENTRIES, ctx->aclv_entries);
238 if (ret < 0)
239 {
240 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
241 ret = 0;
242 else
243 return -2;
244 }
245 else if (ret > NACLVENTRIES)
246 /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */
247 abort ();
248 ctx->aclv_count = ret;
249 # endif
250
251 #elif USE_ACL && HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */
252
253 /* TODO (see set_permissions). */
254
255 #elif USE_ACL && HAVE_STATACL /* older AIX */
256
257 if (desc != -1)
258 ret = fstatacl (desc, STX_NORMAL, &ctx->u.a, sizeof (ctx->u));
259 else
260 ret = statacl (name, STX_NORMAL, &ctx->u.a, sizeof (ctx->u));
261 if (ret == 0)
262 ctx->have_u = true;
263
264 #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
265
266 int ret;
267
268 ret = acl ((char *) name, ACL_GET, NACLENTRIES, ctx->entries);
269 if (ret < 0)
270 return -1;
271 else if (ret > NACLENTRIES)
272 /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
273 abort ();
274 ctx->count = ret;
275
276 #endif
277
278 return 0;
279
280 }