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 * We handle two different types of ACLs: access and default ACLS.
32 * On most systems that support default ACLs they only apply to directories.
34 * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
35 * independently, while others (eg. Solaris) provide both in one call.
37 * The Filed saves ACLs in their native format and uses different streams
38 * for all different platforms. Currently we only allow ACLs to be restored
39 * which were saved in the native format of the platform they are extracted
40 * on. Later on we might add conversion functions for mapping from one
41 * platform to an other or allow restores of systems that use the same
44 * Its also interesting to see what the exact format of acl text is on
45 * certain platforms and if they use they same encoding we might allow
46 * different platform streams to be decoded on an other similar platform.
48 * Original written by Preben 'Peppe' Guldberg, December MMIV
49 * Major rewrite by Marco van Wieringen, November MMVIII
55 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
57 * Entry points when compiled without support for ACLs or on an unsupported platform.
59 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
61 return bacl_exit_fatal;
64 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
66 return bacl_exit_fatal;
70 * Send an ACL stream to the SD.
72 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
74 BSOCK *sd = jcr->store_bsock;
76 #ifdef FD_NO_SEND_TEST
83 if (jcr->acl_data->content_length <= 0) {
90 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
91 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
93 return bacl_exit_fatal;
97 * Send the buffer to the storage deamon
99 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->content);
101 sd->msg = jcr->acl_data->content;
102 sd->msglen = jcr->acl_data->content_length + 1;
106 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
108 return bacl_exit_fatal;
111 jcr->JobBytes += sd->msglen;
113 if (!sd->signal(BNET_EOD)) {
114 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
116 return bacl_exit_fatal;
119 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
124 * First the native ACLs.
126 #if defined(HAVE_ACL)
127 #if defined(HAVE_AIX_OS)
129 #if defined(HAVE_EXTENDED_ACL)
131 #include <sys/access.h>
134 static bool acl_is_trivial(struct acl *acl)
136 return (acl_last(acl) != acl->acl_ext ? false : true);
139 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
141 return (acl->aclEntryN > 0 ? false : true);
145 * Define the supported ACL streams for this OS
147 static int os_access_acl_streams[3] = { STREAM_ACL_AIX_TEXT, STREAM_ACL_AIX_AIXC, STREAM_ACL_AIX_NFS4 };
148 static int os_default_acl_streams[1] = { -1 };
150 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
155 size_t aclsize, acltxtsize;
156 bacl_exit_code retval = bacl_exit_error;
157 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
160 * First see how big the buffers should be.
163 if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, NULL) < 0) {
166 retval = bacl_exit_ok;
169 Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
170 jcr->last_fname, be.bstrerror());
171 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
172 jcr->last_fname, be.bstrerror());
178 * Make sure the buffers are big enough.
180 aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
183 * Retrieve the ACL info.
185 if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
188 retval = bacl_exit_ok;
191 Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
192 jcr->last_fname, be.bstrerror());
193 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
194 jcr->last_fname, be.bstrerror());
200 * See if the acl is non trivial.
204 if (acl_is_trivial((struct acl *)aclbuf)) {
205 retval = bacl_exit_ok;
210 if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
211 retval = bacl_exit_ok;
216 Mmsg2(jcr->errmsg, _("Unknown acl type encountered on file \"%s\": %ld\n"),
217 jcr->last_fname, type.u64);
218 Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
219 jcr->last_fname, type.u64);
224 * We have a non-trivial acl lets convert it into some ASCII form.
226 acltxtsize = sizeof_pool_memory(jcr->acl_data->content);
227 if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
228 aclsize, type, jcr->last_fname, 0) < 0) {
232 * Our buffer is not big enough, acltxtsize should be updated with the value
233 * the aclx_printStr really need. So we increase the buffer and try again.
235 jcr->acl_data->content = check_pool_memory_size(jcr->acl_data->content, acltxtsize + 1);
236 if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
237 aclsize, type, jcr->last_fname, 0) < 0) {
238 Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
240 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
241 jcr->last_fname, type.u64);
246 Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
248 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
249 jcr->last_fname, type.u64);
254 jcr->acl_data->content_length = strlen(jcr->acl_data->content) + 1;
257 retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
259 retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
263 free_pool_memory(aclbuf);
268 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
274 bacl_exit_code retval = bacl_exit_error;
275 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
278 case STREAM_ACL_AIX_TEXT:
280 * Handle the old stream using the old system call for now.
282 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
283 retval = bacl_exit_error;
286 retval = bacl_exit_ok;
288 case STREAM_ACL_AIX_AIXC:
291 case STREAM_ACL_AIX_NFS4:
296 } /* end switch (stream) */
299 * Set the acl buffer to an initial size. For now we set it
300 * to the same size as the ASCII representation.
302 aclbuf = check_pool_memory_size(aclbuf, jcr->acl_data->content_length);
303 aclsize = jcr->acl_data->content_length;
304 if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) < 0) {
308 * The buffer isn't big enough. The man page doesn't say that aclsize
309 * is updated to the needed size as what is done with aclx_printStr.
310 * So for now we try to increase the buffer a maximum of 3 times
311 * and retry the conversion.
313 for (cnt = 0; cnt < 3; cnt++) {
314 aclsize = 2 * aclsize;
315 aclbuf = check_pool_memory_size(aclbuf, aclsize);
317 if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) == 0) {
322 * See why we failed this time, ENOSPC retry if max retries not met,
332 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
333 jcr->last_fname, be.bstrerror());
334 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
335 jcr->last_fname, be.bstrerror());
341 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
342 jcr->last_fname, be.bstrerror());
343 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
344 jcr->last_fname, be.bstrerror());
348 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
351 retval = bacl_exit_ok;
354 Mmsg2(jcr->errmsg, _("aclx_put error on file \"%s\": ERR=%s\n"),
355 jcr->last_fname, be.bstrerror());
356 Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
357 jcr->last_fname, be.bstrerror());
362 retval = bacl_exit_ok;
365 free_pool_memory(aclbuf);
370 #else /* HAVE_EXTENDED_ACL */
372 #include <sys/access.h>
375 * Define the supported ACL streams for this OS
377 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
378 static int os_default_acl_streams[1] = { -1 };
380 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
384 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
385 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
386 actuallyfree(acl_text);
387 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
389 return bacl_exit_error;
392 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
394 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
395 return bacl_exit_error;
399 #endif /* HAVE_EXTENDED_ACL */
402 * For this OS setup the build and parse function pointer to the OS specific functions.
404 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
405 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
407 #elif defined(HAVE_DARWIN_OS) || \
408 defined(HAVE_FREEBSD_OS) || \
409 defined(HAVE_IRIX_OS) || \
410 defined(HAVE_TRU64_OS) || \
411 defined(HAVE_LINUX_OS)
413 #include <sys/types.h>
415 #ifdef HAVE_SYS_ACL_H
418 #error "configure failed to detect availability of sys/acl.h"
422 * On IRIX we can get shortened ACLs
424 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
425 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
429 * In Linux we can get numeric and/or shorted ACLs
431 #if defined(HAVE_LINUX_OS)
432 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
433 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
434 #elif defined(BACL_WANT_SHORT_ACLS)
435 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
436 #elif defined(BACL_WANT_NUMERIC_IDS)
437 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
439 #ifdef BACL_ALTERNATE_TEXT
440 #include <acl/libacl.h>
441 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
446 * Some generic functions used by multiple OSes.
448 static acl_type_t bac_to_os_acltype(bacl_type acltype)
453 case BACL_TYPE_ACCESS:
454 ostype = ACL_TYPE_ACCESS;
456 case BACL_TYPE_DEFAULT:
457 ostype = ACL_TYPE_DEFAULT;
460 #ifdef ACL_TYPE_DEFAULT_DIR
461 case BACL_TYPE_DEFAULT_DIR:
463 * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
465 ostype = ACL_TYPE_DEFAULT_DIR;
468 #ifdef ACL_TYPE_EXTENDED
469 case BACL_TYPE_EXTENDED:
471 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
473 ostype = ACL_TYPE_EXTENDED;
478 * This should never happen, as the per OS version function only tries acl
479 * types supported on a certain platform.
481 ostype = (acl_type_t)ACL_TYPE_NONE;
487 #if !defined(HAVE_DARWIN_OS)
489 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
490 * There is no need to store those acls as we already store the stat bits too.
492 static bool acl_is_trivial(acl_t acl)
495 * acl is trivial if it has only the following entries:
502 #if defined(HAVE_FREEBSD_OS) || \
503 defined(HAVE_LINUX_OS)
506 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
507 while (entry_available == 1) {
509 * Get the tag type of this acl entry.
510 * If we fail to get the tagtype we call the acl non-trivial.
512 if (acl_get_tag_type(ace, &tag) < 0)
515 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
517 if (tag != ACL_USER_OBJ &&
518 tag != ACL_GROUP_OBJ &&
521 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
524 #elif defined(HAVE_IRIX_OS)
527 for (n = 0; n < acl->acl_cnt; n++) {
528 ace = &acl->acl_entry[n];
532 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
534 if (tag != ACL_USER_OBJ &&
535 tag != ACL_GROUP_OBJ &&
536 tag != ACL_OTHER_OBJ)
540 #elif defined(HAVE_TRU64_OS)
543 ace = acl->acl_first;
544 count = acl->acl_num;
547 tag = ace->entry->acl_type;
549 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
551 if (tag != ACL_USER_OBJ &&
552 tag != ACL_GROUP_OBJ &&
556 * On Tru64, perm can also contain non-standard bits such as
557 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
559 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
570 * Generic wrapper around acl_get_file call.
572 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
579 ostype = bac_to_os_acltype(acltype);
580 acl = acl_get_file(jcr->last_fname, ostype);
582 #if defined(HAVE_IRIX_OS)
584 * From observation, IRIX's acl_get_file() seems to return a
585 * non-NULL acl with a count field of -1 when a file has no ACL
586 * defined, while IRIX's acl_to_text() returns NULL when presented
589 * Checking the count in the acl structure before calling
590 * acl_to_text() lets us avoid error messages about files
591 * with no ACLs, without modifying the flow of the code used for
592 * other operating systems, and it saves making some calls
593 * to acl_to_text() besides.
595 if (acl->acl_cnt <= 0) {
596 pm_strcpy(jcr->acl_data->content, "");
597 jcr->acl_data->content_length = 0;
603 #if !defined(HAVE_DARWIN_OS)
605 * Make sure this is not just a trivial ACL.
607 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
609 * The ACLs simply reflect the (already known) standard permissions
610 * So we don't send an ACL stream to the SD.
612 pm_strcpy(jcr->acl_data->content, "");
613 jcr->acl_data->content_length = 0;
619 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
620 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
626 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
627 jcr->last_fname, be.bstrerror());
628 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
629 jcr->last_fname, be.bstrerror());
631 pm_strcpy(jcr->acl_data->content, "");
632 jcr->acl_data->content_length = 0;
634 return bacl_exit_error;
638 * Handle errors gracefully.
640 if (acl == (acl_t)NULL) {
642 #if defined(BACL_ENOTSUP)
645 * If the filesystem reports it doesn't support ACLs we clear the
646 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
647 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
648 * when we change from one filesystem to an other.
650 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
651 break; /* not supported */
654 pm_strcpy(jcr->acl_data->content, "");
655 jcr->acl_data->content_length = 0;
658 /* Some real error */
659 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
660 jcr->last_fname, be.bstrerror());
661 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
662 jcr->last_fname, be.bstrerror());
664 pm_strcpy(jcr->acl_data->content, "");
665 jcr->acl_data->content_length = 0;
666 return bacl_exit_error;
671 * Not supported, just pretend there is nothing to see
673 pm_strcpy(jcr->acl_data->content, "");
674 jcr->acl_data->content_length = 0;
679 * Generic wrapper around acl_set_file call.
681 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
688 * If we get empty default ACLs, clear ACLs now
690 ostype = bac_to_os_acltype(acltype);
691 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
692 if (acl_delete_def_file(jcr->last_fname) == 0) {
699 Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
700 jcr->last_fname, be.bstrerror());
701 return bacl_exit_error;
705 acl = acl_from_text(jcr->acl_data->content);
707 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
708 jcr->last_fname, be.bstrerror());
709 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
710 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
711 return bacl_exit_error;
714 #ifndef HAVE_FREEBSD_OS
716 * FreeBSD always fails acl_valid() - at least on valid input...
717 * As it does the right thing, given valid input, just ignore acl_valid().
719 if (acl_valid(acl) != 0) {
720 Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
721 jcr->last_fname, be.bstrerror());
722 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
723 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
725 return bacl_exit_error;
730 * Restore the ACLs, but don't complain about links which really should
731 * not have attributes, and the file it is linked to may not yet be restored.
732 * This is only true for the old acl streams as in the new implementation we
733 * don't save acls of symlinks (which cannot have acls anyhow)
735 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
741 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
742 jcr->last_fname, be.bstrerror());
743 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
744 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
746 return bacl_exit_error;
754 * OS specific functions for handling different types of acl streams.
756 #if defined(HAVE_DARWIN_OS)
758 * Define the supported ACL streams for this OS
760 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
761 static int os_default_acl_streams[1] = { -1 };
763 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
765 #if defined(ACL_TYPE_EXTENDED)
767 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
768 * and acl_get_file (name, ACL_TYPE_DEFAULT)
769 * always return NULL / EINVAL. There is no point in making
770 * these two useless calls. The real ACL is retrieved through
771 * acl_get_file (name, ACL_TYPE_EXTENDED).
773 * Read access ACLs for files, dirs and links
775 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
776 return bacl_exit_fatal;
779 * Read access ACLs for files, dirs and links
781 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
782 return bacl_exit_fatal;
785 if (jcr->acl_data->content_length > 0) {
786 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
791 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
793 #if defined(ACL_TYPE_EXTENDED)
794 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
796 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
801 * For this OS setup the build and parse function pointer to the OS specific functions.
803 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
804 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
806 #elif defined(HAVE_FREEBSD_OS) || \
807 defined(HAVE_IRIX_OS) || \
808 defined(HAVE_LINUX_OS)
811 * Define the supported ACL streams for these OSes
813 #if defined(HAVE_FREEBSD_OS)
814 static int os_access_acl_streams[1] = { STREAM_ACL_FREEBSD_ACCESS_ACL };
815 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
816 #elif defined(HAVE_IRIX_OS)
817 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
818 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
819 #elif defined(HAVE_LINUX_OS)
820 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
821 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
824 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
827 * Read access ACLs for files, dirs and links
829 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
830 return bacl_exit_fatal;
832 if (jcr->acl_data->content_length > 0) {
833 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
834 return bacl_exit_fatal;
838 * Directories can have default ACLs too
840 if (ff_pkt->type == FT_DIREND) {
841 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
842 return bacl_exit_fatal;
843 if (jcr->acl_data->content_length > 0) {
844 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
845 return bacl_exit_fatal;
851 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
856 case STREAM_UNIX_ACCESS_ACL:
857 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
858 case STREAM_UNIX_DEFAULT_ACL:
859 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
862 * See what type of acl it is.
864 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
865 if (os_access_acl_streams[cnt] == stream) {
866 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
869 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
870 if (os_default_acl_streams[cnt] == stream) {
871 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
876 return bacl_exit_error;
880 * For this OSes setup the build and parse function pointer to the OS specific functions.
882 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
883 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
885 #elif defined(HAVE_TRU64_OS)
888 * Define the supported ACL streams for this OS
890 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
891 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
893 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
896 * Read access ACLs for files, dirs and links
898 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
899 return bacl_exit_error;
900 if (jcr->acl_data->content_length > 0) {
901 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
902 return bacl_exit_error;
905 * Directories can have default ACLs too
907 if (ff_pkt->type == FT_DIREND) {
908 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
909 return bacl_exit_error;
910 if (jcr->acl_data->content_length > 0) {
911 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
912 return bacl_exit_error;
915 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
916 * This is an inherited acl for all subdirs.
917 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
918 * Section 21.5 Default ACLs
920 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
921 return bacl_exit_error;
922 if (jcr->acl_data->content_length > 0) {
923 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
924 return bacl_exit_error;
930 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
933 case STREAM_UNIX_ACCESS_ACL:
934 case STREAM_ACL_TRU64_ACCESS_ACL:
935 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
936 case STREAM_UNIX_DEFAULT_ACL:
937 case STREAM_ACL_TRU64_DEFAULT_ACL:
938 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
939 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
940 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
944 * For this OS setup the build and parse function pointer to the OS specific functions.
946 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
947 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
951 #elif defined(HAVE_HPUX_OS)
952 #ifdef HAVE_SYS_ACL_H
955 #error "configure failed to detect availability of sys/acl.h"
961 * Define the supported ACL streams for this OS
963 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
964 static int os_default_acl_streams[1] = { -1 };
967 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
968 * There is no need to store those acls as we already store the stat bits too.
970 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
975 for (n = 0; n < count; n++) {
978 * See if this acl just is the stat mode in acl form.
980 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
981 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
982 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
989 * OS specific functions for handling different types of acl streams.
991 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
994 struct acl_entry acls[NACLENTRIES];
998 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1000 #if defined(BACL_ENOTSUP)
1003 * Not supported, just pretend there is nothing to see
1005 * If the filesystem reports it doesn't support ACLs we clear the
1006 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1007 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1008 * when we change from one filesystem to an other.
1010 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1011 pm_strcpy(jcr->acl_data->content, "");
1012 jcr->acl_data->content_length = 0;
1013 return bacl_exit_ok;
1016 pm_strcpy(jcr->acl_data->content, "");
1017 jcr->acl_data->content_length = 0;
1018 return bacl_exit_ok;
1020 Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
1021 jcr->last_fname, be.bstrerror());
1022 Dmsg2(100, "getacl error file=%s ERR=%s\n",
1023 jcr->last_fname, be.bstrerror());
1025 pm_strcpy(jcr->acl_data->content, "");
1026 jcr->acl_data->content_length = 0;
1027 return bacl_exit_error;
1031 pm_strcpy(jcr->acl_data->content, "");
1032 jcr->acl_data->content_length = 0;
1033 return bacl_exit_ok;
1035 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1036 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1038 * The ACLs simply reflect the (already known) standard permissions
1039 * So we don't send an ACL stream to the SD.
1041 pm_strcpy(jcr->acl_data->content, "");
1042 jcr->acl_data->content_length = 0;
1043 return bacl_exit_ok;
1045 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1046 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1047 actuallyfree(acl_text);
1049 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1051 Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
1052 jcr->last_fname, be.bstrerror());
1053 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
1054 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1055 return bacl_exit_error;
1057 return bacl_exit_error;
1060 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
1063 struct acl_entry acls[NACLENTRIES];
1066 n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1068 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1069 jcr->last_fname, be.bstrerror());
1070 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1071 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1072 return bacl_exit_error;
1074 if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1075 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1076 jcr->last_fname, be.bstrerror());
1077 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1078 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1080 return bacl_exit_error;
1083 * Restore the ACLs, but don't complain about links which really should
1084 * not have attributes, and the file it is linked to may not yet be restored.
1085 * This is only true for the old acl streams as in the new implementation we
1086 * don't save acls of symlinks (which cannot have acls anyhow)
1088 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1091 return bacl_exit_ok;
1093 Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
1094 jcr->last_fname, be.bstrerror());
1095 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1096 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1097 return bacl_exit_error;
1100 return bacl_exit_ok;
1104 * For this OS setup the build and parse function pointer to the OS specific functions.
1106 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
1107 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
1109 #elif defined(HAVE_SUN_OS)
1110 #ifdef HAVE_SYS_ACL_H
1111 #include <sys/acl.h>
1113 #error "configure failed to detect availability of sys/acl.h"
1116 #if defined(HAVE_EXTENDED_ACL)
1118 * We define some internals of the Solaris acl libs here as those
1119 * are not exposed yet. Probably because they want us to see the
1120 * acls as opague data. But as we need to support different platforms
1121 * and versions of Solaris we need to expose some data to be able
1122 * to determine the type of acl used to stuff it into the correct
1123 * data stream. I know this is far from portable, but maybe the
1124 * proper interface is exposed later on and we can get ride of
1125 * this kludge. Newer versions of Solaris include sys/acl_impl.h
1126 * which has implementation details of acls, if thats included we
1127 * don't have to define it ourself.
1129 #if !defined(_SYS_ACL_IMPL_H)
1130 typedef enum acl_type {
1137 * Two external references to functions in the libsec library function not in current include files.
1140 int acl_type(acl_t *);
1141 char *acl_strerror(int);
1145 * Define the supported ACL streams for this OS
1147 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
1148 static int os_default_acl_streams[1] = { -1 };
1151 * As the new libsec interface with acl_totext and acl_fromtext also handles
1152 * the old format from acltotext we can use the new functions even
1153 * for acls retrieved and stored in the database with older fd versions. If the
1154 * new interface is not defined (Solaris 9 and older we fall back to the old code)
1156 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1158 int acl_enabled, flags;
1161 bacl_exit_code stream_status = bacl_exit_error;
1165 * See if filesystem supports acls.
1167 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1168 switch (acl_enabled) {
1171 * If the filesystem reports it doesn't support ACLs we clear the
1172 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1173 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1174 * when we change from one filesystem to an other.
1176 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1177 pm_strcpy(jcr->acl_data->content, "");
1178 jcr->acl_data->content_length = 0;
1179 return bacl_exit_ok;
1183 return bacl_exit_ok;
1185 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1186 jcr->last_fname, be.bstrerror());
1187 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1188 jcr->last_fname, be.bstrerror());
1189 return bacl_exit_error;
1196 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1198 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1201 return bacl_exit_ok;
1203 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
1204 jcr->last_fname, acl_strerror(errno));
1205 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
1206 jcr->last_fname, acl_strerror(errno));
1207 return bacl_exit_error;
1213 * The ACLs simply reflect the (already known) standard permissions
1214 * So we don't send an ACL stream to the SD.
1216 pm_strcpy(jcr->acl_data->content, "");
1217 jcr->acl_data->content_length = 0;
1218 return bacl_exit_ok;
1221 #if defined(ACL_SID_FMT)
1223 * New format flag added in newer Solaris versions.
1225 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1227 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1228 #endif /* ACL_SID_FMT */
1230 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1231 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1232 actuallyfree(acl_text);
1234 switch (acl_type(aclp)) {
1236 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1239 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1247 return stream_status;
1250 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1253 int acl_enabled, error;
1257 case STREAM_UNIX_ACCESS_ACL:
1258 case STREAM_ACL_SOLARIS_ACLENT:
1259 case STREAM_ACL_SOLARIS_ACE:
1261 * First make sure the filesystem supports acls.
1263 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1264 switch (acl_enabled) {
1266 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1268 return bacl_exit_error;
1272 return bacl_exit_ok;
1274 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1275 jcr->last_fname, be.bstrerror());
1276 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1277 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1278 return bacl_exit_error;
1282 * On a filesystem with ACL support make sure this particilar ACL type can be restored.
1285 case STREAM_ACL_SOLARIS_ACLENT:
1287 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1289 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1290 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1292 return bacl_exit_error;
1295 case STREAM_ACL_SOLARIS_ACE:
1297 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1299 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1300 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1302 return bacl_exit_error;
1307 * Stream id which doesn't describe the type of acl which is encoded.
1314 if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1315 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1316 jcr->last_fname, acl_strerror(error));
1317 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1318 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1319 return bacl_exit_error;
1323 * Validate that the conversion gave us the correct acl type.
1326 case STREAM_ACL_SOLARIS_ACLENT:
1327 if (acl_type(aclp) != ACLENT_T) {
1328 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1330 return bacl_exit_error;
1333 case STREAM_ACL_SOLARIS_ACE:
1334 if (acl_type(aclp) != ACE_T) {
1335 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1337 return bacl_exit_error;
1342 * Stream id which doesn't describe the type of acl which is encoded.
1348 * Restore the ACLs, but don't complain about links which really should
1349 * not have attributes, and the file it is linked to may not yet be restored.
1350 * This is only true for the old acl streams as in the new implementation we
1351 * don't save acls of symlinks (which cannot have acls anyhow)
1353 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1357 return bacl_exit_ok;
1359 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1360 jcr->last_fname, acl_strerror(error));
1361 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1362 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1364 return bacl_exit_error;
1369 return bacl_exit_ok;
1371 return bacl_exit_error;
1372 } /* end switch (stream) */
1375 #else /* HAVE_EXTENDED_ACL */
1378 * Define the supported ACL streams for this OS
1380 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1381 static int os_default_acl_streams[1] = { -1 };
1384 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1385 * There is no need to store those acls as we already store the stat bits too.
1387 static bool acl_is_trivial(int count, aclent_t *entries)
1392 for (n = 0; n < count; n++) {
1395 if (!(ace->a_type == USER_OBJ ||
1396 ace->a_type == GROUP_OBJ ||
1397 ace->a_type == OTHER_OBJ ||
1398 ace->a_type == CLASS_OBJ))
1405 * OS specific functions for handling different types of acl streams.
1407 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1414 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1415 if (n < MIN_ACL_ENTRIES)
1416 return bacl_exit_error;
1418 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1419 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1420 if (acl_is_trivial(n, acls)) {
1422 * The ACLs simply reflect the (already known) standard permissions
1423 * So we don't send an ACL stream to the SD.
1426 pm_strcpy(jcr->acl_data->content, "");
1427 jcr->acl_data->content_length = 0;
1428 return bacl_exit_ok;
1431 if ((acl_text = acltotext(acls, n)) != NULL) {
1432 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1433 actuallyfree(acl_text);
1435 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1438 Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1439 jcr->last_fname, be.bstrerror());
1440 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1441 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1445 return bacl_exit_error;
1448 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1454 acls = aclfromtext(jcr->acl_data->content, &n);
1456 Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1457 jcr->last_fname, be.bstrerror());
1458 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1459 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1460 return bacl_exit_error;
1464 * Restore the ACLs, but don't complain about links which really should
1465 * not have attributes, and the file it is linked to may not yet be restored.
1467 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1471 return bacl_exit_ok;
1473 Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1474 jcr->last_fname, be.bstrerror());
1475 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1476 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1478 return bacl_exit_error;
1482 return bacl_exit_ok;
1484 #endif /* HAVE_EXTENDED_ACL */
1487 * For this OS setup the build and parse function pointer to the OS specific functions.
1489 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1490 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1492 #endif /* HAVE_SUN_OS */
1493 #endif /* HAVE_ACL */
1496 * Entry points when compiled with support for ACLs on a supported platform.
1500 * Read and send an ACL for the last encountered file.
1502 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1505 * See if we are changing from one device to an other.
1506 * We save the current device we are scanning and compare
1507 * it with the current st_dev in the last stat performed on
1508 * the file we are currently storing.
1510 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1512 * Reset the acl save flags.
1514 jcr->acl_data->flags = 0;
1516 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1519 * Save that we started scanning a new filesystem.
1521 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1524 #if defined(HAVE_ACL)
1526 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1529 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1531 * Call the appropriate function.
1533 if (os_build_acl_streams) {
1534 return (*os_build_acl_streams)(jcr, ff_pkt);
1537 return bacl_exit_ok;
1540 return bacl_exit_error;
1543 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1548 #if defined(HAVE_ACL)
1549 case STREAM_UNIX_ACCESS_ACL:
1550 case STREAM_UNIX_DEFAULT_ACL:
1552 * Handle legacy ACL streams.
1554 if (os_parse_acl_streams) {
1555 return (*os_parse_acl_streams)(jcr, stream);
1559 if (os_parse_acl_streams) {
1561 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1563 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1564 if (os_access_acl_streams[cnt] == stream) {
1565 return (*os_parse_acl_streams)(jcr, stream);
1569 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1571 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1572 if (os_default_acl_streams[cnt] == stream) {
1573 return (*os_parse_acl_streams)(jcr, stream);
1583 Qmsg2(jcr, M_WARNING, 0,
1584 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1585 jcr->last_fname, stream);
1586 return bacl_exit_error;