re-mark 1.29b-2 as not yet uploaded (merge madness!)
[debian/tar] / gnu / qcopy-acl.c
1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
3 /* copy-acl.c - copy access control list from one file to another file
4
5    Copyright (C) 2002-2003, 2005-2014 Free Software Foundation, Inc.
6
7    This program is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20    Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible.  */
21
22 #include <config.h>
23
24 #include "acl.h"
25
26 #include "acl-internal.h"
27
28
29 /* Copy access control lists from one file to another. If SOURCE_DESC is
30    a valid file descriptor, use file descriptor operations, else use
31    filename based operations on SRC_NAME. Likewise for DEST_DESC and
32    DST_NAME.
33    If access control lists are not available, fchmod the target file to
34    MODE.  Also sets the non-permission bits of the destination file
35    (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
36    Return 0 if successful.
37    Return -2 and set errno for an error relating to the source file.
38    Return -1 and set errno for an error relating to the destination file.  */
39
40 int
41 qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
42            int dest_desc, mode_t mode)
43 {
44 #if USE_ACL && HAVE_ACL_GET_FILE
45   /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
46   /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
47 # if !HAVE_ACL_TYPE_EXTENDED
48   /* Linux, FreeBSD, IRIX, Tru64 */
49
50   acl_t acl;
51   int ret;
52
53   if (HAVE_ACL_GET_FD && source_desc != -1)
54     acl = acl_get_fd (source_desc);
55   else
56     acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
57   if (acl == NULL)
58     {
59       if (! acl_errno_valid (errno))
60         return qset_acl (dst_name, dest_desc, mode);
61       else
62         return -2;
63     }
64
65   if (HAVE_ACL_SET_FD && dest_desc != -1)
66     ret = acl_set_fd (dest_desc, acl);
67   else
68     ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
69   if (ret != 0)
70     {
71       int saved_errno = errno;
72
73       if (! acl_errno_valid (errno) && !acl_access_nontrivial (acl))
74         {
75           acl_free (acl);
76           return chmod_or_fchmod (dst_name, dest_desc, mode);
77         }
78       else
79         {
80           acl_free (acl);
81           chmod_or_fchmod (dst_name, dest_desc, mode);
82           errno = saved_errno;
83           return -1;
84         }
85     }
86   else
87     acl_free (acl);
88
89   if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
90     {
91       /* We did not call chmod so far, and either the mode and the ACL are
92          separate or special bits are to be set which don't fit into ACLs.  */
93
94       if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
95         return -1;
96     }
97
98   if (S_ISDIR (mode))
99     {
100       acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
101       if (acl == NULL)
102         return -2;
103
104       if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
105         {
106           int saved_errno = errno;
107
108           acl_free (acl);
109           errno = saved_errno;
110           return -1;
111         }
112       else
113         acl_free (acl);
114     }
115   return 0;
116
117 # else /* HAVE_ACL_TYPE_EXTENDED */
118   /* Mac OS X */
119
120   /* On Mac OS X,  acl_get_file (name, ACL_TYPE_ACCESS)
121      and           acl_get_file (name, ACL_TYPE_DEFAULT)
122      always return NULL / EINVAL.  You have to use
123                    acl_get_file (name, ACL_TYPE_EXTENDED)
124      or            acl_get_fd (open (name, ...))
125      to retrieve an ACL.
126      On the other hand,
127                    acl_set_file (name, ACL_TYPE_ACCESS, acl)
128      and           acl_set_file (name, ACL_TYPE_DEFAULT, acl)
129      have the same effect as
130                    acl_set_file (name, ACL_TYPE_EXTENDED, acl):
131      Each of these calls sets the file's ACL.  */
132
133   acl_t acl;
134   int ret;
135
136   if (HAVE_ACL_GET_FD && source_desc != -1)
137     acl = acl_get_fd (source_desc);
138   else
139     acl = acl_get_file (src_name, ACL_TYPE_EXTENDED);
140   if (acl == NULL)
141     {
142       if (!acl_errno_valid (errno))
143         return qset_acl (dst_name, dest_desc, mode);
144       else
145         return -2;
146     }
147
148   if (HAVE_ACL_SET_FD && dest_desc != -1)
149     ret = acl_set_fd (dest_desc, acl);
150   else
151     ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl);
152   if (ret != 0)
153     {
154       int saved_errno = errno;
155
156       if (!acl_errno_valid (saved_errno) && !acl_extended_nontrivial (acl))
157         {
158           acl_free (acl);
159           return chmod_or_fchmod (dst_name, dest_desc, mode);
160         }
161       else
162         {
163           acl_free (acl);
164           chmod_or_fchmod (dst_name, dest_desc, mode);
165           errno = saved_errno;
166           return -1;
167         }
168     }
169   else
170     acl_free (acl);
171
172   /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly.  */
173   return chmod_or_fchmod (dst_name, dest_desc, mode);
174
175 # endif
176
177 #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
178
179   /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
180      of Unixware.  The acl() call returns the access and default ACL both
181      at once.  */
182 # ifdef ACE_GETACL
183   int ace_count;
184   ace_t *ace_entries;
185 # endif
186   int count;
187   aclent_t *entries;
188   int did_chmod;
189   int saved_errno;
190   int ret;
191
192 # ifdef ACE_GETACL
193   /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
194      file systems (whereas the other ones are used in UFS file systems).
195      There is an API
196        pathconf (name, _PC_ACL_ENABLED)
197        fpathconf (desc, _PC_ACL_ENABLED)
198      that allows to determine which of the two kinds of ACLs is supported
199      for the given file.  But some file systems may implement this call
200      incorrectly, so better not use it.
201      When fetching the source ACL, we simply fetch both ACL types.
202      When setting the destination ACL, we try either ACL types, assuming
203      that the kernel will translate the ACL from one form to the other.
204      (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
205      the description of ENOTSUP.)  */
206   for (;;)
207     {
208       ace_count = (source_desc != -1
209                    ? facl (source_desc, ACE_GETACLCNT, 0, NULL)
210                    : acl (src_name, ACE_GETACLCNT, 0, NULL));
211
212       if (ace_count < 0)
213         {
214           if (errno == ENOSYS || errno == EINVAL)
215             {
216               ace_count = 0;
217               ace_entries = NULL;
218               break;
219             }
220           else
221             return -2;
222         }
223
224       if (ace_count == 0)
225         {
226           ace_entries = NULL;
227           break;
228         }
229
230       ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t));
231       if (ace_entries == NULL)
232         {
233           errno = ENOMEM;
234           return -2;
235         }
236
237       ret = (source_desc != -1
238              ? facl (source_desc, ACE_GETACL, ace_count, ace_entries)
239              : acl (src_name, ACE_GETACL, ace_count, ace_entries));
240       if (ret < 0)
241         {
242           free (ace_entries);
243           if (errno == ENOSYS || errno == EINVAL)
244             {
245               ace_count = 0;
246               ace_entries = NULL;
247               break;
248             }
249           else
250             return -2;
251         }
252       if (ret == ace_count)
253         break;
254       /* Huh? The number of ACL entries changed since the last call.
255          Repeat.  */
256     }
257 # endif
258
259   for (;;)
260     {
261       count = (source_desc != -1
262                ? facl (source_desc, GETACLCNT, 0, NULL)
263                : acl (src_name, GETACLCNT, 0, NULL));
264
265       if (count < 0)
266         {
267           if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
268             {
269               count = 0;
270               entries = NULL;
271               break;
272             }
273           else
274             return -2;
275         }
276
277       if (count == 0)
278         {
279           entries = NULL;
280           break;
281         }
282
283       entries = (aclent_t *) malloc (count * sizeof (aclent_t));
284       if (entries == NULL)
285         {
286           errno = ENOMEM;
287           return -2;
288         }
289
290       if ((source_desc != -1
291            ? facl (source_desc, GETACL, count, entries)
292            : acl (src_name, GETACL, count, entries))
293           == count)
294         break;
295       /* Huh? The number of ACL entries changed since the last call.
296          Repeat.  */
297     }
298
299   /* Is there an ACL of either kind?  */
300 # ifdef ACE_GETACL
301   if (ace_count == 0)
302 # endif
303     if (count == 0)
304       return qset_acl (dst_name, dest_desc, mode);
305
306   did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
307   saved_errno = 0; /* the first non-ignorable error code */
308
309   if (!MODE_INSIDE_ACL)
310     {
311       /* On Cygwin, it is necessary to call chmod before acl, because
312          chmod can change the contents of the ACL (in ways that don't
313          change the allowed accesses, but still visible).  */
314       if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
315         saved_errno = errno;
316       did_chmod = 1;
317     }
318
319   /* If both ace_entries and entries are available, try SETACL before
320      ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
321      can.  */
322
323   if (count > 0)
324     {
325       ret = (dest_desc != -1
326              ? facl (dest_desc, SETACL, count, entries)
327              : acl (dst_name, SETACL, count, entries));
328       if (ret < 0 && saved_errno == 0)
329         {
330           saved_errno = errno;
331           if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
332               && !acl_nontrivial (count, entries))
333             saved_errno = 0;
334         }
335       else
336         did_chmod = 1;
337     }
338   free (entries);
339
340 # ifdef ACE_GETACL
341   if (ace_count > 0)
342     {
343       ret = (dest_desc != -1
344              ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries)
345              : acl (dst_name, ACE_SETACL, ace_count, ace_entries));
346       if (ret < 0 && saved_errno == 0)
347         {
348           saved_errno = errno;
349           if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
350               && !acl_ace_nontrivial (ace_count, ace_entries))
351             saved_errno = 0;
352         }
353     }
354   free (ace_entries);
355 # endif
356
357   if (MODE_INSIDE_ACL
358       && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
359     {
360       /* We did not call chmod so far, and either the mode and the ACL are
361          separate or special bits are to be set which don't fit into ACLs.  */
362
363       if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
364         {
365           if (saved_errno == 0)
366             saved_errno = errno;
367         }
368     }
369
370   if (saved_errno)
371     {
372       errno = saved_errno;
373       return -1;
374     }
375   return 0;
376
377 #elif USE_ACL && HAVE_GETACL /* HP-UX */
378
379   struct acl_entry entries[NACLENTRIES];
380   int count;
381 # if HAVE_ACLV_H
382   struct acl aclv_entries[NACLVENTRIES];
383   int aclv_count;
384 # endif
385   int did_chmod;
386   int saved_errno;
387   int ret;
388
389   count = (source_desc != -1
390            ? fgetacl (source_desc, NACLENTRIES, entries)
391            : getacl (src_name, NACLENTRIES, entries));
392
393   if (count < 0)
394     {
395       if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
396         count = 0;
397       else
398         return -2;
399     }
400   else if (count > 0)
401     {
402       if (count > NACLENTRIES)
403         /* If NACLENTRIES cannot be trusted, use dynamic memory allocation.  */
404         abort ();
405     }
406
407 # if HAVE_ACLV_H
408   aclv_count = acl ((char *) src_name, ACL_GET, NACLVENTRIES, aclv_entries);
409
410   if (aclv_count < 0)
411     {
412       if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
413         count = 0;
414       else
415         return -2;
416     }
417   else if (aclv_count > 0)
418     {
419       if (aclv_count > NACLVENTRIES)
420         /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation.  */
421         abort ();
422     }
423 # endif
424
425   if (count == 0)
426 # if HAVE_ACLV_H
427     if (aclv_count == 0)
428 # endif
429       return qset_acl (dst_name, dest_desc, mode);
430
431   did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
432   saved_errno = 0; /* the first non-ignorable error code */
433
434   if (count > 0)
435     {
436       ret = (dest_desc != -1
437              ? fsetacl (dest_desc, count, entries)
438              : setacl (dst_name, count, entries));
439       if (ret < 0 && saved_errno == 0)
440         {
441           saved_errno = errno;
442           if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
443             {
444               struct stat source_statbuf;
445
446               if ((source_desc != -1
447                    ? fstat (source_desc, &source_statbuf)
448                    : stat (src_name, &source_statbuf)) == 0)
449                 {
450                   if (!acl_nontrivial (count, entries, &source_statbuf))
451                     saved_errno = 0;
452                 }
453               else
454                 saved_errno = errno;
455             }
456         }
457       else
458         did_chmod = 1;
459     }
460
461 # if HAVE_ACLV_H
462   if (aclv_count > 0)
463     {
464       ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries);
465       if (ret < 0 && saved_errno == 0)
466         {
467           saved_errno = errno;
468           if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
469             {
470               if (!aclv_nontrivial (aclv_count, aclv_entries))
471                 saved_errno = 0;
472             }
473         }
474       else
475         did_chmod = 1;
476     }
477 # endif
478
479   if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
480     {
481       /* We did not call chmod so far, and special bits are to be set which
482          don't fit into ACLs.  */
483
484       if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
485         {
486           if (saved_errno == 0)
487             saved_errno = errno;
488         }
489     }
490
491   if (saved_errno)
492     {
493       errno = saved_errno;
494       return -1;
495     }
496   return 0;
497
498 #elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */
499
500   /* TODO */
501
502 #elif USE_ACL && HAVE_STATACL /* older AIX */
503
504   union { struct acl a; char room[4096]; } u;
505   int ret;
506
507   if ((source_desc != -1
508        ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u))
509        : statacl (src_name, STX_NORMAL, &u.a, sizeof (u)))
510       < 0)
511     return -2;
512
513   ret = (dest_desc != -1
514          ? fchacl (dest_desc, &u.a, u.a.acl_len)
515          : chacl (dst_name, &u.a, u.a.acl_len));
516   if (ret < 0)
517     {
518       int saved_errno = errno;
519
520       chmod_or_fchmod (dst_name, dest_desc, mode);
521       errno = saved_errno;
522       return -1;
523     }
524
525   /* No need to call chmod_or_fchmod at this point, since the mode bits
526      S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL.  */
527
528   return 0;
529
530 #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
531
532   struct acl entries[NACLENTRIES];
533   int count;
534   int ret;
535
536   count = acl ((char *) src_name, ACL_GET, NACLENTRIES, entries);
537
538   if (count < 0)
539     {
540       if (0)
541         count = 0;
542       else
543         return -2;
544     }
545   else if (count > 0)
546     {
547       if (count > NACLENTRIES)
548         /* If NACLENTRIES cannot be trusted, use dynamic memory allocation.  */
549         abort ();
550     }
551
552   if (count == 0)
553     return qset_acl (dst_name, dest_desc, mode);
554
555   ret = acl ((char *) dst_name, ACL_SET, count, entries);
556   if (ret < 0)
557     {
558       int saved_errno = errno;
559
560       if (0)
561         {
562           if (!acl_nontrivial (count, entries))
563             return chmod_or_fchmod (dst_name, dest_desc, mode);
564         }
565
566       chmod_or_fchmod (dst_name, dest_desc, mode);
567       errno = saved_errno;
568       return -1;
569     }
570
571   if (mode & (S_ISUID | S_ISGID | S_ISVTX))
572     {
573       /* We did not call chmod so far, and either the mode and the ACL are
574          separate or special bits are to be set which don't fit into ACLs.  */
575
576       return chmod_or_fchmod (dst_name, dest_desc, mode);
577     }
578   return 0;
579
580 #else
581
582   return qset_acl (dst_name, dest_desc, mode);
583
584 #endif
585 }