+/*
+ * Cleanup of delayed restore stack with streams for later processing.
+ */
+static void drop_delayed_restore_streams(r_ctx &rctx, bool reuse)
+{
+ RESTORE_DATA_STREAM *rds;
+
+ if (!rctx.delayed_streams) {
+ if (reuse) {
+ rctx.delayed_streams = New(alist(10, owned_by_alist));
+ }
+ return;
+ }
+ if (rctx.delayed_streams->empty()) {
+ return;
+ }
+
+ foreach_alist(rds, rctx.delayed_streams) {
+ if (rds->content) {
+ free(rds->content);
+ rds->content = NULL;
+ }
+ }
+ rctx.delayed_streams->destroy();
+ if (reuse) {
+ rctx.delayed_streams->init(10, owned_by_alist);
+ }
+}
+
+
+/*
+ * Push a data stream onto the delayed restore stack for
+ * later processing.
+ */
+static inline void push_delayed_restore_stream(r_ctx &rctx, char *msg, int msglen)
+{
+ RESTORE_DATA_STREAM *rds;
+
+ if (msglen <= 0) {
+ return;
+ }
+ if (!rctx.delayed_streams) {
+ rctx.delayed_streams = New(alist(10, owned_by_alist));
+ }
+
+ rds = (RESTORE_DATA_STREAM *)malloc(sizeof(RESTORE_DATA_STREAM));
+ rds->stream = rctx.stream;
+ rds->content = (char *)malloc(msglen);
+ memcpy(rds->content, msg, msglen);
+ rds->content_length = msglen;
+ rctx.delayed_streams->append(rds);
+}
+
+/*
+ * Perform a restore of an ACL using the stream received.
+ * This can either be a delayed restore or direct restore.
+ */
+static inline bool do_restore_acl(JCR *jcr, int stream, char *content,
+ uint32_t content_length)
+{
+ if (!jcr->xacl) {
+ return true;
+ }
+ switch (jcr->xacl->restore_acl(jcr, stream, content, content_length)) {
+ case bRC_XACL_fatal:
+ return false;
+ case bRC_XACL_error:
+ /*
+ * Non-fatal errors, count them and when the number is under ACL_MAX_ERROR_PRINT_PER_JOB
+ * print the error message set by the lower level routine in jcr->errmsg.
+ */
+ if (jcr->xacl->get_acl_nr_errors() < ACL_MAX_ERROR_PRINT_PER_JOB) {
+ Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+/*
+ * Perform a restore of an XATTR using the stream received.
+ * This can either be a delayed restore or direct restore.
+ */
+static inline bool do_restore_xattr(JCR *jcr, int stream, char *content,
+ uint32_t content_length)
+{
+ if (!jcr->xacl) {
+ return true;
+ }
+ switch (jcr->xacl->restore_xattr(jcr, stream, content, content_length)) {
+ case bRC_XACL_fatal:
+ return false;
+ case bRC_XACL_error:
+ /*
+ * Non-fatal errors, count them and when the number is under XATTR_MAX_ERROR_PRINT_PER_JOB
+ * print the error message set by the lower level routine in jcr->errmsg.
+ */
+ if (jcr->xacl->get_xattr_nr_errors() < XATTR_MAX_ERROR_PRINT_PER_JOB) {
+ Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+/*
+ * Restore any data streams that are restored after the file
+ * is fully restored and has its attributes restored. Things
+ * like acls and xattr are restored after we set the file
+ * attributes otherwise we might clear some security flags
+ * by setting the attributes.
+ */
+static inline bool pop_delayed_data_streams(r_ctx &rctx)
+{
+ RESTORE_DATA_STREAM *rds;
+ JCR *jcr = rctx.jcr;
+
+ /*
+ * See if there is anything todo.
+ */
+ if (!rctx.delayed_streams ||
+ rctx.delayed_streams->empty()) {
+ return true;
+ }
+
+ /*
+ * Only process known delayed data streams here.
+ * If you start using more delayed data streams
+ * be sure to add them in this loop and add the
+ * proper calls here.
+ *
+ * Currently we support delayed data stream
+ * processing for the following type of streams:
+ * - *_ACL_*
+ * - *_XATTR_*
+ */
+ foreach_alist(rds, rctx.delayed_streams) {
+ switch (rds->stream) {
+ case STREAM_UNIX_ACCESS_ACL:
+ case STREAM_UNIX_DEFAULT_ACL:
+ case STREAM_XACL_AIX_TEXT:
+ case STREAM_XACL_DARWIN_ACCESS:
+ case STREAM_XACL_FREEBSD_DEFAULT:
+ case STREAM_XACL_FREEBSD_ACCESS:
+ case STREAM_XACL_HPUX_ACL_ENTRY:
+ case STREAM_XACL_IRIX_DEFAULT:
+ case STREAM_XACL_IRIX_ACCESS:
+ case STREAM_XACL_LINUX_DEFAULT:
+ case STREAM_XACL_LINUX_ACCESS:
+ case STREAM_XACL_TRU64_DEFAULT:
+ case STREAM_XACL_TRU64_DEFAULT_DIR:
+ case STREAM_XACL_TRU64_ACCESS:
+ case STREAM_XACL_SOLARIS_POSIX:
+ case STREAM_XACL_SOLARIS_NFS4:
+ case STREAM_XACL_AFS_TEXT:
+ case STREAM_XACL_AIX_AIXC:
+ case STREAM_XACL_AIX_NFS4:
+ case STREAM_XACL_FREEBSD_NFS4:
+ case STREAM_XACL_HURD_DEFAULT:
+ case STREAM_XACL_HURD_ACCESS:
+ if (!do_restore_acl(jcr, rds->stream, rds->content, rds->content_length)) {
+ goto get_out;
+ }
+ break;
+ case STREAM_XACL_HURD_XATTR:
+ case STREAM_XACL_IRIX_XATTR:
+ case STREAM_XACL_TRU64_XATTR:
+ case STREAM_XACL_AIX_XATTR:
+ case STREAM_XACL_OPENBSD_XATTR:
+ case STREAM_XACL_SOLARIS_SYS_XATTR:
+ case STREAM_XACL_DARWIN_XATTR:
+ case STREAM_XACL_FREEBSD_XATTR:
+ case STREAM_XACL_LINUX_XATTR:
+ case STREAM_XACL_NETBSD_XATTR:
+ if (!do_restore_xattr(jcr, rds->stream, rds->content, rds->content_length)) {
+ goto get_out;
+ }
+ break;
+ default:
+ Jmsg(jcr, M_WARNING, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"),
+ rds->stream);
+ break;
+ }
+ if (rds->content) {
+ free(rds->content);
+ rds->content = NULL;
+ }
+ }
+
+ drop_delayed_restore_streams(rctx, true);
+ return true;
+
+get_out:
+ drop_delayed_restore_streams(rctx, true);
+ return false;
+}
+
+