+ Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
+ content, jcr->last_fname, be.bstrerror());
+ return bacl_exit_error;
+ }
+
+#ifndef HAVE_FREEBSD_OS
+ /**
+ * FreeBSD always fails acl_valid() - at least on valid input...
+ * As it does the right thing, given valid input, just ignore acl_valid().
+ */
+ if (acl_valid(acl) != 0) {
+ berrno be;
+
+ Mmsg2(jcr->errmsg,
+ _("acl_valid error on file \"%s\": ERR=%s\n"),
+ jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
+ content, jcr->last_fname, be.bstrerror());
+ acl_free(acl);
+ return bacl_exit_error;
+ }
+#endif
+
+ /**
+ * Restore the ACLs, but don't complain about links which really should
+ * not have attributes, and the file it is linked to may not yet be restored.
+ * This is only true for the old acl streams as in the new implementation we
+ * don't save acls of symlinks (which cannot have acls anyhow)
+ */
+ if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
+ berrno be;
+
+ switch (errno) {
+ case ENOENT:
+ acl_free(acl);
+ return bacl_exit_ok;
+#if defined(BACL_ENOTSUP)
+ case BACL_ENOTSUP:
+ /*
+ * If the filesystem reports it doesn't support ACLs we clear the
+ * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
+ * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
+ * when we change from one filesystem to an other.
+ */
+ jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
+ Mmsg1(jcr->errmsg,
+ _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
+ jcr->last_fname);
+ Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n",
+ content, jcr->last_fname);
+ acl_free(acl);
+ return bacl_exit_error;
+#endif
+ default:
+ Mmsg2(jcr->errmsg,
+ _("acl_set_file error on file \"%s\": ERR=%s\n"),
+ jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
+ content, jcr->last_fname, be.bstrerror());
+ acl_free(acl);
+ return bacl_exit_error;
+ }
+ }
+ acl_free(acl);
+ return bacl_exit_ok;
+}
+
+/**
+ * OS specific functions for handling different types of acl streams.
+ */
+#if defined(HAVE_DARWIN_OS)
+/**
+ * Define the supported ACL streams for this OS
+ */
+static int os_access_acl_streams[1] = {
+ STREAM_ACL_DARWIN_ACCESS_ACL
+};
+static int os_default_acl_streams[1] = {
+ -1
+};
+
+static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
+{
+#if defined(HAVE_ACL_TYPE_EXTENDED)
+ /**
+ * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
+ * and acl_get_file (name, ACL_TYPE_DEFAULT)
+ * always return NULL / EINVAL. There is no point in making
+ * these two useless calls. The real ACL is retrieved through
+ * acl_get_file (name, ACL_TYPE_EXTENDED).
+ *
+ * Read access ACLs for files, dirs and links
+ */
+ if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
+ return bacl_exit_fatal;
+#else
+ /**
+ * Read access ACLs for files, dirs and links
+ */
+ if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
+ return bacl_exit_fatal;
+#endif
+
+ if (jcr->acl_data->u.build->content_length > 0) {
+ return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
+ }
+ return bacl_exit_ok;
+}
+
+static bacl_exit_code darwin_parse_acl_streams(JCR *jcr,
+ int stream,
+ char *content,
+ uint32_t content_length)
+{
+#if defined(HAVE_ACL_TYPE_EXTENDED)
+ return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED, content, content_length);
+#else
+ return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
+#endif
+}
+
+/*
+ * For this OS setup the build and parse function pointer to the OS specific functions.
+ */
+static bacl_exit_code (*os_build_acl_streams)
+ (JCR *jcr, FF_PKT *ff_pkt) =
+ darwin_build_acl_streams;
+static bacl_exit_code (*os_parse_acl_streams)
+ (JCR *jcr, int stream, char *content, uint32_t content_length) =
+ darwin_parse_acl_streams;
+
+#elif defined(HAVE_FREEBSD_OS)
+/*
+ * Define the supported ACL streams for these OSes
+ */
+static int os_access_acl_streams[2] = {
+ STREAM_ACL_FREEBSD_ACCESS_ACL,
+ STREAM_ACL_FREEBSD_NFS4_ACL
+};
+static int os_default_acl_streams[1] = {
+ STREAM_ACL_FREEBSD_DEFAULT_ACL
+};
+
+static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
+{
+ int acl_enabled = 0;
+ bacl_type acltype = BACL_TYPE_NONE;
+
+#if defined(_PC_ACL_NFS4)
+ /*
+ * See if filesystem supports NFS4 acls.
+ */
+ acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
+ switch (acl_enabled) {
+ case -1: {
+ berrno be;
+
+ switch (errno) {
+ case ENOENT:
+ return bacl_exit_ok;
+ default:
+ Mmsg2(jcr->errmsg,
+ _("pathconf error on file \"%s\": ERR=%s\n"),
+ jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "pathconf error file=%s ERR=%s\n",
+ jcr->last_fname, be.bstrerror());
+ return bacl_exit_error;
+ }
+ }
+ case 0:
+ break;
+ default:
+ acltype = BACL_TYPE_NFS4;
+ break;
+ }
+#endif
+
+ if (acl_enabled == 0) {
+ /*
+ * See if filesystem supports POSIX acls.
+ */
+ acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
+ switch (acl_enabled) {
+ case -1: {
+ berrno be;
+
+ switch (errno) {
+ case ENOENT:
+ return bacl_exit_ok;
+ default:
+ Mmsg2(jcr->errmsg,
+ _("pathconf error on file \"%s\": ERR=%s\n"),
+ jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "pathconf error file=%s ERR=%s\n",
+ jcr->last_fname, be.bstrerror());
+ return bacl_exit_error;
+ }
+ }
+ case 0:
+ break;
+ default:
+ acltype = BACL_TYPE_ACCESS;
+ break;
+ }
+ }
+
+ /*
+ * If the filesystem reports it doesn't support ACLs we clear the
+ * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
+ * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
+ * when we change from one filesystem to an other.
+ */
+ if (acl_enabled == 0) {
+ jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
+ pm_strcpy(jcr->acl_data->u.build->content, "");
+ jcr->acl_data->u.build->content_length = 0;
+ return bacl_exit_ok;
+ }
+
+ /*
+ * Based on the supported ACLs retrieve and store them.
+ */
+ switch (acltype) {
+ case BACL_TYPE_NFS4:
+ /*
+ * Read NFS4 ACLs for files, dirs and links
+ */
+ if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
+ return bacl_exit_fatal;
+
+ if (jcr->acl_data->u.build->content_length > 0) {
+ if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
+ return bacl_exit_fatal;
+ }
+ break;
+ case BACL_TYPE_ACCESS:
+ /*
+ * Read access ACLs for files, dirs and links
+ */
+ if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
+ return bacl_exit_fatal;
+
+ if (jcr->acl_data->u.build->content_length > 0) {
+ if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
+ return bacl_exit_fatal;
+ }
+
+ /*
+ * Directories can have default ACLs too
+ */
+ if (ff_pkt->type == FT_DIREND) {
+ if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
+ return bacl_exit_fatal;
+ if (jcr->acl_data->u.build->content_length > 0) {
+ if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
+ return bacl_exit_fatal;
+ }