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,
329 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
330 jcr->last_fname, be.bstrerror());
331 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
332 jcr->last_fname, be.bstrerror());
338 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
339 jcr->last_fname, be.bstrerror());
340 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
341 jcr->last_fname, be.bstrerror());
345 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
348 retval = bacl_exit_ok;
351 Mmsg2(jcr->errmsg, _("aclx_put error on file \"%s\": ERR=%s\n"),
352 jcr->last_fname, be.bstrerror());
353 Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
354 jcr->last_fname, be.bstrerror());
359 retval = bacl_exit_ok;
362 free_pool_memory(aclbuf);
367 #else /* HAVE_EXTENDED_ACL */
369 #include <sys/access.h>
372 * Define the supported ACL streams for this OS
374 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
375 static int os_default_acl_streams[1] = { -1 };
377 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
381 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
382 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
383 actuallyfree(acl_text);
384 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
386 return bacl_exit_error;
389 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
391 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
392 return bacl_exit_error;
396 #endif /* HAVE_EXTENDED_ACL */
399 * For this OS setup the build and parse function pointer to the OS specific functions.
401 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
402 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
404 #elif defined(HAVE_DARWIN_OS) || \
405 defined(HAVE_FREEBSD_OS) || \
406 defined(HAVE_IRIX_OS) || \
407 defined(HAVE_OSF1_OS) || \
408 defined(HAVE_LINUX_OS)
410 #include <sys/types.h>
412 #ifdef HAVE_SYS_ACL_H
415 #error "configure failed to detect availability of sys/acl.h"
419 * On IRIX we can get shortened ACLs
421 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
422 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
426 * In Linux we can get numeric and/or shorted ACLs
428 #if defined(HAVE_LINUX_OS)
429 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
430 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
431 #elif defined(BACL_WANT_SHORT_ACLS)
432 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
433 #elif defined(BACL_WANT_NUMERIC_IDS)
434 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
436 #ifdef BACL_ALTERNATE_TEXT
437 #include <acl/libacl.h>
438 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
443 * Some generic functions used by multiple OSes.
445 static acl_type_t bac_to_os_acltype(bacl_type acltype)
450 case BACL_TYPE_ACCESS:
451 ostype = ACL_TYPE_ACCESS;
453 case BACL_TYPE_DEFAULT:
454 ostype = ACL_TYPE_DEFAULT;
457 #ifdef ACL_TYPE_DEFAULT_DIR
458 case BACL_TYPE_DEFAULT_DIR:
460 * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
462 ostype = ACL_TYPE_DEFAULT_DIR;
465 #ifdef ACL_TYPE_EXTENDED
466 case BACL_TYPE_EXTENDED:
468 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
470 ostype = ACL_TYPE_EXTENDED;
475 * This should never happen, as the per OS version function only tries acl
476 * types supported on a certain platform.
478 ostype = (acl_type_t)ACL_TYPE_NONE;
484 #if !defined(HAVE_DARWIN_OS)
486 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
487 * There is no need to store those acls as we already store the stat bits too.
489 static bool acl_is_trivial(acl_t acl)
492 * acl is trivial if it has only the following entries:
499 #if defined(HAVE_FREEBSD_OS) || \
500 defined(HAVE_LINUX_OS)
503 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
504 while (entry_available == 1) {
506 * Get the tag type of this acl entry.
507 * If we fail to get the tagtype we call the acl non-trivial.
509 if (acl_get_tag_type(ace, &tag) < 0)
512 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
514 if (tag != ACL_USER_OBJ &&
515 tag != ACL_GROUP_OBJ &&
518 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
521 #elif defined(HAVE_IRIX_OS)
524 for (n = 0; n < acl->acl_cnt; n++) {
525 ace = &acl->acl_entry[n];
529 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
531 if (tag != ACL_USER_OBJ &&
532 tag != ACL_GROUP_OBJ &&
533 tag != ACL_OTHER_OBJ)
537 #elif defined(HAVE_OSF1_OS)
540 ace = acl->acl_first;
541 count = acl->acl_num;
544 tag = ace->entry->acl_type;
546 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
548 if (tag != ACL_USER_OBJ &&
549 tag != ACL_GROUP_OBJ &&
553 * On Tru64, perm can also contain non-standard bits such as
554 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
556 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
567 * Generic wrapper around acl_get_file call.
569 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
576 ostype = bac_to_os_acltype(acltype);
577 acl = acl_get_file(jcr->last_fname, ostype);
579 #if defined(HAVE_IRIX_OS)
581 * From observation, IRIX's acl_get_file() seems to return a
582 * non-NULL acl with a count field of -1 when a file has no ACL
583 * defined, while IRIX's acl_to_text() returns NULL when presented
586 * Checking the count in the acl structure before calling
587 * acl_to_text() lets us avoid error messages about files
588 * with no ACLs, without modifying the flow of the code used for
589 * other operating systems, and it saves making some calls
590 * to acl_to_text() besides.
592 if (acl->acl_cnt <= 0) {
593 pm_strcpy(jcr->acl_data->content, "");
594 jcr->acl_data->content_length = 0;
600 #if !defined(HAVE_DARWIN_OS)
602 * Make sure this is not just a trivial ACL.
604 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
606 * The ACLs simply reflect the (already known) standard permissions
607 * So we don't send an ACL stream to the SD.
609 pm_strcpy(jcr->acl_data->content, "");
610 jcr->acl_data->content_length = 0;
616 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
617 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
623 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
624 jcr->last_fname, be.bstrerror());
625 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
626 jcr->last_fname, be.bstrerror());
628 pm_strcpy(jcr->acl_data->content, "");
629 jcr->acl_data->content_length = 0;
631 return bacl_exit_error;
635 * Handle errors gracefully.
637 if (acl == (acl_t)NULL) {
639 #if defined(BACL_ENOTSUP)
642 * If the filesystem reports it doesn't support ACLs we clear the
643 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
644 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
645 * when we change from one filesystem to an other.
647 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
648 break; /* not supported */
651 pm_strcpy(jcr->acl_data->content, "");
652 jcr->acl_data->content_length = 0;
655 /* Some real error */
656 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
657 jcr->last_fname, be.bstrerror());
658 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
659 jcr->last_fname, be.bstrerror());
661 pm_strcpy(jcr->acl_data->content, "");
662 jcr->acl_data->content_length = 0;
663 return bacl_exit_error;
668 * Not supported, just pretend there is nothing to see
670 pm_strcpy(jcr->acl_data->content, "");
671 jcr->acl_data->content_length = 0;
676 * Generic wrapper around acl_set_file call.
678 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
685 * If we get empty default ACLs, clear ACLs now
687 ostype = bac_to_os_acltype(acltype);
688 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
689 if (acl_delete_def_file(jcr->last_fname) == 0) {
696 Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
697 jcr->last_fname, be.bstrerror());
698 return bacl_exit_error;
702 acl = acl_from_text(jcr->acl_data->content);
704 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
705 jcr->last_fname, be.bstrerror());
706 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
707 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
708 return bacl_exit_error;
711 #ifndef HAVE_FREEBSD_OS
713 * FreeBSD always fails acl_valid() - at least on valid input...
714 * As it does the right thing, given valid input, just ignore acl_valid().
716 if (acl_valid(acl) != 0) {
717 Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
718 jcr->last_fname, be.bstrerror());
719 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
720 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
722 return bacl_exit_error;
727 * Restore the ACLs, but don't complain about links which really should
728 * not have attributes, and the file it is linked to may not yet be restored.
729 * This is only true for the old acl streams as in the new implementation we
730 * don't save acls of symlinks (which cannot have acls anyhow)
732 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
738 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
739 jcr->last_fname, be.bstrerror());
740 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
741 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
743 return bacl_exit_error;
751 * OS specific functions for handling different types of acl streams.
753 #if defined(HAVE_DARWIN_OS)
755 * Define the supported ACL streams for this OS
757 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
758 static int os_default_acl_streams[1] = { -1 };
760 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
762 #if defined(ACL_TYPE_EXTENDED)
764 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
765 * and acl_get_file (name, ACL_TYPE_DEFAULT)
766 * always return NULL / EINVAL. There is no point in making
767 * these two useless calls. The real ACL is retrieved through
768 * acl_get_file (name, ACL_TYPE_EXTENDED).
770 * Read access ACLs for files, dirs and links
772 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
773 return bacl_exit_fatal;
776 * Read access ACLs for files, dirs and links
778 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
779 return bacl_exit_fatal;
782 if (jcr->acl_data->content_length > 0) {
783 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
788 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
790 #if defined(ACL_TYPE_EXTENDED)
791 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
793 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
798 * For this OS setup the build and parse function pointer to the OS specific functions.
800 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
801 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
803 #elif defined(HAVE_FREEBSD_OS) || \
804 defined(HAVE_IRIX_OS) || \
805 defined(HAVE_LINUX_OS)
808 * Define the supported ACL streams for these OSes
810 #if defined(HAVE_FREEBSD_OS)
811 static int os_access_acl_streams[1] = { STREAM_ACL_FREEBSD_ACCESS_ACL };
812 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
813 #elif defined(HAVE_IRIX_OS)
814 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
815 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
816 #elif defined(HAVE_LINUX_OS)
817 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
818 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
821 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
824 * Read access ACLs for files, dirs and links
826 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
827 return bacl_exit_fatal;
829 if (jcr->acl_data->content_length > 0) {
830 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
831 return bacl_exit_fatal;
835 * Directories can have default ACLs too
837 if (ff_pkt->type == FT_DIREND) {
838 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
839 return bacl_exit_fatal;
840 if (jcr->acl_data->content_length > 0) {
841 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
842 return bacl_exit_fatal;
848 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
853 case STREAM_UNIX_ACCESS_ACL:
854 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
855 case STREAM_UNIX_DEFAULT_ACL:
856 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
859 * See what type of acl it is.
861 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
862 if (os_access_acl_streams[cnt] == stream) {
863 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
866 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
867 if (os_default_acl_streams[cnt] == stream) {
868 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
873 return bacl_exit_error;
877 * For this OSes setup the build and parse function pointer to the OS specific functions.
879 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
880 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
882 #elif defined(HAVE_OSF1_OS)
885 * Define the supported ACL streams for this OS
887 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
888 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
890 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
893 * Read access ACLs for files, dirs and links
895 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
896 return bacl_exit_error;
897 if (jcr->acl_data->content_length > 0) {
898 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
899 return bacl_exit_error;
902 * Directories can have default ACLs too
904 if (ff_pkt->type == FT_DIREND) {
905 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
906 return bacl_exit_error;
907 if (jcr->acl_data->content_length > 0) {
908 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
909 return bacl_exit_error;
912 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
913 * This is an inherited acl for all subdirs.
914 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
915 * Section 21.5 Default ACLs
917 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
918 return bacl_exit_error;
919 if (jcr->acl_data->content_length > 0) {
920 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
921 return bacl_exit_error;
927 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
930 case STREAM_UNIX_ACCESS_ACL:
931 case STREAM_ACL_TRU64_ACCESS_ACL:
932 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
933 case STREAM_UNIX_DEFAULT_ACL:
934 case STREAM_ACL_TRU64_DEFAULT_ACL:
935 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
936 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
937 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
941 * For this OS setup the build and parse function pointer to the OS specific functions.
943 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
944 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
948 #elif defined(HAVE_HPUX_OS)
949 #ifdef HAVE_SYS_ACL_H
952 #error "configure failed to detect availability of sys/acl.h"
958 * Define the supported ACL streams for this OS
960 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
961 static int os_default_acl_streams[1] = { -1 };
964 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
965 * There is no need to store those acls as we already store the stat bits too.
967 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
972 for (n = 0; n < count; n++) {
975 * See if this acl just is the stat mode in acl form.
977 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
978 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
979 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
986 * OS specific functions for handling different types of acl streams.
988 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
991 struct acl_entry acls[NACLENTRIES];
995 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
997 #if defined(BACL_ENOTSUP)
1000 * Not supported, just pretend there is nothing to see
1002 * If the filesystem reports it doesn't support ACLs we clear the
1003 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1004 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1005 * when we change from one filesystem to an other.
1007 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1008 pm_strcpy(jcr->acl_data->content, "");
1009 jcr->acl_data->content_length = 0;
1010 return bacl_exit_ok;
1013 pm_strcpy(jcr->acl_data->content, "");
1014 jcr->acl_data->content_length = 0;
1015 return bacl_exit_ok;
1017 Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
1018 jcr->last_fname, be.bstrerror());
1019 Dmsg2(100, "getacl error file=%s ERR=%s\n",
1020 jcr->last_fname, be.bstrerror());
1022 pm_strcpy(jcr->acl_data->content, "");
1023 jcr->acl_data->content_length = 0;
1024 return bacl_exit_error;
1028 pm_strcpy(jcr->acl_data->content, "");
1029 jcr->acl_data->content_length = 0;
1030 return bacl_exit_ok;
1032 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1033 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1035 * The ACLs simply reflect the (already known) standard permissions
1036 * So we don't send an ACL stream to the SD.
1038 pm_strcpy(jcr->acl_data->content, "");
1039 jcr->acl_data->content_length = 0;
1040 return bacl_exit_ok;
1042 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1043 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1044 actuallyfree(acl_text);
1046 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1048 Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
1049 jcr->last_fname, be.bstrerror());
1050 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
1051 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1052 return bacl_exit_error;
1054 return bacl_exit_error;
1057 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
1060 struct acl_entry acls[NACLENTRIES];
1063 n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1065 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1066 jcr->last_fname, be.bstrerror());
1067 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1068 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1069 return bacl_exit_error;
1071 if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1072 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1073 jcr->last_fname, be.bstrerror());
1074 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1075 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1077 return bacl_exit_error;
1080 * Restore the ACLs, but don't complain about links which really should
1081 * not have attributes, and the file it is linked to may not yet be restored.
1082 * This is only true for the old acl streams as in the new implementation we
1083 * don't save acls of symlinks (which cannot have acls anyhow)
1085 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1088 return bacl_exit_ok;
1090 Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
1091 jcr->last_fname, be.bstrerror());
1092 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1093 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1094 return bacl_exit_error;
1097 return bacl_exit_ok;
1101 * For this OS setup the build and parse function pointer to the OS specific functions.
1103 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
1104 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
1106 #elif defined(HAVE_SUN_OS)
1107 #ifdef HAVE_SYS_ACL_H
1108 #include <sys/acl.h>
1110 #error "configure failed to detect availability of sys/acl.h"
1113 #if defined(HAVE_EXTENDED_ACL)
1115 * We define some internals of the Solaris acl libs here as those
1116 * are not exposed yet. Probably because they want us to see the
1117 * acls as opague data. But as we need to support different platforms
1118 * and versions of Solaris we need to expose some data to be able
1119 * to determine the type of acl used to stuff it into the correct
1120 * data stream. I know this is far from portable, but maybe the
1121 * proper interface is exposed later on and we can get ride of
1122 * this kludge. Newer versions of Solaris include sys/acl_impl.h
1123 * which has implementation details of acls, if thats included we
1124 * don't have to define it ourself.
1126 #if !defined(_SYS_ACL_IMPL_H)
1127 typedef enum acl_type {
1134 * Two external references to functions in the libsec library function not in current include files.
1137 int acl_type(acl_t *);
1138 char *acl_strerror(int);
1142 * Define the supported ACL streams for this OS
1144 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
1145 static int os_default_acl_streams[1] = { -1 };
1148 * As the new libsec interface with acl_totext and acl_fromtext also handles
1149 * the old format from acltotext we can use the new functions even
1150 * for acls retrieved and stored in the database with older fd versions. If the
1151 * new interface is not defined (Solaris 9 and older we fall back to the old code)
1153 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1155 int acl_enabled, flags;
1158 bacl_exit_code stream_status = bacl_exit_error;
1162 * See if filesystem supports acls.
1164 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1165 switch (acl_enabled) {
1168 * If the filesystem reports it doesn't support ACLs we clear the
1169 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1170 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1171 * when we change from one filesystem to an other.
1173 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1174 pm_strcpy(jcr->acl_data->content, "");
1175 jcr->acl_data->content_length = 0;
1176 return bacl_exit_ok;
1180 return bacl_exit_ok;
1182 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1183 jcr->last_fname, be.bstrerror());
1184 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1185 jcr->last_fname, be.bstrerror());
1186 return bacl_exit_error;
1193 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1195 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1198 return bacl_exit_ok;
1200 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
1201 jcr->last_fname, acl_strerror(errno));
1202 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
1203 jcr->last_fname, acl_strerror(errno));
1204 return bacl_exit_error;
1210 * The ACLs simply reflect the (already known) standard permissions
1211 * So we don't send an ACL stream to the SD.
1213 pm_strcpy(jcr->acl_data->content, "");
1214 jcr->acl_data->content_length = 0;
1215 return bacl_exit_ok;
1218 #if defined(ACL_SID_FMT)
1220 * New format flag added in newer Solaris versions.
1222 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1224 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1225 #endif /* ACL_SID_FMT */
1227 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1228 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1229 actuallyfree(acl_text);
1231 switch (acl_type(aclp)) {
1233 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1236 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1244 return stream_status;
1247 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1250 int acl_enabled, error;
1254 case STREAM_UNIX_ACCESS_ACL:
1255 case STREAM_ACL_SOLARIS_ACLENT:
1256 case STREAM_ACL_SOLARIS_ACE:
1258 * First make sure the filesystem supports acls.
1260 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1261 switch (acl_enabled) {
1263 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1265 return bacl_exit_error;
1269 return bacl_exit_ok;
1271 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1272 jcr->last_fname, be.bstrerror());
1273 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1274 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1275 return bacl_exit_error;
1279 * On a filesystem with ACL support make sure this particilar ACL type can be restored.
1282 case STREAM_ACL_SOLARIS_ACLENT:
1284 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1286 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1287 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1289 return bacl_exit_error;
1292 case STREAM_ACL_SOLARIS_ACE:
1294 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1296 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1297 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1299 return bacl_exit_error;
1304 * Stream id which doesn't describe the type of acl which is encoded.
1311 if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1312 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1313 jcr->last_fname, acl_strerror(error));
1314 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1315 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1316 return bacl_exit_error;
1320 * Validate that the conversion gave us the correct acl type.
1323 case STREAM_ACL_SOLARIS_ACLENT:
1324 if (acl_type(aclp) != ACLENT_T) {
1325 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1327 return bacl_exit_error;
1330 case STREAM_ACL_SOLARIS_ACE:
1331 if (acl_type(aclp) != ACE_T) {
1332 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1334 return bacl_exit_error;
1339 * Stream id which doesn't describe the type of acl which is encoded.
1345 * Restore the ACLs, but don't complain about links which really should
1346 * not have attributes, and the file it is linked to may not yet be restored.
1347 * This is only true for the old acl streams as in the new implementation we
1348 * don't save acls of symlinks (which cannot have acls anyhow)
1350 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1354 return bacl_exit_ok;
1356 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1357 jcr->last_fname, acl_strerror(error));
1358 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1359 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1361 return bacl_exit_error;
1366 return bacl_exit_ok;
1368 return bacl_exit_error;
1369 } /* end switch (stream) */
1372 #else /* HAVE_EXTENDED_ACL */
1375 * Define the supported ACL streams for this OS
1377 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1378 static int os_default_acl_streams[1] = { -1 };
1381 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1382 * There is no need to store those acls as we already store the stat bits too.
1384 static bool acl_is_trivial(int count, aclent_t *entries)
1389 for (n = 0; n < count; n++) {
1392 if (!(ace->a_type == USER_OBJ ||
1393 ace->a_type == GROUP_OBJ ||
1394 ace->a_type == OTHER_OBJ ||
1395 ace->a_type == CLASS_OBJ))
1402 * OS specific functions for handling different types of acl streams.
1404 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1411 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1412 if (n < MIN_ACL_ENTRIES)
1413 return bacl_exit_error;
1415 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1416 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1417 if (acl_is_trivial(n, acls)) {
1419 * The ACLs simply reflect the (already known) standard permissions
1420 * So we don't send an ACL stream to the SD.
1423 pm_strcpy(jcr->acl_data->content, "");
1424 jcr->acl_data->content_length = 0;
1425 return bacl_exit_ok;
1428 if ((acl_text = acltotext(acls, n)) != NULL) {
1429 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1430 actuallyfree(acl_text);
1432 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1435 Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1436 jcr->last_fname, be.bstrerror());
1437 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1438 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1442 return bacl_exit_error;
1445 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1451 acls = aclfromtext(jcr->acl_data->content, &n);
1453 Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1454 jcr->last_fname, be.bstrerror());
1455 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1456 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1457 return bacl_exit_error;
1461 * Restore the ACLs, but don't complain about links which really should
1462 * not have attributes, and the file it is linked to may not yet be restored.
1464 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1468 return bacl_exit_ok;
1470 Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1471 jcr->last_fname, be.bstrerror());
1472 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1473 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1475 return bacl_exit_error;
1479 return bacl_exit_ok;
1481 #endif /* HAVE_EXTENDED_ACL */
1484 * For this OS setup the build and parse function pointer to the OS specific functions.
1486 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1487 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1489 #endif /* HAVE_SUN_OS */
1490 #endif /* HAVE_ACL */
1493 * Entry points when compiled with support for ACLs on a supported platform.
1497 * Read and send an ACL for the last encountered file.
1499 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1502 * See if we are changing from one device to an other.
1503 * We save the current device we are scanning and compare
1504 * it with the current st_dev in the last stat performed on
1505 * the file we are currently storing.
1507 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1509 * Reset the acl save flags.
1511 jcr->acl_data->flags = 0;
1513 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1516 * Save that we started scanning a new filesystem.
1518 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1521 #if defined(HAVE_ACL)
1523 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1526 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1528 * Call the appropriate function.
1530 if (os_build_acl_streams) {
1531 return (*os_build_acl_streams)(jcr, ff_pkt);
1534 return bacl_exit_ok;
1537 return bacl_exit_error;
1540 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1545 #if defined(HAVE_ACL)
1546 case STREAM_UNIX_ACCESS_ACL:
1547 case STREAM_UNIX_DEFAULT_ACL:
1549 * Handle legacy ACL streams.
1551 if (os_parse_acl_streams) {
1552 return (*os_parse_acl_streams)(jcr, stream);
1556 if (os_parse_acl_streams) {
1558 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1560 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1561 if (os_access_acl_streams[cnt] == stream) {
1562 return (*os_parse_acl_streams)(jcr, stream);
1566 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1568 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1569 if (os_default_acl_streams[cnt] == stream) {
1570 return (*os_parse_acl_streams)(jcr, stream);
1580 Qmsg2(jcr, M_WARNING, 0,
1581 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1582 jcr->last_fname, stream);
1583 return bacl_exit_error;