2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Major refactoring of ACL and XATTR code written by:
22 * Radosław Korzeniewski, MMXVI
23 * radoslaw@korzeniewski.net, radekk@inteos.pl
24 * Inteos Sp. z o.o. http://www.inteos.pl/
30 #include "xacl_freebsd.h"
32 #if defined(HAVE_FREEBSD_OS)
34 * Define the supported ACL streams for this OS
36 static const int os_acl_streams[] = {
37 STREAM_XACL_FREEBSD_ACCESS,
38 STREAM_XACL_FREEBSD_NFS4,
42 static const int os_default_acl_streams[] = {
43 STREAM_XACL_FREEBSD_DEFAULT,
48 * Define the supported XATTR streams for this OS
50 static const int os_xattr_streams[] = {
51 STREAM_XACL_FREEBSD_XATTR,
55 static const int os_xattr_namespaces[] = {
56 EXTATTR_NAMESPACE_USER,
57 EXTATTR_NAMESPACE_SYSTEM,
61 static const char *os_xattr_acl_skiplist[] = {
62 "system.posix1e.acl_access",
63 "system.posix1e.acl_default",
68 static const char *os_xattr_skiplist[] = {
73 * OS Specyfic constructor
75 XACL_FreeBSD::XACL_FreeBSD(){
77 set_acl_streams(os_acl_streams, os_default_acl_streams);
78 set_xattr_streams(os_xattr_streams);
79 set_xattr_skiplists(os_xattr_skiplist, os_xattr_acl_skiplist);
83 * Translates Bacula internal acl representation into
87 * xacltype - internal Bacula acl type (XACL_type)
89 * acl_type_t - os dependent acl type
90 * when failed - ACL_TYPE_NONE is returned
92 acl_type_t XACL_FreeBSD::get_acltype(XACL_type xacltype){
97 #ifdef HAVE_ACL_TYPE_NFS4
99 acltype = ACL_TYPE_NFS4;
102 case XACL_TYPE_ACCESS:
103 acltype = ACL_TYPE_ACCESS;
105 case XACL_TYPE_DEFAULT:
106 acltype = ACL_TYPE_DEFAULT;
110 * sanity check for acl's not supported by OS
112 acltype = (acl_type_t)ACL_TYPE_NONE;
119 * Counts a number of acl entries
124 * int - number of entries in acl object
125 * when no acl entry available or any error then return zero '0'
127 int XACL_FreeBSD::acl_nrentries(acl_t acl){
130 acl_entry_t aclentry;
133 rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &aclentry);
136 rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &aclentry);
143 * Checks if acl is simple.
145 * acl is simple if it has only the following entries:
153 * true - when acl object is simple
154 * false - when acl object is not simple
156 bool XACL_FreeBSD::acl_issimple(acl_t acl){
158 acl_entry_t aclentry;
162 rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &aclentry);
164 if (acl_get_tag_type(aclentry, &acltag) < 0){
168 * Check for ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER to find out.
170 if (acltag != ACL_USER_OBJ &&
171 acltag != ACL_GROUP_OBJ &&
172 acltag != ACL_OTHER){
175 rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &aclentry);
181 * Checks if ACL's are available for a specified file
184 * jcr - Job Control Record
185 * name - specifies the system variable to be queried
187 * bRC_XACL_ok - check successful, lets setup xacltype variable
188 * bRC_XACL_error - in case of error
189 * bRC_XACL_skip - you should skip all other routine
190 * bRC_XACL_cont - you need to continue your routine
192 bRC_XACL XACL_FreeBSD::check_xacltype (JCR *jcr, int name){
196 aclrc = pathconf(jcr->last_fname, name);
199 /* some error check why */
201 if (errno == ENOENT){
202 /* file does not exist skip it */
203 return bRC_XACL_skip;
205 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
206 Dmsg2(100, "pathconf error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
207 return bRC_XACL_error;
211 /* continue the routine */
212 return bRC_XACL_cont;
220 * Perform OS specyfic ACL backup
222 * in/out - check API at xacl.h
224 bRC_XACL XACL_FreeBSD::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
227 XACL_type xacltype = XACL_TYPE_NONE;
229 #if defined(_PC_ACL_NFS4)
231 * Check if filesystem supports NFS4 acls.
233 rc = check_xacltype(jcr, _PC_ACL_NFS4);
236 xacltype = XACL_TYPE_NFS4;
247 if (xacltype == XACL_TYPE_NONE){
249 * Check if filesystem supports POSIX acls.
251 rc = check_xacltype(jcr, _PC_ACL_EXTENDED);
254 xacltype = XACL_TYPE_ACCESS;
266 /* no ACL's available for file, so skip this filesystem */
267 if (xacltype == XACL_TYPE_NONE){
268 clear_flag(XACL_FLAG_NATIVE);
270 * it is a bit of hardcore to clear a poolmemory with a NULL pointer,
271 * but it is working, hehe :)
272 * you may ask why it is working? it is simple, a pm_strcpy function is handling
273 * a null pointer with a substitiution of empty string.
284 if (os_get_acl(jcr, XACL_TYPE_NFS4) == bRC_XACL_fatal)
285 return bRC_XACL_fatal;
287 if (get_content_len() > 0){
288 if (send_acl_stream(jcr, STREAM_XACL_FREEBSD_NFS4) == bRC_XACL_fatal)
289 return bRC_XACL_fatal;
292 case XACL_TYPE_ACCESS:
296 if (os_get_acl(jcr, XACL_TYPE_ACCESS) == bRC_XACL_fatal)
297 return bRC_XACL_fatal;
299 if (get_content_len() > 0){
300 if (send_acl_stream(jcr, STREAM_XACL_FREEBSD_ACCESS) == bRC_XACL_fatal)
301 return bRC_XACL_fatal;
305 * Directories can have default ACLs too
307 if (ff_pkt->type == FT_DIREND){
308 if (os_get_acl(jcr, XACL_TYPE_DEFAULT) == bRC_XACL_fatal)
309 return bRC_XACL_fatal;
310 if (get_content_len() > 0){
311 if (send_acl_stream(jcr, STREAM_XACL_FREEBSD_DEFAULT) == bRC_XACL_fatal)
312 return bRC_XACL_fatal;
324 * Perform OS specyfic ACL restore
326 * in/out - check API at xacl.h
328 bRC_XACL XACL_FreeBSD::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length){
331 const char *acl_type_name;
334 case STREAM_UNIX_ACCESS_ACL:
335 case STREAM_XACL_FREEBSD_ACCESS:
336 case STREAM_UNIX_DEFAULT_ACL:
337 case STREAM_XACL_FREEBSD_DEFAULT:
338 aclrc = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
339 acl_type_name = "POSIX";
341 case STREAM_XACL_FREEBSD_NFS4:
342 #if defined(_PC_ACL_NFS4)
343 aclrc = pathconf(jcr->last_fname, _PC_ACL_NFS4);
345 acl_type_name = "NFS4";
348 acl_type_name = "unknown";
360 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
361 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
362 return bRC_XACL_error;
366 clear_flag(XACL_FLAG_NATIVE);
367 Mmsg2(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"), jcr->last_fname, acl_type_name);
368 return bRC_XACL_error;
374 case STREAM_UNIX_ACCESS_ACL:
375 case STREAM_XACL_FREEBSD_ACCESS:
376 return os_set_acl(jcr, XACL_TYPE_ACCESS, content, length);
377 case STREAM_UNIX_DEFAULT_ACL:
378 case STREAM_XACL_FREEBSD_DEFAULT:
379 return os_set_acl(jcr, XACL_TYPE_DEFAULT, content, length);
380 case STREAM_XACL_FREEBSD_NFS4:
381 return os_set_acl(jcr, XACL_TYPE_NFS4, content, length);
385 return bRC_XACL_error;
389 * Perform OS specyfic extended attribute backup
391 * in/out - check API at xacl.h
393 bRC_XACL XACL_FreeBSD::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
403 uint32_t name_gen_len;
404 char * namespace_str;
407 alist *xattr_list = NULL;
413 for (a = 0; os_xattr_namespaces[a] != -1; a++){ // loop through all available namespaces
414 /* xlist is allocated as POOLMEM by os_get_xattr_names */
415 rc = os_get_xattr_names(jcr, os_xattr_namespaces[a], &xlist, &xlen);
418 /* it's ok, so go further */
422 /* no xattr available, so skip rest of it */
428 /* get a string representation of the namespace */
429 if (extattr_namespace_to_string(os_xattr_namespaces[a], &namespace_str) != 0){
430 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"), os_xattr_namespaces[a], jcr->last_fname);
431 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n", os_xattr_namespaces[a], jcr->last_fname);
434 namespace_len = strlen(namespace_str);
436 /* follow the list of xattr names and get the values */
437 for (name = xlist; (name - xlist) + 1 < xlen; name = strchr(name, '\0') + 1){
438 name_len = strlen(name);
439 name_gen = get_pool_memory(PM_FNAME);
440 name_gen = check_pool_memory_size(name_gen, name_len + namespace_len + 2);
441 bsnprintf(name_gen, name_len + namespace_len + 2, "%s.%s", namespace_str, name);
442 name_gen_len = strlen(name_gen);
444 skip = check_xattr_skiplists(jcr, ff_pkt, name_gen);
445 if (skip || name_len == 0){
446 Dmsg1(100, "Skipping xattr named %s\n", name_gen);
450 /* value is allocated as POOLMEM by os_get_xattr_value */
451 rc = os_get_xattr_value(jcr, os_xattr_namespaces[a], name, &value, &value_len);
454 /* it's ok, so go further */
457 /* no xattr available, so skip rest of it */
466 * we have a name of the extended attribute in the name variable
467 * and value of the extended attribute in the value variable
468 * so we need to build a list
470 xattr = (XACL_xattr*)malloc(sizeof(XACL_xattr));
471 xattr->name_len = name_gen_len;
472 xattr->name = name_gen;
473 xattr->value_len = value_len;
474 xattr->value = value;
475 /* magic name_len name value_len value */
476 len += sizeof(uint32_t) + sizeof(uint32_t) + name_gen_len + sizeof(uint32_t) + value_len;
478 if (xattr_list == NULL){
479 xattr_list = New(alist(10, not_owned_by_alist));
481 xattr_list->append(xattr);
484 if (xattr_count > 0){
485 /* serialize the stream */
486 rc = serialize_xattr_stream(jcr, len, xattr_list);
487 if (rc != bRC_XACL_ok){
488 Mmsg(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"), jcr->last_fname);
489 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n", jcr->last_fname);
492 /* send data to SD */
493 rc = send_xattr_stream(jcr, STREAM_XACL_FREEBSD_XATTR);
500 /* free allocated data */
501 if (xattr_list != NULL){
502 foreach_alist(xattr, xattr_list){
507 free_pool_memory(name_gen);
524 * Perform OS specyfic XATTR restore. Runtime is called only when stream is supported by OS.
526 * in/out - check API at xacl.h
528 bRC_XACL XACL_FreeBSD::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length){
529 return generic_restore_xattr(jcr, stream);
533 * Low level OS specyfic runtime to get ACL data from file. The ACL data is set in internal content buffer
535 * in/out - check API at xacl.h
537 bRC_XACL XACL_FreeBSD::os_get_acl(JCR *jcr, XACL_type xacltype){
542 bRC_XACL rc = bRC_XACL_ok;
544 acltype = get_acltype(xacltype);
545 acl = acl_get_file(jcr->last_fname, acltype);
548 Dmsg1(400, "OS_ACL read from file: %s\n",jcr->last_fname);
549 if (acl_nrentries(acl) == 0){
553 /* check for fimple ACL which correspond to standard permissions only */
554 if (xacltype == XACL_TYPE_ACCESS && acl_issimple(acl)){
558 #if defined(_PC_ACL_NFS4)
559 if (xacltype == XACL_TYPE_NFS4){
561 if (acl_is_trivial_np(acl, &trivial) == 0){
569 if ((acltext = acl_to_text(acl, NULL)) != NULL){
570 set_content(acltext);
578 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
579 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
588 /* fs does not support acl, skip it */
589 Dmsg0(400, "Wow, ACL is not supported on this filesystem\n");
590 clear_flag(XACL_FLAG_NATIVE);
595 /* Some real error */
596 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
597 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
608 * it is a bit of hardcore to clear a poolmemory with a NULL pointer,
609 * but it is working, hehe :)
610 * you may ask why it is working? it is simple, a pm_strcpy function is handling
611 * a null pointer with a substitiution of empty string.
618 * Low level OS specyfic runtime to set ACL data on file
620 * in/out - check API at xacl.h
622 bRC_XACL XACL_FreeBSD::os_set_acl(JCR *jcr, XACL_type xacltype, char *content, uint32_t length){
627 acltype = get_acltype(xacltype);
628 if (acltype == ACL_TYPE_DEFAULT && length == 0){
629 /* delete ACl from file when no acl data available for default acl's */
630 if (acl_delete_def_file(jcr->last_fname) == 0){
640 * If the filesystem reports it doesn't support acl's we clear the
641 * XACL_FLAG_NATIVE flag so we skip ACL restores on all other files
642 * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
643 * when we change from one filesystem to an other.
645 clear_flag(XACL_FLAG_NATIVE);
646 Mmsg(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"), jcr->last_fname);
647 return bRC_XACL_error;
649 Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
650 return bRC_XACL_error;
654 acl = acl_from_text(content);
658 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
659 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
660 return bRC_XACL_error;
664 * Restore the ACLs, but don't complain about links which really should
665 * not have attributes, and the file it is linked to may not yet be restored.
666 * This is only true for the old acl streams as in the new implementation we
667 * don't save acls of symlinks (which cannot have acls anyhow)
669 if (acl_set_file(jcr->last_fname, acltype, acl) != 0 && jcr->last_type != FT_LNK){
677 * If the filesystem reports it doesn't support ACLs we clear the
678 * XACL_FLAG_NATIVE flag so we skip ACL restores on all other files
679 * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
680 * when we change from one filesystem to an other.
682 clear_flag(XACL_FLAG_NATIVE);
683 Mmsg(jcr->errmsg, _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"), jcr->last_fname);
684 Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n", content, jcr->last_fname);
686 return bRC_XACL_error;
688 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
689 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
691 return bRC_XACL_error;
699 * Return a list of xattr names in newly allocated pool memory and a length of the allocated buffer.
700 * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
703 * in/out - check API at xacl.h
705 * As a FreeBSD uses a different attributes name schema/format then this method is a very different
706 * from a standard generic method because it uses a namespace (ns) value for os dependent optimization.
708 bRC_XACL XACL_FreeBSD::os_get_xattr_names (JCR *jcr, int ns, POOLMEM ** pxlist, uint32_t * xlen){
716 /* check input data */
717 if (jcr == NULL || xlen == NULL || pxlist == NULL){
718 return bRC_XACL_inval;
720 /* get the length of the extended attributes */
721 len = extattr_list_link(jcr->last_fname, ns, NULL, 0);
728 /* no file available, skip it */
729 return bRC_XACL_skip;
731 /* no xattr supported on filesystem, clear a flag and skip it */
732 clear_flag(XACL_FLAG_NATIVE);
734 return bRC_XACL_skip;
736 if (ns == EXTATTR_NAMESPACE_SYSTEM){
737 return bRC_XACL_cont;
738 } /* else show error */
740 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
741 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
742 return bRC_XACL_error;
747 /* xattr available but empty, skip it */
748 return bRC_XACL_skip;
754 * allocate memory for the extented attribute list
755 * default size is a 4k for PM_BSOCK, which should be sufficient on almost all
756 * Linux system where xattrs a limited in size to single filesystem block ~4kB
757 * so we need to check required size
759 list = get_pool_memory(PM_BSOCK);
760 list = check_pool_memory_size(list, len + 1);
761 memset(list, 0, len + 1);
763 /* get the list of extended attributes names for a file */
764 len = extattr_list_link(jcr->last_fname, ns, list, len);
771 /* no file available, skip it, first release allocated memory */
772 free_pool_memory(list);
773 return bRC_XACL_skip;
775 if (ns == EXTATTR_NAMESPACE_SYSTEM){
776 return bRC_XACL_cont;
777 } /* else show error */
779 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
780 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
781 free_pool_memory(list);
782 return bRC_XACL_error;
789 /* convert FreeBSD list type to the generic one */
790 genlist = get_pool_memory(PM_BSOCK);
791 genlist = check_pool_memory_size(genlist, len + 1);
792 memset(genlist, 0, len + 1);
793 for (a = 0; a < len; a += list[a] + 1){
795 memcpy(genlist + a, list + a + 1, stra);
796 genlist[a + stra] = '\0';
798 free_pool_memory(list);
799 /* setup return data */
806 * Return a value of the requested attribute name and a length of the allocated buffer.
807 * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
810 * in/out - check API at xacl.h
812 * As a FreeBSD uses a different attributes name schema/format then this method is a very different
813 * from a standard generic method because it uses a namespace (ns) value for os dependent optimization.
815 bRC_XACL XACL_FreeBSD::os_get_xattr_value (JCR *jcr, int ns, char * name, char ** pvalue, uint32_t * plen){
820 /* check input data */
821 if (jcr == NULL || name == NULL || plen == NULL || pvalue == NULL){
822 return bRC_XACL_inval;
824 /* get the length of the value for extended attribute */
825 len = extattr_get_link(jcr->last_fname, ns, name, NULL, 0);
832 /* no file available, skip it */
833 return bRC_XACL_skip;
835 /* XXX: what about ENOATTR error value? */
836 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
837 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
838 return bRC_XACL_error;
848 * allocate memory for the extented attribute value
849 * default size is a 256B for PM_MESSAGE, so we need to check required size
851 value = get_pool_memory(PM_MESSAGE);
852 value = check_pool_memory_size(value, len + 1);
853 memset(value, 0, len + 1);
854 /* value is not empty, get a data */
855 len = extattr_get_link(jcr->last_fname, ns, name, value, len);
862 /* no file available, skip it, first release allocated memory */
863 free_pool_memory(value);
864 return bRC_XACL_skip;
866 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
867 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
868 free_pool_memory(value);
869 return bRC_XACL_error;
876 /* ensure a value is nul terminated */
883 /* setup return data */
890 * Low level OS specyfic runtime to set extended attribute on file
892 * in/out - check API at xacl.h
894 * xattr->name should be in '<namespace>.<name>' format which
895 * function handle without problem, otherwise it returns an error
896 * TODO: it is possible to handle a different attributes name format
897 * for os portability where default namespace 'user' can be used
899 bRC_XACL XACL_FreeBSD::os_set_xattr (JCR *jcr, XACL_xattr *xattr){
906 /* check input data */
907 if (jcr == NULL || xattr == NULL){
908 return bRC_XACL_inval;
911 /* search for attribute namespace which is distinguished from attribute name by a dot '.' character */
912 if ((name = strchr(xattr->name, '.')) == (char *)NULL){
913 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"), xattr->name, jcr->last_fname);
914 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n", xattr->name, jcr->last_fname);
915 return bRC_XACL_error;
918 /* split namespace and name of the attribute */
919 nspace = xattr->name;
922 /* check if namespace is valid on this system */
923 if (extattr_string_to_namespace(nspace, &ns) != 0){
924 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"), nspace, jcr->last_fname);
925 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n", nspace, jcr->last_fname);
926 return bRC_XACL_error;
929 /* set extattr on file */
930 rc = extattr_set_link(jcr->last_fname, ns, name, xattr->value, xattr->value_len);
931 if (rc < 0 || rc != (int)xattr->value_len){
938 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
939 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
940 return bRC_XACL_error;
946 #endif /* HAVE_FREEBSD_OS */