+ /*
+ * First see how big the buffers should be.
+ */
+ memset(&type, 0, sizeof(acl_type_t));
+ type.u64 = ACL_ANY;
+ if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, &mode) < 0) {
+ berrno be;
+ if (errno == ENOENT) {
+ retval = bacl_rtn_ok;
+ } else if (errno == ENOSYS) {
+ /*
+ * 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.
+ */
+ jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
+ retval = bacl_rtn_ok;
+ } else {
+ Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
+ jcr->last_fname, be.bstrerror());
+ Dmsg1(100, "%s", jcr->errmsg);
+ }
+ goto get_out;
+ }
+
+ /*
+ * Make sure the buffers are big enough.
+ */
+ aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
+
+ /*
+ * Retrieve the ACL info.
+ */
+ if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
+ berrno be;
+ if (errno == ENOENT) {
+ retval = bacl_rtn_ok;
+ } else {
+ Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
+ jcr->last_fname, be.bstrerror());
+ Dmsg1(100, "%s", jcr->errmsg);
+ }
+ goto get_out;
+ }
+
+ /*
+ * See if the acl is non trivial.
+ */
+ switch (type.u64) {
+ case ACL_AIXC:
+ if (acl_is_trivial((struct acl *)aclbuf)) {
+ retval = bacl_rtn_ok;
+ goto get_out;
+ }
+ break;
+ case ACL_NFS4:
+ if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
+ retval = bacl_rtn_ok;
+ goto get_out;
+ }
+ break;
+ default:
+ Mmsg2(jcr->errmsg, _("Unknown acl type encountered on file \"%s\": %ld\n"),
+ jcr->last_fname, type.u64);
+ Dmsg1(100, "%s", jcr->errmsg);
+ goto get_out;
+ }
+
+ /*
+ * We have a non-trivial acl lets convert it into some ASCII form.
+ */
+ acltxtsize = sizeof_pool_memory(jcr->acl_ctx->content);
+ if (aclx_printStr(jcr->acl_ctx->content, &acltxtsize, aclbuf,
+ aclsize, type, jcr->last_fname, 0) < 0) {
+ if ((errno == ENOSPC) {
+ /*
+ * Our buffer is not big enough, acltxtsize should be updated with the value
+ * the aclx_printStr really need. So we increase the buffer and try again.
+ */
+ jcr->acl_ctx->content = check_pool_memory_size(jcr->acl_ctx->content, acltxtsize + 1);
+ if (aclx_printStr(jcr->acl_ctx->content, &acltxtsize, aclbuf,
+ aclsize, type, jcr->last_fname, 0) < 0) {
+ Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
+ jcr->last_fname);
+ Dmsg1(100, "%s", jcr->errmsg);
+ goto get_out;
+ }
+ } else {
+ Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
+ jcr->last_fname);
+ Dmsg1(100, "%s", jcr->errmsg);
+ goto get_out;
+ }
+ }
+
+ jcr->acl_ctx->content_length = strlen(jcr->acl_ctx->content) + 1;
+ switch (type.u64) {
+ case ACL_AIXC:
+ retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
+ break;
+ case ACL_NFS4:
+ retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
+ break;
+ }
+
+get_out:
+ free_pool_memory(aclbuf);
+
+ return retval;
+}
+
+/*
+ * See if a specific type of ACLs are supported on the filesystem
+ * the file is located on.
+ */
+static inline bool aix_query_acl_support(JCR *jcr,
+ uint64_t aclType,
+ acl_type_t *pacl_type_info)
+{
+ unsigned int i;
+ acl_types_list_t acl_type_list;
+ size_t acl_type_list_len = sizeof(acl_types_list_t);
+
+ memset(&acl_type_list, 0, sizeof(acl_type_list));
+ if (aclx_gettypes(jcr->last_fname, &acl_type_list, &acl_type_list_len)) {
+ return false;
+ }
+
+ for (i = 0; i < acl_type_list.num_entries; i++) {
+ if (acl_type_list.entries[i].u64 == aclType) {
+ memcpy(pacl_type_info, acl_type_list.entries + i, sizeof(acl_type_t));
+ return true;
+ }
+ }
+ return false;
+}
+
+static bacl_rtn_code aix_restore_acl_streams(JCR *jcr,
+ int stream,
+ char *content,
+ uint32_t content_length)
+{
+ int cnt;
+ acl_type_t type;
+ size_t aclsize;
+ bacl_rtn_code retval = bacl_rtn_error;
+ POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
+
+ switch (stream) {
+ case STREAM_ACL_AIX_TEXT:
+ /*
+ * Handle the old stream using the old system call for now.
+ */
+ if (acl_put(jcr->last_fname, content, 0) != 0) {
+ retval = bacl_rtn_error;
+ goto get_out;
+ }
+ retval = bacl_rtn_ok;
+ goto get_out;
+ case STREAM_ACL_AIX_AIXC:
+ if (!aix_query_acl_support(jcr, ACL_AIXC, &type)) {
+ Mmsg1(jcr->errmsg,
+ _("Trying to restore POSIX acl on file \"%s\" on filesystem without AIXC acl support\n"),
+ jcr->last_fname);
+ goto get_out;
+ }
+ break;
+ case STREAM_ACL_AIX_NFS4:
+ if (!aix_query_acl_support(jcr, ACL_NFS4, &type)) {
+ Mmsg1(jcr->errmsg,
+ _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without NFS4 acl support\n"),
+ jcr->last_fname);
+ goto get_out;
+ }
+ break;
+ default:
+ goto get_out;
+ }
+
+ /*
+ * Set the acl buffer to an initial size. For now we set it
+ * to the same size as the ASCII representation.
+ */
+ aclbuf = check_pool_memory_size(aclbuf, content_length);
+ aclsize = content_length;
+ if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
+ berrno be;
+ if (errno == ENOSPC) {
+ /*
+ * The buffer isn't big enough. The man page doesn't say that aclsize
+ * is updated to the needed size as what is done with aclx_printStr.
+ * So for now we try to increase the buffer a maximum of 3 times
+ * and retry the conversion.
+ */
+ for (cnt = 0; cnt < 3; cnt++) {
+ aclsize = 2 * aclsize;
+ aclbuf = check_pool_memory_size(aclbuf, aclsize);
+
+ if (aclx_scanStr(content, aclbuf, &aclsize, type) == 0) {
+ break;
+ }
+
+ /*
+ * See why we failed this time, ENOSPC retry if max retries not met,
+ * otherwise abort.
+ */
+ if (errno == ENOSPC && cnt < 3) {
+ continue;
+ }
+ Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
+ jcr->last_fname, be.bstrerror(errno));
+ Dmsg1(100, "%s", jcr->errmsg);
+ goto get_out;
+ }
+ } else {
+ Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
+ jcr->last_fname, be.bstrerror());
+ Dmsg1(100, "%s", jcr->errmsg);
+ goto get_out
+ }
+ }
+
+ if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
+ berrno be;
+ if (errno == ENOENT) {
+ retval = bacl_rtn_ok;
+ } else if (ENOSYS) {
+ /*
+ * 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_ctx->flags &= ~BACL_FLAG_RESTORE_NATIVE;
+ } else {
+ Mmsg2(jcr->errmsg, _("aclx_put error on file \"%s\": ERR=%s\n"),
+ jcr->last_fname, be.bstrerror());
+ Dmsg1(100, "%s", jcr->errmsg);
+ goto get_out;
+ }
+ }
+
+ retval = bacl_rtn_ok;
+
+get_out:
+ free_pool_memory(aclbuf);
+ return retval;
+}
+
+#else /* HAVE_EXTENDED_ACL */
+
+#include <sys/access.h>
+
+/*
+ * Define the supported ACL streams for this OS
+ */
+static int os_access_acl_streams[1] = {
+ STREAM_ACL_AIX_TEXT
+};
+static int os_default_acl_streams[1] = {
+ -1
+};
+
+static bacl_rtn_code aix_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)