OpenCoverage

file-has-acl.c

Absolute File Name:/home/opencoverage/opencoverage/guest-scripts/coreutils/src/gnulib/lib/file-has-acl.c
Source codeSwitch to Preprocessed file
LineSourceCount
1/* Test whether a file has a nontrivial ACL. -*- coding: utf-8 -*--
2-
3 Copyright (C) 2002-2003, 2005-2018 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 <https://www.gnu.org/licenses/>.-
17-
18 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */-
19-
20/* Without this pragma, gcc 4.7.0 20120126 may suggest that the-
21 file_has_acl function might be candidate for attribute 'const' */-
22#if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__-
23# pragma GCC diagnostic ignored "-Wsuggest-attribute=const"-
24#endif-
25-
26#include <config.h>-
27-
28#include "acl.h"-
29-
30#include "acl-internal.h"-
31-
32#if GETXATTR_WITH_POSIX_ACLS-
33# include <sys/xattr.h>-
34# include <linux/xattr.h>-
35#endif-
36-
37/* Return 1 if NAME has a nontrivial access control list,-
38 0 if ACLs are not supported, or if NAME has no or only a base ACL,-
39 and -1 (setting errno) on error. Note callers can determine-
40 if ACLs are not supported as errno is set in that case also.-
41 SB must be set to the stat buffer of NAME,-
42 obtained through stat() or lstat(). */-
43-
44int-
45file_has_acl (char const *name, struct stat const *sb)-
46{-
47#if USE_ACL-
48 if (! S_ISLNK (sb->st_mode))-
49 {-
50-
51# if GETXATTR_WITH_POSIX_ACLS-
52-
53 ssize_t ret;-
54-
55 ret = getxattr (name, XATTR_NAME_POSIX_ACL_ACCESS, NULL, 0);-
56 if (ret < 0 && errno == ENODATA)-
57 ret = 0;-
58 else if (ret > 0)-
59 return 1;-
60-
61 if (ret == 0 && S_ISDIR (sb->st_mode))-
62 {-
63 ret = getxattr (name, XATTR_NAME_POSIX_ACL_DEFAULT, NULL, 0);-
64 if (ret < 0 && errno == ENODATA)-
65 ret = 0;-
66 else if (ret > 0)-
67 return 1;-
68 }-
69-
70 if (ret < 0)-
71 return - acl_errno_valid (errno);-
72 return ret;-
73-
74# elif HAVE_ACL_GET_FILE-
75-
76 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */-
77 /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */-
78 int ret;-
79-
80 if (HAVE_ACL_EXTENDED_FILE) /* Linux */-
81 {-
82 /* On Linux, acl_extended_file is an optimized function: It only-
83 makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for-
84 ACL_TYPE_DEFAULT. */-
85 ret = acl_extended_file (name);-
86 }-
87 else /* FreeBSD, Mac OS X, IRIX, Tru64 */-
88 {-
89# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */-
90 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)-
91 and acl_get_file (name, ACL_TYPE_DEFAULT)-
92 always return NULL / EINVAL. There is no point in making-
93 these two useless calls. The real ACL is retrieved through-
94 acl_get_file (name, ACL_TYPE_EXTENDED). */-
95 acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED);-
96 if (acl)-
97 {-
98 ret = acl_extended_nontrivial (acl);-
99 acl_free (acl);-
100 }-
101 else-
102 ret = -1;-
103# else /* FreeBSD, IRIX, Tru64 */-
104 acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);-
105 if (acl)-
106 {-
107 int saved_errno;-
108-
109 ret = acl_access_nontrivial (acl);-
110 saved_errno = errno;-
111 acl_free (acl);-
112 errno = saved_errno;-
113# if HAVE_ACL_FREE_TEXT /* Tru64 */-
114 /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always-
115 returns NULL with errno not set. There is no point in-
116 making this call. */-
117# else /* FreeBSD, IRIX */-
118 /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS)-
119 and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory-
120 either both succeed or both fail; it depends on the-
121 file system. Therefore there is no point in making the second-
122 call if the first one already failed. */-
123 if (ret == 0 && S_ISDIR (sb->st_mode))-
124 {-
125 acl = acl_get_file (name, ACL_TYPE_DEFAULT);-
126 if (acl)-
127 {-
128 ret = (0 < acl_entries (acl));-
129 acl_free (acl);-
130 }-
131 else-
132 ret = -1;-
133 }-
134# endif-
135 }-
136 else-
137 ret = -1;-
138# endif-
139 }-
140 if (ret < 0)-
141 return - acl_errno_valid (errno);-
142 return ret;-
143-
144# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */-
145-
146# if defined ACL_NO_TRIVIAL-
147-
148 /* Solaris 10 (newer version), which has additional API declared in-
149 <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,-
150 acl_fromtext, ...). */-
151 return acl_trivial (name);-
152-
153# else /* Solaris, Cygwin, general case */-
154-
155 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions-
156 of Unixware. The acl() call returns the access and default ACL both-
157 at once. */-
158 {-
159 /* Initially, try to read the entries into a stack-allocated buffer.-
160 Use malloc if it does not fit. */-
161 enum-
162 {-
163 alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */-
164 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t))-
165 };-
166 aclent_t buf[alloc_init];-
167 size_t alloc = alloc_init;-
168 aclent_t *entries = buf;-
169 aclent_t *malloced = NULL;-
170 int count;-
171-
172 for (;;)-
173 {-
174 count = acl (name, GETACL, alloc, entries);-
175 if (count < 0 && errno == ENOSPC)-
176 {-
177 /* Increase the size of the buffer. */-
178 free (malloced);-
179 if (alloc > alloc_max / 2)-
180 {-
181 errno = ENOMEM;-
182 return -1;-
183 }-
184 alloc = 2 * alloc; /* <= alloc_max */-
185 entries = malloced =-
186 (aclent_t *) malloc (alloc * sizeof (aclent_t));-
187 if (entries == NULL)-
188 {-
189 errno = ENOMEM;-
190 return -1;-
191 }-
192 continue;-
193 }-
194 break;-
195 }-
196 if (count < 0)-
197 {-
198 if (errno == ENOSYS || errno == ENOTSUP)-
199 ;-
200 else-
201 {-
202 int saved_errno = errno;-
203 free (malloced);-
204 errno = saved_errno;-
205 return -1;-
206 }-
207 }-
208 else if (count == 0)-
209 ;-
210 else-
211 {-
212 /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin-
213 returns only 3 entries for files with no ACL. But this is safe:-
214 If there are more than 4 entries, there cannot be only the-
215 "user::", "group::", "other:", and "mask:" entries. */-
216 if (count > 4)-
217 {-
218 free (malloced);-
219 return 1;-
220 }-
221-
222 if (acl_nontrivial (count, entries))-
223 {-
224 free (malloced);-
225 return 1;-
226 }-
227 }-
228 free (malloced);-
229 }-
230-
231# ifdef ACE_GETACL-
232 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4-
233 file systems (whereas the other ones are used in UFS file systems). */-
234 {-
235 /* Initially, try to read the entries into a stack-allocated buffer.-
236 Use malloc if it does not fit. */-
237 enum-
238 {-
239 alloc_init = 4000 / sizeof (ace_t), /* >= 3 */-
240 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))-
241 };-
242 ace_t buf[alloc_init];-
243 size_t alloc = alloc_init;-
244 ace_t *entries = buf;-
245 ace_t *malloced = NULL;-
246 int count;-
247-
248 for (;;)-
249 {-
250 count = acl (name, ACE_GETACL, alloc, entries);-
251 if (count < 0 && errno == ENOSPC)-
252 {-
253 /* Increase the size of the buffer. */-
254 free (malloced);-
255 if (alloc > alloc_max / 2)-
256 {-
257 errno = ENOMEM;-
258 return -1;-
259 }-
260 alloc = 2 * alloc; /* <= alloc_max */-
261 entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));-
262 if (entries == NULL)-
263 {-
264 errno = ENOMEM;-
265 return -1;-
266 }-
267 continue;-
268 }-
269 break;-
270 }-
271 if (count < 0)-
272 {-
273 if (errno == ENOSYS || errno == EINVAL)-
274 ;-
275 else-
276 {-
277 int saved_errno = errno;-
278 free (malloced);-
279 errno = saved_errno;-
280 return -1;-
281 }-
282 }-
283 else if (count == 0)-
284 ;-
285 else-
286 {-
287 /* In the old (original Solaris 10) convention:-
288 If there are more than 3 entries, there cannot be only the-
289 ACE_OWNER, ACE_GROUP, ACE_OTHER entries.-
290 In the newer Solaris 10 and Solaris 11 convention:-
291 If there are more than 6 entries, there cannot be only the-
292 ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with-
293 NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with-
294 NEW_ACE_ACCESS_DENIED_ACE_TYPE. */-
295 if (count > 6)-
296 {-
297 free (malloced);-
298 return 1;-
299 }-
300-
301 if (acl_ace_nontrivial (count, entries))-
302 {-
303 free (malloced);-
304 return 1;-
305 }-
306 }-
307 free (malloced);-
308 }-
309# endif-
310-
311 return 0;-
312# endif-
313-
314# elif HAVE_GETACL /* HP-UX */-
315-
316 {-
317 struct acl_entry entries[NACLENTRIES];-
318 int count;-
319-
320 count = getacl (name, NACLENTRIES, entries);-
321-
322 if (count < 0)-
323 {-
324 /* ENOSYS is seen on newer HP-UX versions.-
325 EOPNOTSUPP is typically seen on NFS mounts.-
326 ENOTSUP was seen on Quantum StorNext file systems (cvfs). */-
327 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)-
328 ;-
329 else-
330 return -1;-
331 }-
332 else if (count == 0)-
333 return 0;-
334 else /* count > 0 */-
335 {-
336 if (count > NACLENTRIES)-
337 /* If NACLENTRIES cannot be trusted, use dynamic memory-
338 allocation. */-
339 abort ();-
340-
341 /* If there are more than 3 entries, there cannot be only the-
342 (uid,%), (%,gid), (%,%) entries. */-
343 if (count > 3)-
344 return 1;-
345-
346 {-
347 struct stat statbuf;-
348-
349 if (stat (name, &statbuf) < 0)-
350 return -1;-
351-
352 return acl_nontrivial (count, entries);-
353 }-
354 }-
355 }-
356-
357# if HAVE_ACLV_H /* HP-UX >= 11.11 */-
358-
359 {-
360 struct acl entries[NACLVENTRIES];-
361 int count;-
362-
363 count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries);-
364-
365 if (count < 0)-
366 {-
367 /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.-
368 EINVAL is seen on NFS in HP-UX 11.31. */-
369 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)-
370 ;-
371 else-
372 return -1;-
373 }-
374 else if (count == 0)-
375 return 0;-
376 else /* count > 0 */-
377 {-
378 if (count > NACLVENTRIES)-
379 /* If NACLVENTRIES cannot be trusted, use dynamic memory-
380 allocation. */-
381 abort ();-
382-
383 /* If there are more than 4 entries, there cannot be only the-
384 four base ACL entries. */-
385 if (count > 4)-
386 return 1;-
387-
388 return aclv_nontrivial (count, entries);-
389 }-
390 }-
391-
392# endif-
393-
394# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */-
395-
396 acl_type_t type;-
397 char aclbuf[1024];-
398 void *acl = aclbuf;-
399 size_t aclsize = sizeof (aclbuf);-
400 mode_t mode;-
401-
402 for (;;)-
403 {-
404 /* The docs say that type being 0 is equivalent to ACL_ANY, but it-
405 is not true, in AIX 5.3. */-
406 type.u64 = ACL_ANY;-
407 if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)-
408 break;-
409 if (errno == ENOSYS)-
410 return 0;-
411 if (errno != ENOSPC)-
412 {-
413 if (acl != aclbuf)-
414 {-
415 int saved_errno = errno;-
416 free (acl);-
417 errno = saved_errno;-
418 }-
419 return -1;-
420 }-
421 aclsize = 2 * aclsize;-
422 if (acl != aclbuf)-
423 free (acl);-
424 acl = malloc (aclsize);-
425 if (acl == NULL)-
426 {-
427 errno = ENOMEM;-
428 return -1;-
429 }-
430 }-
431-
432 if (type.u64 == ACL_AIXC)-
433 {-
434 int result = acl_nontrivial ((struct acl *) acl);-
435 if (acl != aclbuf)-
436 free (acl);-
437 return result;-
438 }-
439 else if (type.u64 == ACL_NFS4)-
440 {-
441 int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl);-
442 if (acl != aclbuf)-
443 free (acl);-
444 return result;-
445 }-
446 else-
447 {-
448 /* A newer type of ACL has been introduced in the system.-
449 We should better support it. */-
450 if (acl != aclbuf)-
451 free (acl);-
452 errno = EINVAL;-
453 return -1;-
454 }-
455-
456# elif HAVE_STATACL /* older AIX */-
457-
458 union { struct acl a; char room[4096]; } u;-
459-
460 if (statacl ((char *) name, STX_NORMAL, &u.a, sizeof (u)) < 0)-
461 return -1;-
462-
463 return acl_nontrivial (&u.a);-
464-
465# elif HAVE_ACLSORT /* NonStop Kernel */-
466-
467 {-
468 struct acl entries[NACLENTRIES];-
469 int count;-
470-
471 count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);-
472-
473 if (count < 0)-
474 {-
475 if (errno == ENOSYS || errno == ENOTSUP)-
476 ;-
477 else-
478 return -1;-
479 }-
480 else if (count == 0)-
481 return 0;-
482 else /* count > 0 */-
483 {-
484 if (count > NACLENTRIES)-
485 /* If NACLENTRIES cannot be trusted, use dynamic memory-
486 allocation. */-
487 abort ();-
488-
489 /* If there are more than 4 entries, there cannot be only the-
490 four base ACL entries. */-
491 if (count > 4)-
492 return 1;-
493-
494 return acl_nontrivial (count, entries);-
495 }-
496 }-
497-
498# endif-
499 }-
500#endif-
501-
502 return 0;
executed 160 times by 2 tests
Executed by:
  • ls
  • vdir
160
503}-
Source codeSwitch to Preprocessed file

Generated by Squish Coco 4.1.2