/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
The main author of Bacula is Kern Sibbald, with contributions from
many others, a complete list can be found in the file AUTHORS.
const bool have_lzo = false;
#endif
-
static void deallocate_cipher(r_ctx &rctx);
static void deallocate_fork_cipher(r_ctx &rctx);
static void free_signature(r_ctx &rctx);
static void free_session(r_ctx &rctx);
-static void close_previous_stream(r_ctx &rctx);
-
+static bool close_previous_stream(JCR *jcr, r_ctx &rctx);
static bool verify_signature(JCR *jcr, r_ctx &rctx);
int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
uint64_t *addr, int flags, int32_t stream, RESTORE_CIPHER_CTX *cipher_ctx);
}
#ifdef HAVE_DARWIN_OS
-bool restore_finderinfo(JCR *jcr, POOLMEM *buf, int32_t buflen)
+static bool restore_finderinfo(JCR *jcr, POOLMEM *buf, int32_t buflen)
{
struct attrlist attrList;
return true;
}
#else
-bool restore_finderinfo(JCR *jcr, POOLMEM *buf, int32_t buflen)
+static bool restore_finderinfo(JCR *jcr, POOLMEM *buf, int32_t buflen)
{
return true;
}
#endif
+/*
+ * Cleanup of delayed restore stack with streams for later
+ * processing.
+ */
+static inline void drop_delayed_restore_streams(r_ctx &rctx, bool reuse)
+{
+ RESTORE_DATA_STREAM *rds;
+
+ if (!rctx.delayed_streams ||
+ rctx.delayed_streams->empty()) {
+ return;
+ }
+
+ foreach_alist(rds, rctx.delayed_streams) {
+ free(rds->content);
+ }
+
+ 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, BSOCK *sd)
+{
+ RESTORE_DATA_STREAM *rds;
+
+ 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(sd->msglen);
+ memcpy(rds->content, sd->msg, sd->msglen);
+ rds->content_length = sd->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)
+{
+ switch (parse_acl_streams(jcr, stream)) {
+ case bacl_exit_fatal:
+ return false;
+ case bacl_exit_error:
+ /*
+ * Non-fatal errors, count them and when the number is under ACL_REPORT_ERR_MAX_PER_JOB
+ * print the error message set by the lower level routine in jcr->errmsg.
+ */
+ if (jcr->acl_data->nr_errors < ACL_REPORT_ERR_MAX_PER_JOB) {
+ Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+ }
+ jcr->acl_data->nr_errors++;
+ break;
+ case bacl_exit_ok:
+ 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)
+{
+ switch (parse_xattr_streams(jcr, stream)) {
+ case bxattr_exit_fatal:
+ return false;
+ case bxattr_exit_error:
+ /*
+ * Non-fatal errors, count them and when the number is under XATTR_REPORT_ERR_MAX_PER_JOB
+ * print the error message set by the lower level routine in jcr->errmsg.
+ */
+ if (jcr->xattr_data->nr_errors < XATTR_REPORT_ERR_MAX_PER_JOB) {
+ Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+ }
+ jcr->xattr_data->nr_errors++;
+ break;
+ case bxattr_exit_ok:
+ 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(JCR *jcr, r_ctx &rctx)
+{
+ RESTORE_DATA_STREAM *rds;
+
+ /*
+ * 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_ACL_AIX_TEXT:
+ case STREAM_ACL_DARWIN_ACCESS_ACL:
+ case STREAM_ACL_FREEBSD_DEFAULT_ACL:
+ case STREAM_ACL_FREEBSD_ACCESS_ACL:
+ case STREAM_ACL_HPUX_ACL_ENTRY:
+ case STREAM_ACL_IRIX_DEFAULT_ACL:
+ case STREAM_ACL_IRIX_ACCESS_ACL:
+ case STREAM_ACL_LINUX_DEFAULT_ACL:
+ case STREAM_ACL_LINUX_ACCESS_ACL:
+ case STREAM_ACL_TRU64_DEFAULT_ACL:
+ case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
+ case STREAM_ACL_TRU64_ACCESS_ACL:
+ case STREAM_ACL_SOLARIS_ACLENT:
+ case STREAM_ACL_SOLARIS_ACE:
+ case STREAM_ACL_AFS_TEXT:
+ case STREAM_ACL_AIX_AIXC:
+ case STREAM_ACL_AIX_NFS4:
+ case STREAM_ACL_FREEBSD_NFS4_ACL:
+ pm_memcpy(jcr->acl_data->content, rds->content, rds->content_length);
+ jcr->acl_data->content_length = rds->content_length;
+ if (!do_restore_acl(jcr, rds->stream)) {
+ goto bail_out;
+ }
+ free(rds->content);
+ break;
+ case STREAM_XATTR_IRIX:
+ case STREAM_XATTR_TRU64:
+ case STREAM_XATTR_AIX:
+ case STREAM_XATTR_OPENBSD:
+ case STREAM_XATTR_SOLARIS_SYS:
+ case STREAM_XATTR_DARWIN:
+ case STREAM_XATTR_FREEBSD:
+ case STREAM_XATTR_LINUX:
+ case STREAM_XATTR_NETBSD:
+ pm_memcpy(jcr->xattr_data->content, rds->content, rds->content_length);
+ jcr->xattr_data->content_length = rds->content_length;
+ if (!do_restore_xattr(jcr, rds->stream)) {
+ goto bail_out;
+ }
+ free(rds->content);
+ break;
+ default:
+ Jmsg(jcr, M_WARNING, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"),
+ rds->stream);
+ break;
+ }
+ }
+
+ /*
+ * We processed the stack so we can destroy it.
+ */
+ rctx.delayed_streams->destroy();
+
+ /*
+ * (Re)Initialize the stack for a new use.
+ */
+ rctx.delayed_streams->init(10, owned_by_alist);
+
+ return true;
+
+bail_out:
+
+ /*
+ * Destroy the content of the stack and (re)initialize it for a new use.
+ */
+ drop_delayed_restore_streams(rctx, true);
+
+ return false;
+}
+
/*
* Restore the requested files.
*/
/*
* if any previous stream open, close it
*/
- close_previous_stream(rctx);
+ if (!close_previous_stream(jcr, rctx)) {
+ goto bail_out;
+ }
/*
* TODO: manage deleted files
* b) and it is not a directory (they are never "extracted")
* c) or the file name is empty
*/
- if ((!rctx.extract && jcr->last_type != FT_DIREND) || (*jcr->last_fname == 0)) {
+ if ((!rctx.extract &&
+ jcr->last_type != FT_DIREND) ||
+ (*jcr->last_fname == 0)) {
break;
}
if (have_acl) {
- pm_memcpy(jcr->acl_data->content, sd->msg, sd->msglen);
- jcr->acl_data->content_length = sd->msglen;
- switch (parse_acl_streams(jcr, rctx.stream)) {
- case bacl_exit_fatal:
- goto bail_out;
- case bacl_exit_error:
- /*
- * Non-fatal errors, count them and when the number is under ACL_REPORT_ERR_MAX_PER_JOB
- * print the error message set by the lower level routine in jcr->errmsg.
- */
- if (jcr->acl_data->nr_errors < ACL_REPORT_ERR_MAX_PER_JOB) {
- Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+ /*
+ * For anything that is not a directory we delay
+ * the restore of acls till a later stage.
+ */
+ if (jcr->last_type != FT_DIREND) {
+ push_delayed_restore_stream(rctx, sd);
+ } else {
+ pm_memcpy(jcr->acl_data->content, sd->msg, sd->msglen);
+ jcr->acl_data->content_length = sd->msglen;
+ if (!do_restore_acl(jcr, rctx.stream)) {
+ goto bail_out;
}
- jcr->acl_data->nr_errors++;
- break;
- case bacl_exit_ok:
- break;
}
} else {
non_support_acl++;
case STREAM_XATTR_AIX:
case STREAM_XATTR_OPENBSD:
case STREAM_XATTR_SOLARIS_SYS:
- case STREAM_XATTR_SOLARIS:
case STREAM_XATTR_DARWIN:
case STREAM_XATTR_FREEBSD:
case STREAM_XATTR_LINUX:
* b) and it is not a directory (they are never "extracted")
* c) or the file name is empty
*/
- if ((!rctx.extract && jcr->last_type != FT_DIREND) || (*jcr->last_fname == 0)) {
+ if ((!rctx.extract &&
+ jcr->last_type != FT_DIREND) ||
+ (*jcr->last_fname == 0)) {
+ break;
+ }
+ if (have_xattr) {
+ /*
+ * For anything that is not a directory we delay
+ * the restore of xattr till a later stage.
+ */
+ if (jcr->last_type != FT_DIREND) {
+ push_delayed_restore_stream(rctx, sd);
+ } else {
+ pm_memcpy(jcr->xattr_data->content, sd->msg, sd->msglen);
+ jcr->xattr_data->content_length = sd->msglen;
+ if (!do_restore_xattr(jcr, rctx.stream)) {
+ goto bail_out;
+ }
+ }
+ } else {
+ non_support_xattr++;
+ }
+ break;
+
+ case STREAM_XATTR_SOLARIS:
+ /*
+ * Do not restore Extended Attributes when
+ * a) The current file is not extracted
+ * b) and it is not a directory (they are never "extracted")
+ * c) or the file name is empty
+ */
+ if ((!rctx.extract &&
+ jcr->last_type != FT_DIREND) ||
+ (*jcr->last_fname == 0)) {
break;
}
if (have_xattr) {
pm_memcpy(jcr->xattr_data->content, sd->msg, sd->msglen);
jcr->xattr_data->content_length = sd->msglen;
- switch (parse_xattr_streams(jcr, rctx.stream)) {
- case bxattr_exit_fatal:
+ if (!do_restore_xattr(jcr, rctx.stream)) {
goto bail_out;
- case bxattr_exit_error:
- /*
- * Non-fatal errors, count them and when the number is under XATTR_REPORT_ERR_MAX_PER_JOB
- * print the error message set by the lower level routine in jcr->errmsg.
- */
- if (jcr->xattr_data->nr_errors < XATTR_REPORT_ERR_MAX_PER_JOB) {
- Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
- }
- jcr->xattr_data->nr_errors++;
- break;
- case bxattr_exit_ok:
- break;
}
} else {
non_support_xattr++;
break;
case STREAM_PLUGIN_NAME:
- close_previous_stream(rctx);
+ if (!close_previous_stream(jcr, rctx)) {
+ goto bail_out;
+ }
Dmsg1(50, "restore stream_plugin_name=%s\n", sd->msg);
plugin_name_stream(jcr, sd->msg);
break;
break; /* these are sent by Director */
default:
- close_previous_stream(rctx);
+ if (!close_previous_stream(jcr, rctx)) {
+ goto bail_out;
+ }
Jmsg(jcr, M_WARNING, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"),
rctx.stream);
Dmsg2(0, "Unknown stream=%d data=%s\n", rctx.stream, sd->msg);
bclose_chksize(jcr, &rctx.forkbfd, rctx.fork_size);
}
- close_previous_stream(rctx);
+ if (!close_previous_stream(jcr, rctx)) {
+ goto bail_out;
+ }
jcr->setJobStatus(JS_Terminated);
goto ok_out;
jcr->xattr_data = NULL;
}
+ /*
+ * Free the delayed stream stack list.
+ */
+ if (rctx.delayed_streams) {
+ drop_delayed_restore_streams(rctx, false);
+ delete rctx.delayed_streams;
+ }
+
bclose(&rctx.forkbfd);
bclose(&rctx.bfd);
free_attr(rctx.attr);
bool decompress_data(JCR *jcr, int32_t stream, char **data, uint32_t *length)
{
+#if defined(HAVE_LZO) || defined(HAVE_LIBZ)
char ec1[50]; /* Buffer printing huge values */
+#endif
Dmsg1(200, "Stream found in decompress_data(): %d\n", stream);
if(stream == STREAM_COMPRESSED_DATA || stream == STREAM_SPARSE_COMPRESSED_DATA || stream == STREAM_WIN32_COMPRESSED_DATA
return -1;
}
-
/*
* If extracting, close any previous stream
*/
-static void close_previous_stream(r_ctx &rctx)
+static bool close_previous_stream(JCR *jcr, r_ctx &rctx)
{
/*
* If extracting, it was from previous stream, so
}
rctx.extract = false;
+ /*
+ * Now perform the delayed restore of some specific data streams.
+ */
+ if (!pop_delayed_data_streams(jcr, rctx)) {
+ return false;
+ }
+
/*
* Verify the cryptographic signature, if any
*/
Dmsg0(000, "=== logic error !open\n");
bclose(&rctx.bfd);
}
-}
+ return true;
+}
/*
* In the context of jcr, flush any remaining data from the cipher context,