2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2010 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Functions to handle ACLs for bacula.
31 * Currently we support the following OSes:
32 * - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
38 * - Solaris (POSIX and NFSv4/ZFS acls)
41 * Next to OS specific acls we support AFS acls using the pioctl interface.
43 * We handle two different types of ACLs: access and default ACLS.
44 * On most systems that support default ACLs they only apply to directories.
46 * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
47 * independently, while others (eg. Solaris) provide both in one call.
49 * The Filed saves ACLs in their native format and uses different streams
50 * for all different platforms. Currently we only allow ACLs to be restored
51 * which were saved in the native format of the platform they are extracted
52 * on. Later on we might add conversion functions for mapping from one
53 * platform to an other or allow restores of systems that use the same
56 * Its also interesting to see what the exact format of acl text is on
57 * certain platforms and if they use they same encoding we might allow
58 * different platform streams to be decoded on an other similar platform.
60 * Original written by Preben 'Peppe' Guldberg, December MMIV
61 * Major rewrite by Marco van Wieringen, November MMVIII
67 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
69 * Entry points when compiled without support for ACLs or on an unsupported platform.
71 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
73 return bacl_exit_fatal;
76 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
78 return bacl_exit_fatal;
82 * Send an ACL stream to the SD.
84 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
86 BSOCK *sd = jcr->store_bsock;
88 #ifdef FD_NO_SEND_TEST
95 if (jcr->acl_data->content_length <= 0) {
102 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
103 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
105 return bacl_exit_fatal;
109 * Send the buffer to the storage deamon
111 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->content);
113 sd->msg = jcr->acl_data->content;
114 sd->msglen = jcr->acl_data->content_length + 1;
118 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
120 return bacl_exit_fatal;
123 jcr->JobBytes += sd->msglen;
125 if (!sd->signal(BNET_EOD)) {
126 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
128 return bacl_exit_fatal;
131 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
136 * First the native ACLs.
138 #if defined(HAVE_ACL)
139 #if defined(HAVE_AIX_OS)
141 #if defined(HAVE_EXTENDED_ACL)
143 #include <sys/access.h>
146 static bool acl_is_trivial(struct acl *acl)
148 return (acl_last(acl) != acl->acl_ext ? false : true);
151 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
153 return (acl->aclEntryN > 0 ? false : true);
157 * Define the supported ACL streams for this OS
159 static int os_access_acl_streams[3] = { STREAM_ACL_AIX_TEXT, STREAM_ACL_AIX_AIXC, STREAM_ACL_AIX_NFS4 };
160 static int os_default_acl_streams[1] = { -1 };
162 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
167 size_t aclsize, acltxtsize;
168 bacl_exit_code retval = bacl_exit_error;
169 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
172 * First see how big the buffers should be.
175 if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, NULL) < 0) {
178 retval = bacl_exit_ok;
181 Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
182 jcr->last_fname, be.bstrerror());
183 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
184 jcr->last_fname, be.bstrerror());
190 * Make sure the buffers are big enough.
192 aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
195 * Retrieve the ACL info.
197 if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
200 retval = bacl_exit_ok;
203 Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
204 jcr->last_fname, be.bstrerror());
205 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
206 jcr->last_fname, be.bstrerror());
212 * See if the acl is non trivial.
216 if (acl_is_trivial((struct acl *)aclbuf)) {
217 retval = bacl_exit_ok;
222 if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
223 retval = bacl_exit_ok;
228 Mmsg2(jcr->errmsg, _("Unknown acl type encountered on file \"%s\": %ld\n"),
229 jcr->last_fname, type.u64);
230 Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
231 jcr->last_fname, type.u64);
236 * We have a non-trivial acl lets convert it into some ASCII form.
238 acltxtsize = sizeof_pool_memory(jcr->acl_data->content);
239 if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
240 aclsize, type, jcr->last_fname, 0) < 0) {
244 * Our buffer is not big enough, acltxtsize should be updated with the value
245 * the aclx_printStr really need. So we increase the buffer and try again.
247 jcr->acl_data->content = check_pool_memory_size(jcr->acl_data->content, acltxtsize + 1);
248 if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
249 aclsize, type, jcr->last_fname, 0) < 0) {
250 Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
252 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
253 jcr->last_fname, type.u64);
258 Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
260 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
261 jcr->last_fname, type.u64);
266 jcr->acl_data->content_length = strlen(jcr->acl_data->content) + 1;
269 retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
271 retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
275 free_pool_memory(aclbuf);
280 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
286 bacl_exit_code retval = bacl_exit_error;
287 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
290 case STREAM_ACL_AIX_TEXT:
292 * Handle the old stream using the old system call for now.
294 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
295 retval = bacl_exit_error;
298 retval = bacl_exit_ok;
300 case STREAM_ACL_AIX_AIXC:
303 case STREAM_ACL_AIX_NFS4:
308 } /* end switch (stream) */
311 * Set the acl buffer to an initial size. For now we set it
312 * to the same size as the ASCII representation.
314 aclbuf = check_pool_memory_size(aclbuf, jcr->acl_data->content_length);
315 aclsize = jcr->acl_data->content_length;
316 if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) < 0) {
320 * The buffer isn't big enough. The man page doesn't say that aclsize
321 * is updated to the needed size as what is done with aclx_printStr.
322 * So for now we try to increase the buffer a maximum of 3 times
323 * and retry the conversion.
325 for (cnt = 0; cnt < 3; cnt++) {
326 aclsize = 2 * aclsize;
327 aclbuf = check_pool_memory_size(aclbuf, aclsize);
329 if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) == 0) {
334 * See why we failed this time, ENOSPC retry if max retries not met,
344 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
345 jcr->last_fname, be.bstrerror());
346 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
347 jcr->last_fname, be.bstrerror());
353 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
354 jcr->last_fname, be.bstrerror());
355 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
356 jcr->last_fname, be.bstrerror());
360 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
363 retval = bacl_exit_ok;
366 Mmsg2(jcr->errmsg, _("aclx_put error on file \"%s\": ERR=%s\n"),
367 jcr->last_fname, be.bstrerror());
368 Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
369 jcr->last_fname, be.bstrerror());
374 retval = bacl_exit_ok;
377 free_pool_memory(aclbuf);
382 #else /* HAVE_EXTENDED_ACL */
384 #include <sys/access.h>
387 * Define the supported ACL streams for this OS
389 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
390 static int os_default_acl_streams[1] = { -1 };
392 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
396 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
397 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
398 actuallyfree(acl_text);
399 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
401 return bacl_exit_error;
404 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
406 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
407 return bacl_exit_error;
411 #endif /* HAVE_EXTENDED_ACL */
414 * For this OS setup the build and parse function pointer to the OS specific functions.
416 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
417 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
419 #elif defined(HAVE_DARWIN_OS) || \
420 defined(HAVE_FREEBSD_OS) || \
421 defined(HAVE_IRIX_OS) || \
422 defined(HAVE_OSF1_OS) || \
423 defined(HAVE_LINUX_OS)
425 #include <sys/types.h>
427 #ifdef HAVE_SYS_ACL_H
430 #error "configure failed to detect availability of sys/acl.h"
434 * On IRIX we can get shortened ACLs
436 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
437 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
441 * In Linux we can get numeric and/or shorted ACLs
443 #if defined(HAVE_LINUX_OS)
444 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
445 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
446 #elif defined(BACL_WANT_SHORT_ACLS)
447 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
448 #elif defined(BACL_WANT_NUMERIC_IDS)
449 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
451 #ifdef BACL_ALTERNATE_TEXT
452 #include <acl/libacl.h>
453 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
458 * Some generic functions used by multiple OSes.
460 static acl_type_t bac_to_os_acltype(bacl_type acltype)
465 case BACL_TYPE_ACCESS:
466 ostype = ACL_TYPE_ACCESS;
468 case BACL_TYPE_DEFAULT:
469 ostype = ACL_TYPE_DEFAULT;
472 #ifdef ACL_TYPE_DEFAULT_DIR
473 case BACL_TYPE_DEFAULT_DIR:
475 * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
477 ostype = ACL_TYPE_DEFAULT_DIR;
480 #ifdef ACL_TYPE_EXTENDED
481 case BACL_TYPE_EXTENDED:
483 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
485 ostype = ACL_TYPE_EXTENDED;
490 * This should never happen, as the per OS version function only tries acl
491 * types supported on a certain platform.
493 ostype = (acl_type_t)ACL_TYPE_NONE;
499 #if !defined(HAVE_DARWIN_OS)
501 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
502 * There is no need to store those acls as we already store the stat bits too.
504 static bool acl_is_trivial(acl_t acl)
507 * acl is trivial if it has only the following entries:
514 #if defined(HAVE_FREEBSD_OS) || \
515 defined(HAVE_LINUX_OS)
518 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
519 while (entry_available == 1) {
521 * Get the tag type of this acl entry.
522 * If we fail to get the tagtype we call the acl non-trivial.
524 if (acl_get_tag_type(ace, &tag) < 0)
527 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
529 if (tag != ACL_USER_OBJ &&
530 tag != ACL_GROUP_OBJ &&
533 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
536 #elif defined(HAVE_IRIX_OS)
539 for (n = 0; n < acl->acl_cnt; n++) {
540 ace = &acl->acl_entry[n];
544 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
546 if (tag != ACL_USER_OBJ &&
547 tag != ACL_GROUP_OBJ &&
548 tag != ACL_OTHER_OBJ)
552 #elif defined(HAVE_OSF1_OS)
555 ace = acl->acl_first;
556 count = acl->acl_num;
559 tag = ace->entry->acl_type;
561 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
563 if (tag != ACL_USER_OBJ &&
564 tag != ACL_GROUP_OBJ &&
568 * On Tru64, perm can also contain non-standard bits such as
569 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
571 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
582 * Generic wrapper around acl_get_file call.
584 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
591 ostype = bac_to_os_acltype(acltype);
592 acl = acl_get_file(jcr->last_fname, ostype);
594 #if defined(HAVE_IRIX_OS)
596 * From observation, IRIX's acl_get_file() seems to return a
597 * non-NULL acl with a count field of -1 when a file has no ACL
598 * defined, while IRIX's acl_to_text() returns NULL when presented
601 * Checking the count in the acl structure before calling
602 * acl_to_text() lets us avoid error messages about files
603 * with no ACLs, without modifying the flow of the code used for
604 * other operating systems, and it saves making some calls
605 * to acl_to_text() besides.
607 if (acl->acl_cnt <= 0) {
608 pm_strcpy(jcr->acl_data->content, "");
609 jcr->acl_data->content_length = 0;
615 #if !defined(HAVE_DARWIN_OS)
617 * Make sure this is not just a trivial ACL.
619 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
621 * The ACLs simply reflect the (already known) standard permissions
622 * So we don't send an ACL stream to the SD.
624 pm_strcpy(jcr->acl_data->content, "");
625 jcr->acl_data->content_length = 0;
631 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
632 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
638 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
639 jcr->last_fname, be.bstrerror());
640 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
641 jcr->last_fname, be.bstrerror());
643 pm_strcpy(jcr->acl_data->content, "");
644 jcr->acl_data->content_length = 0;
646 return bacl_exit_error;
650 * Handle errors gracefully.
652 if (acl == (acl_t)NULL) {
654 #if defined(BACL_ENOTSUP)
657 * If the filesystem reports it doesn't support ACLs we clear the
658 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
659 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
660 * when we change from one filesystem to an other.
662 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
663 break; /* not supported */
666 pm_strcpy(jcr->acl_data->content, "");
667 jcr->acl_data->content_length = 0;
670 /* Some real error */
671 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
672 jcr->last_fname, be.bstrerror());
673 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
674 jcr->last_fname, be.bstrerror());
676 pm_strcpy(jcr->acl_data->content, "");
677 jcr->acl_data->content_length = 0;
678 return bacl_exit_error;
683 * Not supported, just pretend there is nothing to see
685 pm_strcpy(jcr->acl_data->content, "");
686 jcr->acl_data->content_length = 0;
691 * Generic wrapper around acl_set_file call.
693 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
700 * If we get empty default ACLs, clear ACLs now
702 ostype = bac_to_os_acltype(acltype);
703 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
704 if (acl_delete_def_file(jcr->last_fname) == 0) {
711 Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
712 jcr->last_fname, be.bstrerror());
713 return bacl_exit_error;
717 acl = acl_from_text(jcr->acl_data->content);
719 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
720 jcr->last_fname, be.bstrerror());
721 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
722 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
723 return bacl_exit_error;
726 #ifndef HAVE_FREEBSD_OS
728 * FreeBSD always fails acl_valid() - at least on valid input...
729 * As it does the right thing, given valid input, just ignore acl_valid().
731 if (acl_valid(acl) != 0) {
732 Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
733 jcr->last_fname, be.bstrerror());
734 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
735 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
737 return bacl_exit_error;
742 * Restore the ACLs, but don't complain about links which really should
743 * not have attributes, and the file it is linked to may not yet be restored.
744 * This is only true for the old acl streams as in the new implementation we
745 * don't save acls of symlinks (which cannot have acls anyhow)
747 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
753 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
754 jcr->last_fname, be.bstrerror());
755 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
756 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
758 return bacl_exit_error;
766 * OS specific functions for handling different types of acl streams.
768 #if defined(HAVE_DARWIN_OS)
770 * Define the supported ACL streams for this OS
772 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
773 static int os_default_acl_streams[1] = { -1 };
775 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
777 #if defined(ACL_TYPE_EXTENDED)
779 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
780 * and acl_get_file (name, ACL_TYPE_DEFAULT)
781 * always return NULL / EINVAL. There is no point in making
782 * these two useless calls. The real ACL is retrieved through
783 * acl_get_file (name, ACL_TYPE_EXTENDED).
785 * Read access ACLs for files, dirs and links
787 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
788 return bacl_exit_fatal;
791 * Read access ACLs for files, dirs and links
793 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
794 return bacl_exit_fatal;
797 if (jcr->acl_data->content_length > 0) {
798 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
803 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
805 #if defined(ACL_TYPE_EXTENDED)
806 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
808 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
813 * For this OS setup the build and parse function pointer to the OS specific functions.
815 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
816 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
818 #elif defined(HAVE_FREEBSD_OS) || \
819 defined(HAVE_IRIX_OS) || \
820 defined(HAVE_LINUX_OS)
823 * Define the supported ACL streams for these OSes
825 #if defined(HAVE_FREEBSD_OS)
826 static int os_access_acl_streams[1] = { STREAM_ACL_FREEBSD_ACCESS_ACL };
827 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
828 #elif defined(HAVE_IRIX_OS)
829 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
830 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
831 #elif defined(HAVE_LINUX_OS)
832 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
833 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
836 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
839 * Read access ACLs for files, dirs and links
841 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
842 return bacl_exit_fatal;
844 if (jcr->acl_data->content_length > 0) {
845 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
846 return bacl_exit_fatal;
850 * Directories can have default ACLs too
852 if (ff_pkt->type == FT_DIREND) {
853 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
854 return bacl_exit_fatal;
855 if (jcr->acl_data->content_length > 0) {
856 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
857 return bacl_exit_fatal;
863 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
868 case STREAM_UNIX_ACCESS_ACL:
869 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
870 case STREAM_UNIX_DEFAULT_ACL:
871 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
874 * See what type of acl it is.
876 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
877 if (os_access_acl_streams[cnt] == stream) {
878 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
881 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
882 if (os_default_acl_streams[cnt] == stream) {
883 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
888 return bacl_exit_error;
892 * For this OSes setup the build and parse function pointer to the OS specific functions.
894 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
895 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
897 #elif defined(HAVE_OSF1_OS)
900 * Define the supported ACL streams for this OS
902 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
903 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
905 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
908 * Read access ACLs for files, dirs and links
910 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
911 return bacl_exit_error;
912 if (jcr->acl_data->content_length > 0) {
913 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
914 return bacl_exit_error;
917 * Directories can have default ACLs too
919 if (ff_pkt->type == FT_DIREND) {
920 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
921 return bacl_exit_error;
922 if (jcr->acl_data->content_length > 0) {
923 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
924 return bacl_exit_error;
927 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
928 * This is an inherited acl for all subdirs.
929 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
930 * Section 21.5 Default ACLs
932 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
933 return bacl_exit_error;
934 if (jcr->acl_data->content_length > 0) {
935 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
936 return bacl_exit_error;
942 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
945 case STREAM_UNIX_ACCESS_ACL:
946 case STREAM_ACL_TRU64_ACCESS_ACL:
947 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
948 case STREAM_UNIX_DEFAULT_ACL:
949 case STREAM_ACL_TRU64_DEFAULT_ACL:
950 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
951 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
952 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
956 * For this OS setup the build and parse function pointer to the OS specific functions.
958 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
959 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
963 #elif defined(HAVE_HPUX_OS)
964 #ifdef HAVE_SYS_ACL_H
967 #error "configure failed to detect availability of sys/acl.h"
973 * Define the supported ACL streams for this OS
975 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
976 static int os_default_acl_streams[1] = { -1 };
979 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
980 * There is no need to store those acls as we already store the stat bits too.
982 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
987 for (n = 0; n < count; n++) {
990 * See if this acl just is the stat mode in acl form.
992 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
993 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
994 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1001 * OS specific functions for handling different types of acl streams.
1003 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1006 struct acl_entry acls[NACLENTRIES];
1010 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1012 #if defined(BACL_ENOTSUP)
1015 * Not supported, just pretend there is nothing to see
1017 * If the filesystem reports it doesn't support ACLs we clear the
1018 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1019 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1020 * when we change from one filesystem to an other.
1022 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1023 pm_strcpy(jcr->acl_data->content, "");
1024 jcr->acl_data->content_length = 0;
1025 return bacl_exit_ok;
1028 pm_strcpy(jcr->acl_data->content, "");
1029 jcr->acl_data->content_length = 0;
1030 return bacl_exit_ok;
1032 Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
1033 jcr->last_fname, be.bstrerror());
1034 Dmsg2(100, "getacl error file=%s ERR=%s\n",
1035 jcr->last_fname, be.bstrerror());
1037 pm_strcpy(jcr->acl_data->content, "");
1038 jcr->acl_data->content_length = 0;
1039 return bacl_exit_error;
1043 pm_strcpy(jcr->acl_data->content, "");
1044 jcr->acl_data->content_length = 0;
1045 return bacl_exit_ok;
1047 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1048 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1050 * The ACLs simply reflect the (already known) standard permissions
1051 * So we don't send an ACL stream to the SD.
1053 pm_strcpy(jcr->acl_data->content, "");
1054 jcr->acl_data->content_length = 0;
1055 return bacl_exit_ok;
1057 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1058 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1059 actuallyfree(acl_text);
1061 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1063 Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
1064 jcr->last_fname, be.bstrerror());
1065 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
1066 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1067 return bacl_exit_error;
1069 return bacl_exit_error;
1072 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
1075 struct acl_entry acls[NACLENTRIES];
1078 n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1080 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1081 jcr->last_fname, be.bstrerror());
1082 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1083 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1084 return bacl_exit_error;
1086 if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1087 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1088 jcr->last_fname, be.bstrerror());
1089 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1090 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1092 return bacl_exit_error;
1095 * Restore the ACLs, but don't complain about links which really should
1096 * not have attributes, and the file it is linked to may not yet be restored.
1097 * This is only true for the old acl streams as in the new implementation we
1098 * don't save acls of symlinks (which cannot have acls anyhow)
1100 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1103 return bacl_exit_ok;
1105 Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
1106 jcr->last_fname, be.bstrerror());
1107 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1108 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1109 return bacl_exit_error;
1112 return bacl_exit_ok;
1116 * For this OS setup the build and parse function pointer to the OS specific functions.
1118 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
1119 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
1121 #elif defined(HAVE_SUN_OS)
1122 #ifdef HAVE_SYS_ACL_H
1123 #include <sys/acl.h>
1125 #error "configure failed to detect availability of sys/acl.h"
1128 #if defined(HAVE_EXTENDED_ACL)
1130 * We define some internals of the Solaris acl libs here as those
1131 * are not exposed yet. Probably because they want us to see the
1132 * acls as opague data. But as we need to support different platforms
1133 * and versions of Solaris we need to expose some data to be able
1134 * to determine the type of acl used to stuff it into the correct
1135 * data stream. I know this is far from portable, but maybe the
1136 * proper interface is exposed later on and we can get ride of
1137 * this kludge. Newer versions of Solaris include sys/acl_impl.h
1138 * which has implementation details of acls, if thats included we
1139 * don't have to define it ourself.
1141 #if !defined(_SYS_ACL_IMPL_H)
1142 typedef enum acl_type {
1149 * Two external references to functions in the libsec library function not in current include files.
1152 int acl_type(acl_t *);
1153 char *acl_strerror(int);
1157 * Define the supported ACL streams for this OS
1159 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
1160 static int os_default_acl_streams[1] = { -1 };
1163 * As the new libsec interface with acl_totext and acl_fromtext also handles
1164 * the old format from acltotext we can use the new functions even
1165 * for acls retrieved and stored in the database with older fd versions. If the
1166 * new interface is not defined (Solaris 9 and older we fall back to the old code)
1168 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1170 int acl_enabled, flags;
1173 bacl_exit_code stream_status = bacl_exit_error;
1177 * See if filesystem supports acls.
1179 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1180 switch (acl_enabled) {
1183 * If the filesystem reports it doesn't support ACLs we clear the
1184 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1185 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1186 * when we change from one filesystem to an other.
1188 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1189 pm_strcpy(jcr->acl_data->content, "");
1190 jcr->acl_data->content_length = 0;
1191 return bacl_exit_ok;
1195 return bacl_exit_ok;
1197 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1198 jcr->last_fname, be.bstrerror());
1199 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1200 jcr->last_fname, be.bstrerror());
1201 return bacl_exit_error;
1208 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1210 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1213 return bacl_exit_ok;
1215 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
1216 jcr->last_fname, acl_strerror(errno));
1217 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
1218 jcr->last_fname, acl_strerror(errno));
1219 return bacl_exit_error;
1225 * The ACLs simply reflect the (already known) standard permissions
1226 * So we don't send an ACL stream to the SD.
1228 pm_strcpy(jcr->acl_data->content, "");
1229 jcr->acl_data->content_length = 0;
1230 return bacl_exit_ok;
1233 #if defined(ACL_SID_FMT)
1235 * New format flag added in newer Solaris versions.
1237 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1239 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1240 #endif /* ACL_SID_FMT */
1242 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1243 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1244 actuallyfree(acl_text);
1246 switch (acl_type(aclp)) {
1248 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1251 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1259 return stream_status;
1262 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1265 int acl_enabled, error;
1269 case STREAM_UNIX_ACCESS_ACL:
1270 case STREAM_ACL_SOLARIS_ACLENT:
1271 case STREAM_ACL_SOLARIS_ACE:
1273 * First make sure the filesystem supports acls.
1275 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1276 switch (acl_enabled) {
1278 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1280 return bacl_exit_error;
1284 return bacl_exit_ok;
1286 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1287 jcr->last_fname, be.bstrerror());
1288 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1289 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1290 return bacl_exit_error;
1294 * On a filesystem with ACL support make sure this particilar ACL type can be restored.
1297 case STREAM_ACL_SOLARIS_ACLENT:
1299 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1301 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1302 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1304 return bacl_exit_error;
1307 case STREAM_ACL_SOLARIS_ACE:
1309 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1311 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1312 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1314 return bacl_exit_error;
1319 * Stream id which doesn't describe the type of acl which is encoded.
1326 if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1327 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1328 jcr->last_fname, acl_strerror(error));
1329 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1330 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1331 return bacl_exit_error;
1335 * Validate that the conversion gave us the correct acl type.
1338 case STREAM_ACL_SOLARIS_ACLENT:
1339 if (acl_type(aclp) != ACLENT_T) {
1340 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1342 return bacl_exit_error;
1345 case STREAM_ACL_SOLARIS_ACE:
1346 if (acl_type(aclp) != ACE_T) {
1347 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1349 return bacl_exit_error;
1354 * Stream id which doesn't describe the type of acl which is encoded.
1360 * Restore the ACLs, but don't complain about links which really should
1361 * not have attributes, and the file it is linked to may not yet be restored.
1362 * This is only true for the old acl streams as in the new implementation we
1363 * don't save acls of symlinks (which cannot have acls anyhow)
1365 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1369 return bacl_exit_ok;
1371 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1372 jcr->last_fname, acl_strerror(error));
1373 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1374 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1376 return bacl_exit_error;
1381 return bacl_exit_ok;
1383 return bacl_exit_error;
1384 } /* end switch (stream) */
1387 #else /* HAVE_EXTENDED_ACL */
1390 * Define the supported ACL streams for this OS
1392 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1393 static int os_default_acl_streams[1] = { -1 };
1396 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1397 * There is no need to store those acls as we already store the stat bits too.
1399 static bool acl_is_trivial(int count, aclent_t *entries)
1404 for (n = 0; n < count; n++) {
1407 if (!(ace->a_type == USER_OBJ ||
1408 ace->a_type == GROUP_OBJ ||
1409 ace->a_type == OTHER_OBJ ||
1410 ace->a_type == CLASS_OBJ))
1417 * OS specific functions for handling different types of acl streams.
1419 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1426 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1427 if (n < MIN_ACL_ENTRIES)
1428 return bacl_exit_error;
1430 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1431 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1432 if (acl_is_trivial(n, acls)) {
1434 * The ACLs simply reflect the (already known) standard permissions
1435 * So we don't send an ACL stream to the SD.
1438 pm_strcpy(jcr->acl_data->content, "");
1439 jcr->acl_data->content_length = 0;
1440 return bacl_exit_ok;
1443 if ((acl_text = acltotext(acls, n)) != NULL) {
1444 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1445 actuallyfree(acl_text);
1447 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1450 Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1451 jcr->last_fname, be.bstrerror());
1452 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1453 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1457 return bacl_exit_error;
1460 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1466 acls = aclfromtext(jcr->acl_data->content, &n);
1468 Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1469 jcr->last_fname, be.bstrerror());
1470 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1471 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1472 return bacl_exit_error;
1476 * Restore the ACLs, but don't complain about links which really should
1477 * not have attributes, and the file it is linked to may not yet be restored.
1479 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1483 return bacl_exit_ok;
1485 Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1486 jcr->last_fname, be.bstrerror());
1487 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1488 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1490 return bacl_exit_error;
1494 return bacl_exit_ok;
1496 #endif /* HAVE_EXTENDED_ACL */
1499 * For this OS setup the build and parse function pointer to the OS specific functions.
1501 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1502 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1504 #endif /* HAVE_SUN_OS */
1505 #endif /* HAVE_ACL */
1508 * Entry points when compiled with support for ACLs on a supported platform.
1512 * Read and send an ACL for the last encountered file.
1514 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1517 * See if we are changing from one device to an other.
1518 * We save the current device we are scanning and compare
1519 * it with the current st_dev in the last stat performed on
1520 * the file we are currently storing.
1522 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1524 * Reset the acl save flags.
1526 jcr->acl_data->flags = 0;
1528 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1531 * Save that we started scanning a new filesystem.
1533 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1536 #if defined(HAVE_ACL)
1538 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1541 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1543 * Call the appropriate function.
1545 if (os_build_acl_streams) {
1546 return (*os_build_acl_streams)(jcr, ff_pkt);
1549 return bacl_exit_ok;
1552 return bacl_exit_error;
1555 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1560 #if defined(HAVE_ACL)
1561 case STREAM_UNIX_ACCESS_ACL:
1562 case STREAM_UNIX_DEFAULT_ACL:
1564 * Handle legacy ACL streams.
1566 if (os_parse_acl_streams) {
1567 return (*os_parse_acl_streams)(jcr, stream);
1571 if (os_parse_acl_streams) {
1573 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1575 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1576 if (os_access_acl_streams[cnt] == stream) {
1577 return (*os_parse_acl_streams)(jcr, stream);
1581 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1583 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1584 if (os_default_acl_streams[cnt] == stream) {
1585 return (*os_parse_acl_streams)(jcr, stream);
1595 Qmsg2(jcr, M_WARNING, 0,
1596 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1597 jcr->last_fname, stream);
1598 return bacl_exit_error;