+struct OBJ_CTX {
+ JCR *jcr;
+ int count;
+};
+
+static int restore_object_handler(void *ctx, int num_fields, char **row)
+{
+ OBJ_CTX *octx = (OBJ_CTX *)ctx;
+ JCR *jcr = octx->jcr;
+ BSOCK *fd;
+
+ fd = jcr->file_bsock;
+ if (jcr->is_job_canceled()) {
+ return 1;
+ }
+ /* Old File Daemon doesn't handle restore objects */
+ if (jcr->FDVersion < 3) {
+ Jmsg(jcr, M_WARNING, 0, _("Client \"%s\" may not be used to restore "
+ "this job. Please upgrade your client.\n"),
+ jcr->client->name());
+ return 1;
+ }
+
+ if (jcr->FDVersion < 5) { /* Old version without PluginName */
+ fd->fsend("restoreobject JobId=%s %s,%s,%s,%s,%s,%s\n",
+ row[0], row[1], row[2], row[3], row[4], row[5], row[6]);
+ } else {
+ /* bash spaces from PluginName */
+ bash_spaces(row[9]);
+ fd->fsend("restoreobject JobId=%s %s,%s,%s,%s,%s,%s,%s\n",
+ row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[9]);
+ }
+ Dmsg1(010, "Send obj hdr=%s", fd->msg);
+
+ fd->msglen = pm_strcpy(fd->msg, row[7]);
+ fd->send(); /* send Object name */
+
+ Dmsg1(010, "Send obj: %s\n", fd->msg);
+
+// fd->msglen = str_to_uint64(row[1]); /* object length */
+// Dmsg1(000, "obj size: %lld\n", (uint64_t)fd->msglen);
+
+ /* object */
+ db_unescape_object(jcr, jcr->db,
+ row[8], /* Object */
+ str_to_uint64(row[1]), /* Object length */
+ &fd->msg, &fd->msglen);
+ fd->send(); /* send object */
+ octx->count++;
+
+ if (debug_level > 100) {
+ for (int i=0; i < fd->msglen; i++)
+ if (!fd->msg[i])
+ fd->msg[i] = ' ';
+ Dmsg1(000, "Send obj: %s\n", fd->msg);
+ }
+
+ return 0;
+}
+
+/*
+ * Send the plugin Restore Objects, which allow the
+ * plugin to get information early in the restore
+ * process. The RestoreObjects were created during
+ * the backup by the plugin.
+ */
+bool send_restore_objects(JCR *jcr)
+{
+ char ed1[50];
+ POOL_MEM query(PM_MESSAGE);
+ BSOCK *fd;
+ OBJ_CTX octx;
+
+ if (!jcr->JobIds || !jcr->JobIds[0]) {
+ return true;
+ }
+ octx.jcr = jcr;
+ octx.count = 0;
+
+ /* restore_object_handler is called for each file found */
+
+ /* send restore objects for all jobs involved */
+ Mmsg(query, get_restore_objects, jcr->JobIds, FT_RESTORE_FIRST);
+ db_sql_query(jcr->db, query.c_str(), restore_object_handler, (void *)&octx);
+
+ /* send config objects for the current restore job */
+ Mmsg(query, get_restore_objects,
+ edit_uint64(jcr->JobId, ed1), FT_PLUGIN_CONFIG_FILLED);
+ db_sql_query(jcr->db, query.c_str(), restore_object_handler, (void *)&octx);
+
+ /*
+ * Send to FD only if we have at least one restore object.
+ * This permits backward compatibility with older FDs.
+ */
+ if (octx.count > 0) {
+ fd = jcr->file_bsock;
+ fd->fsend("restoreobject end\n");
+ if (!response(jcr, fd, OKRestoreObject, "RestoreObject", DISPLAY_ERROR)) {
+ Jmsg(jcr, M_FATAL, 0, _("RestoreObject failed.\n"));
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ * Send the plugin a list of component info files. These
+ * were files that were created during the backup for
+ * the VSS plugin. The list is a list of those component
+ * files that have been chosen for restore. We
+ * send them before the Restore Objects.
+ */
+bool send_component_info(JCR *jcr)
+{
+ BSOCK *fd;
+ char buf[2000];
+ bool ok = true;
+
+ if (!jcr->component_fd) {
+ return true; /* nothing to send */
+ }
+ /* Don't send if old version FD */
+ if (jcr->FDVersion < 6) {
+ goto bail_out;
+ }