]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
metaplugin: Add RestoreObject support.
authorRadosław Korzeniewski <radoslaw@korzeniewski.net>
Fri, 2 Jul 2021 07:23:21 +0000 (09:23 +0200)
committerEric Bollengier <eric@baculasystems.com>
Thu, 24 Mar 2022 08:03:03 +0000 (09:03 +0100)
With this patch the backend can handle Restore Object save and
receive.

bacula/src/plugins/fd/pluginlib/metaplugin.cpp
bacula/src/plugins/fd/pluginlib/metaplugin.h
bacula/src/plugins/fd/pluginlib/ptcomm.cpp
bacula/src/plugins/fd/pluginlib/ptcomm.h
bacula/src/plugins/fd/pluginlib/test_metaplugin_backend.c

index bc4629540a0a6e15422cfd9a9ec31b1171e15b43..0640e995c6169b199bdd77efad9518222accb5ea 100644 (file)
@@ -376,17 +376,19 @@ bRC METAPLUGIN::parse_plugin_command(bpContext *ctx, const char *command, alist
  *    bRC_OK - on success
  *    bRC_Error - on error
  */
-bRC METAPLUGIN::parse_plugin_restoreobj(bpContext *ctx, restore_object_pkt *rop)
+bRC METAPLUGIN::handle_plugin_restoreobj(bpContext *ctx, restore_object_pkt *rop)
 {
    if (!rop){
       return bRC_OK;    /* end of rop list */
    }
 
-   if (!strcmp(rop->object_name, INI_RESTORE_OBJECT_NAME)) {
-      /* we have a single RO for every backend */
-      backend.switch_command(rop->plugin_name);
+   /* we have a single RO for every backend */
+   backend.switch_command(rop->plugin_name);
 
-      DMSG(ctx, DINFO, "INIcmd: %s\n", rop->plugin_name);
+   // if (strcmp(rop->object_name, INI_RESTORE_OBJECT_NAME) == 0) {
+   if (strcmp(rop->object_name, INI_RESTORE_OBJECT_NAME) == 0 && rop->object_type == FT_PLUGIN_CONFIG) {
+
+      DMSG2(ctx, DINFO, "INIcmd: %s %d\n", rop->plugin_name, rop->object_type);
 
       ini.clear_items();
       if (!ini.dump_string(rop->object, rop->object_len))
@@ -404,8 +406,7 @@ bRC METAPLUGIN::parse_plugin_restoreobj(bpContext *ctx, restore_object_pkt *rop)
          return bRC_Error;
       }
 
-      for (int i=0; ini.items[i].name; i++)
-      {
+      for (int i = 0; ini.items[i].name; i++) {
          if (ini.items[i].found){
             if (ini.items[i].handler == ini_store_str){
                DMSG2(ctx, DINFO, "INI: %s = %s\n", ini.items[i].name, ini.items[i].val.strval);
@@ -422,8 +423,20 @@ bRC METAPLUGIN::parse_plugin_restoreobj(bpContext *ctx, restore_object_pkt *rop)
             }
          }
       }
+
+      return bRC_OK;
    }
 
+   // handle any other RO restore
+   restore_object_class *ropclass = new restore_object_class;
+   ropclass->sent = false;
+   pm_strcpy(ropclass->plugin_name, rop->plugin_name);
+   pm_strcpy(ropclass->object_name, rop->object_name);
+   ropclass->length = rop->object_len;
+   pm_memcpy(ropclass->data, rop->object, rop->object_len);
+   restoreobject_list.append(ropclass);
+   DMSG2(ctx, DINFO, "ROclass saved for later: %s %d\n", ropclass->object_name.c_str(), ropclass->length);
+
    return bRC_OK;
 }
 
@@ -1242,7 +1255,7 @@ bRC METAPLUGIN::handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
    /* Plugin command e.g. plugin = <plugin-name>:parameters */
    case bEventBackupCommand:
       DMSG(ctx, D2, "bEventBackupCommand value=%s\n", NPRT((char *)value));
-      robjsent = false;
+      pluginconfigsent = false;
       return prepare_backend(ctx, BACKEND_JOB_INFO_BACKUP, (char*)value);
 
    /* Plugin command e.g. plugin = <plugin-name>:parameters */
@@ -1285,7 +1298,7 @@ bRC METAPLUGIN::handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
          break;
       }
       DMSG(ctx, D2, "bEventRestoreObject value=%p\n", value);
-      return parse_plugin_restoreobj(ctx, (restore_object_pkt *) value);
+      return handle_plugin_restoreobj(ctx, (restore_object_pkt *) value);
 
    case bEventCancelCommand:
       DMSG2(ctx, D3, "bEventCancelCommand self = %p pctx = %p\n", this, pctx);
@@ -1690,7 +1703,8 @@ bRC METAPLUGIN::perform_read_metadata(bpContext *ctx)
 
    DMSG0(ctx, DDEBUG, "perform_read_metadata()\n");
    // setup flags
-   nextfile = pluginobject = readacl = readxattr = false;
+   nextfile = readacl = readxattr = false;
+   objectsent = false;
    // loop on metadata from backend or EOD which means no more files to backup
    while (true)
    {
@@ -1700,12 +1714,21 @@ bRC METAPLUGIN::perform_read_metadata(bpContext *ctx)
          if (scan_parameter_str(cmd, "FNAME:", fname)){
             /* got FNAME: */
             nextfile = true;
+            object = FileObject;
             return bRC_OK;
          }
          if (scan_parameter_str(cmd, "PLUGINOBJ:", fname)){
             /* got Plugin Object header */
             nextfile = true;
-            pluginobject = true;
+            object = PluginObject;
+            // pluginobject = true;
+            return bRC_OK;
+         }
+         if (scan_parameter_str(cmd, "RESTOREOBJ:", fname)){
+            /* got Restore Object header */
+            nextfile = true;
+            object = RestoreObject;
+            // restoreobject = true;
             return bRC_OK;
          }
          if (bstrcmp(cmd.c_str(), "ACL")){
@@ -1761,9 +1784,9 @@ bRC METAPLUGIN::perform_file_index_query(bpContext *ctx)
 /**
  * @brief
  *
- * @param ctx
- * @param sp
- * @return bRC
+ * @param ctx bpContext - for Bacula debug and jobinfo messages
+ * @param sp save_pkt from startBackupFile()
+ * @return bRC bRC_OK when success, bRC_Error if not
  */
 bRC METAPLUGIN::perform_read_pluginobject(bpContext *ctx, struct save_pkt *sp)
 {
@@ -1835,8 +1858,9 @@ bRC METAPLUGIN::perform_read_pluginobject(bpContext *ctx, struct save_pkt *sp)
          if (backend.ctx->is_eod()){
             /* no more plugin object params to backup */
             DMSG0(ctx, DINFO, "No more Plugin Object params from backend.\n");
-            pluginobject = false;
-            pluginobjectsent = true;
+            // pluginobject = false;
+            // pluginobjectsent = true;
+            objectsent = true;
             return bRC_OK;
          }
       }
@@ -1845,6 +1869,75 @@ bRC METAPLUGIN::perform_read_pluginobject(bpContext *ctx, struct save_pkt *sp)
    return bRC_Error;
 }
 
+/**
+ * @brief Receives a Restore Object data and populates save_pkt.
+ *
+ * @param ctx bpContext - for Bacula debug and jobinfo messages
+ * @param sp save_pkt from startBackupFile()
+ * @return bRC bRC_OK when success, bRC_Error if not
+ */
+bRC METAPLUGIN::perform_read_restoreobject(bpContext *ctx, struct save_pkt *sp)
+{
+   POOL_MEM cmd(PM_FNAME);
+
+   sp->restore_obj.object = NULL;
+
+   if (strlen(fname.c_str()) == 0){
+      // input variable is not valid
+      return bRC_Error;
+   }
+
+   DMSG0(ctx, DDEBUG, "perform_read_restoreobject()\n");
+   // read object length required param
+   if (backend.ctx->read_command(ctx, cmd) > 0) {
+      DMSG(ctx, DDEBUG, "read_command(4): %s\n", cmd.c_str());
+      POOL_MEM param(PM_NAME);
+      uint64_t length;
+      if (scan_parameter_str(cmd, "RESTOREOBJ_LEN:", param)) {
+         if (!size_to_uint64(param.c_str(), strlen(param.c_str()), &length)){
+            // error in convert
+            DMSG1(ctx, DERROR, "Cannot convert Restore Object length to integer! p=%s\n", param.c_str());
+            JMSG1(ctx, M_ERROR, "Cannot convert Restore Object length to integer! p=%s\n", param.c_str());
+            return bRC_Error;
+         }
+         DMSG1(ctx, DDEBUG, "size: %llu\n", length);
+         sp->restore_obj.object_len = length;
+         robjbuf.check_size(length + 1);
+      } else {
+         // no required param
+         DMSG0(ctx, DERROR, "Cannot read Restore Object length!\n");
+         JMSG0(ctx, M_ERROR, "Cannot read Restore Object length!\n");
+         return bRC_Error;
+      }
+   } else {
+      if (backend.ctx->is_fatal()){
+         /* raise up error from backend */
+         return bRC_Error;
+      }
+   }
+
+   int32_t recv_len = 0;
+
+   if (backend.ctx->recv_data(ctx, robjbuf, &recv_len) != bRC_OK) {
+      DMSG0(ctx, DERROR, "Cannot read data from backend!\n");
+      return bRC_Error;
+   }
+
+   /* no more restore object data to backup */
+   DMSG0(ctx, DINFO, "No more Restore Object data from backend.\n");
+   objectsent = true;
+
+   if (recv_len != sp->restore_obj.object_len) {
+      DMSG2(ctx, DERROR, "Backend reported RO length:%ld read:%ld\n", sp->restore_obj.object_len, recv_len);
+      JMSG2(ctx, M_ERROR, "Backend reported RO length:%ld read:%ld\n", sp->restore_obj.object_len, recv_len);
+      sp->restore_obj.object_len = recv_len;
+   }
+
+   sp->restore_obj.object = robjbuf.c_str();
+
+   return bRC_OK;
+}
+
 /*
  * Handle Bacula Plugin I/O API for backend
  *
@@ -1988,14 +2081,14 @@ bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp)
    }
 
    /* The first file in Full backup, is the RestoreObject */
-   if (!estimate && mode == BACKUP_FULL && robjsent == false) {
+   if (!estimate && mode == BACKUP_FULL && pluginconfigsent == false) {
       ConfigFile ini;
       ini.register_items(plugin_items_dump, sizeof(struct ini_items));
       sp->restore_obj.object_name = (char *)INI_RESTORE_OBJECT_NAME;
       sp->restore_obj.object_len = ini.serialize(robjbuf.c_str());
       sp->restore_obj.object = robjbuf.c_str();
       sp->type = FT_PLUGIN_CONFIG;
-      DMSG0(ctx, DINFO, "Prepared RestoreObject sent.\n");
+      DMSG2(ctx, DINFO, "Prepared RestoreObject/%s (%d) sent.\n", INI_RESTORE_OBJECT_NAME, FT_PLUGIN_CONFIG);
       return bRC_OK;
    }
 
@@ -2017,8 +2110,36 @@ bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp)
    DMSG(ctx, DINFO, "fname:%s\n", fname.c_str());
    sp->fname = fname.c_str();
 
-   if (!pluginobject){
-      // here we handle metadata information
+   switch (object)
+   {
+   case RestoreObject:
+      // handle Restore Object parameters and data
+      if (perform_read_restoreobject(ctx, sp) != bRC_OK) {
+         // signal error
+         return bRC_Error;
+      }
+      sp->restore_obj.object_name = fname.c_str();
+      sp->type = FT_RESTORE_FIRST;
+      size = sp->restore_obj.object_len;
+      sp->statp.st_mode = 0700 | S_IFREG;
+      {
+         time_t now = time(NULL);
+         sp->statp.st_ctime = now;
+         sp->statp.st_mtime = now;
+         sp->statp.st_atime = now;
+      }
+      break;
+   case PluginObject:
+      // handle Plugin Object parameters
+      if (perform_read_pluginobject(ctx, sp) != bRC_OK) {
+         // signal error
+         return bRC_Error;
+      }
+      sp->type = FT_PLUGIN_OBJECT;
+      size = sp->plugin_obj.object_size;
+      break;
+   default:
+      // here we handle standard file metadata information
       reqparams--;
 
       // ensure clear state for metadatas
@@ -2131,14 +2252,7 @@ bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp)
          return bRC_Error;
       }
 
-   } else {
-      // handle Plugin Object parameters
-      if (perform_read_pluginobject(ctx, sp) != bRC_OK) {
-         // signal error
-         return bRC_Error;
-      }
-      sp->type = FT_PLUGIN_OBJECT;
-      size = sp->plugin_obj.object_size;
+      break;
    }
 
    if (backend.ctx->is_error()) {
@@ -2182,16 +2296,16 @@ bRC METAPLUGIN::endBackupFile(bpContext *ctx)
 
    if (!estimate){
       /* The current file was the restore object, so just ask for the next file */
-      if (mode == BACKUP_FULL && robjsent == false) {
-         robjsent = true;
+      if (mode == BACKUP_FULL && pluginconfigsent == false) {
+         pluginconfigsent = true;
          return bRC_More;
       }
    }
 
    // check for next file only when no previous error
    if (!openerror) {
-      if (estimate || pluginobjectsent) {
-         pluginobjectsent = false;
+      if (estimate || objectsent) {
+         objectsent = false;
          if (perform_read_metadata(ctx) != bRC_OK) {
             /* signal error */
             return bRC_Error;
@@ -2212,6 +2326,38 @@ bRC METAPLUGIN::endBackupFile(bpContext *ctx)
  */
 bRC METAPLUGIN::startRestoreFile(bpContext *ctx, const char *cmd)
 {
+   if (restoreobject_list.size() > 0) {
+      restore_object_class *ropclass;
+      POOL_MEM backcmd(PM_FNAME);
+
+      foreach_alist(ropclass, &restoreobject_list) {
+         if (!ropclass->sent && strcmp(cmd, ropclass->plugin_name.c_str()) == 0) {
+
+            Mmsg(backcmd, "RESTOREOBJ:%s\n", ropclass->object_name.c_str());
+            DMSG1(ctx, DINFO, "%s", backcmd.c_str());
+            ropclass->sent = true;
+
+            if (backend.ctx->write_command(ctx, backcmd.c_str()) < 0)
+            {
+               DMSG0(ctx, DERROR, "Error sending RESTOREOBJ command\n");
+               return bRC_Error;
+            }
+
+            Mmsg(backcmd, "RESTOREOBJ_LEN:%d\n", ropclass->length);
+            if (backend.ctx->write_command(ctx, backcmd.c_str()) < 0) {
+               DMSG0(ctx, DERROR, "Error sending RESTOREOBJ_LEN command\n");
+               return bRC_Error;
+            }
+
+            /* send data */
+            if (backend.ctx->send_data(ctx, ropclass->data.c_str(), ropclass->length) != bRC_OK) {
+               DMSG0(ctx, DERROR, "Error sending RestoreObject data\n");
+               return bRC_Error;
+            }
+         }
+      }
+   }
+
    return bRC_OK;
 }
 
index b74658d43e57525f0a2cf95e7268bfd8319e6714..6aee4b1f8690312eeb03e857397f03db520805d0 100644 (file)
 
 #include "pluginlib.h"
 #include "ptcomm.h"
-#include "smartmutex.h"
 #include "lib/ini.h"
-#include "pluginlib/commctx.h"
-#include "pluginlib/smartalist.h"
+#include "commctx.h"
+#include "smartalist.h"
 
 
 #define USE_CMD_PARSER
@@ -83,6 +82,16 @@ extern const char *valid_params[];
 // custom checkFile() callback
 extern checkFile_t checkFile;
 
+// a simple ro buf class
+struct restore_object_class
+{
+   POOL_MEM plugin_name;
+   POOL_MEM object_name;
+   POOL_MEM data;
+   int32_t length;
+   bool sent;
+};
+
 /*
  * This is a main plugin API class. It manages a plugin context.
  *  All the public methods correspond to a public Bacula API calls, even if
@@ -137,14 +146,17 @@ public:
                   where(NULL),
                   regexwhere(NULL),
                   replace(0),
-                  robjsent(false),
+                  pluginconfigsent(false),
                   estimate(false),
                   listing(None),
                   nodata(false),
                   nextfile(false),
                   openerror(false),
-                  pluginobject(false),
-                  pluginobjectsent(false),
+                  object(FileObject),
+                  objectsent(false),
+                  // pluginobject(false),
+                  // pluginobjectsent(false),
+                  // restoreobject(false),
                   readacl(false),
                   readxattr(false),
                   skipextract(false),
@@ -162,8 +174,9 @@ public:
                   acldata(PM_MESSAGE),
                   xattrdatalen(0),
                   xattrdata(PM_MESSAGE),
-                  metadatas_list(10, true),
-                  prevjobname(NULL)
+                  metadatas_list(10, owned_by_alist),
+                  prevjobname(NULL),
+                  restoreobject_list()
    {}
 #if __cplusplus > 201103L
    METAPLUGIN(METAPLUGIN&) = delete;
@@ -172,6 +185,12 @@ public:
    ~METAPLUGIN() {}
 
 private:
+   enum OBJECT
+   {
+      FileObject,
+      PluginObject,
+      RestoreObject,
+   };
    enum LISTING
    {
       None,
@@ -190,14 +209,17 @@ private:
    char *where;                  // the Where variable for restore job if set by user
    char *regexwhere;             // the RegexWhere variable for restore job if set by user
    char replace;                 // the replace variable for restore job
-   bool robjsent;                // set when RestoreObject was sent during Full backup
+   bool pluginconfigsent;        // set when RestoreObject/INI_RESTORE_OBJECT_NAME_FT_PLUGIN_CONFIG was sent during Full backup
    bool estimate;                // used when mode is METAPLUGIN_BACKUP_* but we are doing estimate only
    LISTING listing;              // used for a Listing procedure for estimate
    bool nodata;                  // set when backend signaled no data for backup or no data for restore
    bool nextfile;                // set when IO_CLOSE got FNAME: command
    bool openerror;               // show if "openfile" was unsuccessful
-   bool pluginobject;            // set when IO_CLOSE got FNAME: command
-   bool pluginobjectsent;        // set when startBackupFile handled plugin object and endBackupFile has to check for nextfile
+   OBJECT object;                //
+   bool objectsent;              // set when startBackupFile handled object and endBackupFile has to check for nextfile
+   // bool pluginobject;            // set when got PLUGINOBJ: command
+   // bool pluginobjectsent;        // set when startBackupFile handled plugin object and endBackupFile has to check for nextfile
+   // bool restoreobject;           // set when got RESTOREOBJ: command
    bool readacl;                 // got ACL data from backend
    bool readxattr;               // got XATTR data from backend
    bool skipextract;             // got SKIP response from backend, so we should artificially skip it for backend
@@ -218,12 +240,14 @@ private:
    POOL_MEM xattrdata;           // the buffer for XATTR data received from backend
    cmd_parser parser;            // Plugin command parser
    ConfigFile ini;               // Restore ini file handler
-   alist metadatas_list;         //
-   plugin_metadata metadatas;    //
+   alist metadatas_list;         // a list if managed metadatas
+   plugin_metadata metadatas;    // the private metadata class
    const char *prevjobname;      // this is a bVarPrevJobName parameter if requested
+   // a list of received RO from bacula which we will use to feed into backend later
+   smart_alist<restore_object_class> restoreobject_list;
 
    bRC parse_plugin_command(bpContext *ctx, const char *command, alist *params);
-   bRC parse_plugin_restoreobj(bpContext *ctx, restore_object_pkt *rop);
+   bRC handle_plugin_restoreobj(bpContext *ctx, restore_object_pkt *rop);
    bRC run_backend(bpContext *ctx);
    bRC send_parameters(bpContext *ctx, char *command);
    bRC send_jobinfo(bpContext *ctx, char type);
@@ -243,6 +267,7 @@ private:
    bRC perform_read_metadata(bpContext *ctx);
    bRC perform_read_fstatdata(bpContext *ctx, struct save_pkt *sp);
    bRC perform_read_pluginobject(bpContext *ctx, struct save_pkt *sp);
+   bRC perform_read_restoreobject(bpContext *ctx, struct save_pkt *sp);
    bRC perform_read_acl(bpContext *ctx);
    bRC perform_write_acl(bpContext *ctx, const xacl_pkt * xacl);
    bRC perform_read_xattr(bpContext *ctx);
index 2d83d183e842cb7a5b5eefcaf5b8bbb221a1059f..4699df97985827e2638745132750fdf8ca6ae35b 100644 (file)
@@ -583,7 +583,7 @@ int32_t PTCOMM::recvbackend_fixed(bpContext *ctx, char cmd, char *buf, int32_t b
  *    -1 - when encountered any error
  *    <n> - the number of bytes sent, success
  */
-int32_t PTCOMM::sendbackend(bpContext *ctx, char cmd, POOLMEM *buf, int32_t len)
+int32_t PTCOMM::sendbackend(bpContext *ctx, char cmd, const char *buf, int32_t len)
 {
    int status;
    PTHEADER *header;
@@ -595,7 +595,7 @@ int32_t PTCOMM::sendbackend(bpContext *ctx, char cmd, POOLMEM *buf, int32_t len)
       return -1;
    }
 
-   if (len > 999999){
+   if (len > PTCOMM_MAX_PACKET_SIZE){
       /* message length too long, cannot send it */
       DMSG(ctx, DERROR, "Message length %i too long, cannot send data.\n", len);
       JMSG(ctx, M_FATAL, "Message length %i too long, cannot send data.\n", len);
@@ -806,7 +806,7 @@ bool PTCOMM::read_ack(bpContext *ctx)
  *    -1 - when encountered any error
  *    <n> - the number of bytes sent, success
  */
-int32_t PTCOMM::write_command(bpContext *ctx, POOLMEM *buf)
+int32_t PTCOMM::write_command(bpContext *ctx, const char *buf)
 {
    int32_t len;
    len = buf ? strlen(buf) : 0;
@@ -825,7 +825,7 @@ int32_t PTCOMM::write_command(bpContext *ctx, POOLMEM *buf)
  *    -1 - when encountered any error
  *    <n> - the number of bytes sent, success
  */
-int32_t PTCOMM::write_data(bpContext *ctx, POOLMEM *buf, int32_t len)
+int32_t PTCOMM::write_data(bpContext *ctx, const char *buf, int32_t len)
 {
    int32_t status;
 
@@ -903,3 +903,73 @@ bool PTCOMM::handshake(bpContext *ctx, const char *pluginname, const char * plug
 
    return false;
 }
+
+/**
+ * @brief Sends a single stream of data to backend read from a buf.
+ *
+ * @param ctx bpContext - for Bacula debug and jobinfo messages
+ * @param buf a buffer to read a data to send
+ * @param len a lengtho of the data to send
+ * @return bRC bRC_OK when successful, bRC_Error otherwise
+ */
+bRC PTCOMM::send_data(bpContext *ctx, const char *buf, int32_t len)
+{
+   /* send data */
+   int32_t offset = 0;
+
+   while (offset < len)
+   {
+      int32_t count = MIN(len - offset, PTCOMM_MAX_PACKET_SIZE);
+      int32_t status = write_data(ctx, buf + offset, count);
+      if (status < 0) {
+         /* got some error */
+         return bRC_Error;
+      }
+      offset += status;
+   }
+
+   /* signal end of data to restore and get ack */
+   if (!send_ack(ctx)) {
+      return bRC_Error;
+   }
+
+   return bRC_OK;
+}
+
+/**
+ * @brief Receives a single stream of data from backend and saves it at buf.
+ *    For a good performance it is expected that `buf` will be preallocated
+ *    for the expected size of the stream.
+ *
+ * @param ctx bpContext - for Bacula debug and jobinfo messages
+ * @param buf a buffer to save received data
+ * @param recv_len a number of bytes saved at buf
+ * @return bRC bRC_OK when successful, bRC_Error otherwise
+ */
+bRC PTCOMM::recv_data(bpContext *ctx, POOL_MEM &buf, int32_t *recv_len)
+{
+   POOL_MEM cmd(PM_MESSAGE);
+   int32_t offset = 0;
+
+   // loop on data from backend and EOD
+   while (!is_eod())
+   {
+      int32_t status = read_data(ctx, cmd);
+      if (status > 0) {
+         buf.check_size(offset + status);   // it should be preallocated
+         memcpy(buf.c_str() + offset, cmd.c_str(), status);
+         offset += status;
+      } else {
+         if (is_fatal()){
+            /* raise up error from backend */
+            return bRC_Error;
+         }
+      }
+   }
+
+   if (recv_len != NULL) {
+      *recv_len = offset;
+   }
+
+   return bRC_OK;
+}
index 0176c0347fabe0229722c0facec4346c5d1c30a3..3e3fcc4123105edf8ef42e1373aee266dc38d8e3 100644 (file)
@@ -34,6 +34,8 @@
 #define PTCOMM_DEFAULT_TIMEOUT   3600        // timeout waiting for data is 1H as some backends could spent it doing real work
                                              // TODO: I think we should move it to plugin configurable variable instead of a const
 
+#define PTCOMM_MAX_PACKET_SIZE   999999
+
 /*
  * The protocol packet header.
  *  Every packet exchanged between Plugin and Backend will have a special header
@@ -96,7 +98,7 @@ protected:
    int32_t recvbackend(bpContext *ctx, char *cmd, POOL_MEM &buf, bool any=false);
    int32_t recvbackend_fixed(bpContext *ctx, char cmd, char *buf, int32_t bufsize);
 
-   int32_t sendbackend(bpContext *ctx, char cmd, POOLMEM *buf, int32_t len);
+   int32_t sendbackend(bpContext *ctx, char cmd, const char *buf, int32_t len);
 
 public:
    PTCOMM(const char * command = NULL) :
@@ -128,7 +130,10 @@ public:
    int32_t read_data(bpContext *ctx, POOL_MEM &buf);
    int32_t read_data_fixed(bpContext *ctx, char *buf, int32_t len);
 
-   int32_t write_command(bpContext *ctx, char *buf);
+   int32_t write_command(bpContext *ctx, const char *buf);
+
+   bRC send_data(bpContext *ctx, const char *buf, int32_t len);
+   bRC recv_data(bpContext *ctx, POOL_MEM &buf, int32_t *recv_len=NULL);
 
    /**
     * @brief Sends a command to the backend.
@@ -140,7 +145,7 @@ public:
     *    <n> - the number of bytes sent, success
     */
    int32_t write_command(bpContext *ctx, POOL_MEM &buf) { return write_command(ctx, buf.addr()); }
-   int32_t write_data(bpContext *ctx, char *buf, int32_t len);
+   int32_t write_data(bpContext *ctx, const char *buf, int32_t len);
 
    bool read_ack(bpContext *ctx);
    bool send_ack(bpContext *ctx);
index d6e1a3bf77aa378cca002019bca10ee537b6b927..d9aaef2d822f356ff29032749079f2f9959e2761 100644 (file)
@@ -211,14 +211,14 @@ void write_plugin(const char cmd, const char *str)
  * @param cmd the packet type to sent
  * @param str the text to write
  */
-void write_plugin_bin(const char *str, int len = 0)
+void write_plugin_bin(const unsigned char *str, int len = 0)
 {
-   const char * out;
+   const unsigned char * out;
 
    if (str) {
       out = str;
    } else {
-      out = "";
+      out = (const unsigned char*)"";
    }
 
    printf("D%06d\n", len);
@@ -261,6 +261,342 @@ static void catch_function(int signo)
    jobcancelled = true;
 }
 
+unsigned char restore_object_data[] = {
+  0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20,
+  0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e, 0x64, 0x3a, 0x20, 0x4e, 0x61, 0x6d,
+  0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x0a, 0x6d, 0x65, 0x74, 0x61, 0x64,
+  0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a,
+  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a,
+  0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69,
+  0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e, 0x64, 0x3a,
+  0x20, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x0a, 0x6d, 0x65, 0x74, 0x61,
+  0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65,
+  0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74,
+  0x2d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x0a, 0x20, 0x20, 0x6e,
+  0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c,
+  0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x6c,
+  0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61,
+  0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65,
+  0x73, 0x74, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x23,
+  0x20, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x62,
+  0x61, 0x63, 0x75, 0x6c, 0x61, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x70, 0x61,
+  0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
+  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x73,
+  0x65, 0x63, 0x72, 0x65, 0x74, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x35, 0x62,
+  0x41, 0x6f, 0x56, 0x32, 0x43, 0x70, 0x7a, 0x42, 0x76, 0x68, 0x42, 0x51,
+  0x5a, 0x61, 0x59, 0x55, 0x58, 0x31, 0x71, 0x59, 0x61, 0x77, 0x43, 0x30,
+  0x30, 0x71, 0x68, 0x72, 0x78, 0x38, 0x63, 0x45, 0x57, 0x30, 0x66, 0x4b,
+  0x31, 0x7a, 0x59, 0x6b, 0x54, 0x78, 0x56, 0x64, 0x62, 0x78, 0x66, 0x76,
+  0x57, 0x4d, 0x79, 0x69, 0x30, 0x68, 0x35, 0x51, 0x62, 0x77, 0x65, 0x4a,
+  0x6b, 0x71, 0x0a, 0x20, 0x20, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d,
+  0x65, 0x3a, 0x20, 0x59, 0x6d, 0x46, 0x6a, 0x64, 0x57, 0x78, 0x68, 0x43,
+  0x67, 0x3d, 0x3d, 0x0a, 0x20, 0x20, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
+  0x72, 0x64, 0x3a, 0x20, 0x63, 0x47, 0x78, 0x31, 0x5a, 0x32, 0x6c, 0x75,
+  0x64, 0x47, 0x56, 0x7a, 0x64, 0x41, 0x6f, 0x3d, 0x0a, 0x20, 0x20, 0x73,
+  0x65, 0x63, 0x72, 0x65, 0x74, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x4e, 0x57,
+  0x4a, 0x42, 0x62, 0x31, 0x59, 0x79, 0x51, 0x33, 0x42, 0x36, 0x51, 0x6e,
+  0x5a, 0x6f, 0x51, 0x6c, 0x46, 0x61, 0x59, 0x56, 0x6c, 0x56, 0x57, 0x44,
+  0x46, 0x78, 0x57, 0x57, 0x46, 0x33, 0x51, 0x7a, 0x41, 0x77, 0x63, 0x57,
+  0x68, 0x79, 0x65, 0x44, 0x68, 0x6a, 0x52, 0x56, 0x63, 0x77, 0x5a, 0x6b,
+  0x73, 0x78, 0x65, 0x6c, 0x6c, 0x72, 0x56, 0x48, 0x68, 0x57, 0x5a, 0x47,
+  0x4a, 0x34, 0x5a, 0x6e, 0x5a, 0x58, 0x54, 0x58, 0x6c, 0x70, 0x4d, 0x47,
+  0x67, 0x31, 0x55, 0x57, 0x4a, 0x33, 0x5a, 0x55, 0x70, 0x72, 0x63, 0x51,
+  0x6f, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65,
+  0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69,
+  0x6e, 0x64, 0x3a, 0x20, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61,
+  0x70, 0x0a, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a,
+  0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
+  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69,
+  0x67, 0x6d, 0x61, 0x70, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73,
+  0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+  0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c,
+  0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20,
+  0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x64,
+  0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x64, 0x61, 0x74, 0x61, 0x62,
+  0x61, 0x73, 0x65, 0x3a, 0x20, 0x62, 0x61, 0x63, 0x75, 0x6c, 0x61, 0x0a,
+  0x20, 0x20, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x68,
+  0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30,
+  0x2e, 0x31, 0x0a, 0x20, 0x20, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+  0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x27, 0x35, 0x34, 0x33,
+  0x32, 0x27, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65,
+  0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69,
+  0x6e, 0x64, 0x3a, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x0a,
+  0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20,
+  0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+  0x74, 0x65, 0x73, 0x74, 0x2d, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61,
+  0x69, 0x6e, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
+  0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65,
+  0x73, 0x74, 0x0a, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c,
+  0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x73, 0x70, 0x65,
+  0x63, 0x3a, 0x0a, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f,
+  0x72, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a,
+  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a,
+  0x20, 0x20, 0x23, 0x20, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49,
+  0x50, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x20, 0x20, 0x70, 0x6f,
+  0x72, 0x74, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6e, 0x61, 0x6d,
+  0x65, 0x3a, 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x23, 0x20, 0x41, 0x63, 0x74,
+  0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2c, 0x20, 0x6e, 0x6f, 0x20, 0x70, 0x6f,
+  0x72, 0x74, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x65, 0x64,
+  0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x3a, 0x20,
+  0x31, 0x32, 0x33, 0x34, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x61, 0x72,
+  0x67, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x33,
+  0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72,
+  0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e,
+  0x64, 0x3a, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x0a, 0x6d,
+  0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x6e,
+  0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74,
+  0x65, 0x73, 0x74, 0x2d, 0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x73, 0x65,
+  0x72, 0x76, 0x69, 0x63, 0x65, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65,
+  0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69,
+  0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65,
+  0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a,
+  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d,
+  0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
+  0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x65, 0x72, 0x3a, 0x20,
+  0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x0a, 0x73, 0x70, 0x65, 0x63,
+  0x3a, 0x0a, 0x20, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x3a, 0x0a, 0x20,
+  0x20, 0x2d, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x38, 0x30, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x77, 0x65,
+  0x62, 0x0a, 0x20, 0x20, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49,
+  0x50, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x20, 0x20, 0x73, 0x65,
+  0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74,
+  0x65, 0x73, 0x74, 0x2d, 0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x77, 0x65,
+  0x62, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72,
+  0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e,
+  0x64, 0x3a, 0x20, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e,
+  0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x43, 0x6c, 0x61, 0x69, 0x6d,
+  0x0a, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20,
+  0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69,
+  0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73,
+  0x74, 0x65, 0x6e, 0x74, 0x2d, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x2d,
+  0x63, 0x6c, 0x61, 0x69, 0x6d, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65,
+  0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69,
+  0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65,
+  0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a,
+  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a,
+  0x73, 0x70, 0x65, 0x63, 0x3a, 0x0a, 0x20, 0x20, 0x61, 0x63, 0x63, 0x65,
+  0x73, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x2d, 0x20, 0x52, 0x65, 0x61, 0x64, 0x57, 0x72, 0x69, 0x74, 0x65,
+  0x4f, 0x6e, 0x63, 0x65, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x73, 0x6f, 0x75,
+  0x72, 0x63, 0x65, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
+  0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x31,
+  0x47, 0x69, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65,
+  0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69,
+  0x6e, 0x64, 0x3a, 0x20, 0x50, 0x6f, 0x64, 0x0a, 0x6d, 0x65, 0x74, 0x61,
+  0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65,
+  0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74,
+  0x31, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63,
+  0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73,
+  0x74, 0x0a, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75,
+  0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x3a,
+  0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x23, 0x20, 0x74, 0x69, 0x65, 0x72, 0x3a, 0x20,
+  0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x0a, 0x73, 0x70, 0x65,
+  0x63, 0x3a, 0x0a, 0x20, 0x20, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d,
+  0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73,
+  0x74, 0x2d, 0x31, 0x0a, 0x20, 0x20, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d,
+  0x61, 0x69, 0x6e, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74,
+  0x65, 0x73, 0x74, 0x2d, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69,
+  0x6e, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+  0x72, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x69, 0x6d, 0x61, 0x67,
+  0x65, 0x3a, 0x20, 0x62, 0x75, 0x73, 0x79, 0x62, 0x6f, 0x78, 0x3a, 0x31,
+  0x2e, 0x32, 0x38, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6d, 0x6d,
+  0x61, 0x6e, 0x64, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d,
+  0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x2d, 0x20, 0x22, 0x33, 0x36, 0x30, 0x30, 0x22, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
+  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76,
+  0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x3a,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6e, 0x61, 0x6d,
+  0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73,
+  0x74, 0x2d, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74,
+  0x2d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61,
+  0x74, 0x68, 0x3a, 0x20, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x20,
+  0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x2d, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75,
+  0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x70, 0x65, 0x72, 0x73,
+  0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x74, 0x6f, 0x72, 0x61,
+  0x67, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x65, 0x72,
+  0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d,
+  0x65, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x4e, 0x61, 0x6d,
+  0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73,
+  0x74, 0x2d, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74,
+  0x2d, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x2d, 0x63, 0x6c, 0x61, 0x69,
+  0x6d, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72,
+  0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e,
+  0x64, 0x3a, 0x20, 0x50, 0x6f, 0x64, 0x0a, 0x6d, 0x65, 0x74, 0x61, 0x64,
+  0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a,
+  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x32,
+  0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65,
+  0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74,
+  0x0a, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
+  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x73, 0x70, 0x65, 0x63, 0x3a,
+  0x0a, 0x20, 0x20, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x3a,
+  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d,
+  0x32, 0x0a, 0x20, 0x20, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69,
+  0x6e, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73,
+  0x74, 0x2d, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0a,
+  0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73,
+  0x3a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x3a,
+  0x20, 0x62, 0x75, 0x73, 0x79, 0x62, 0x6f, 0x78, 0x3a, 0x31, 0x2e, 0x32,
+  0x38, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
+  0x64, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x73,
+  0x6c, 0x65, 0x65, 0x70, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d,
+  0x20, 0x22, 0x33, 0x36, 0x30, 0x30, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+  0x74, 0x65, 0x73, 0x74, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69,
+  0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x61, 0x70, 0x70,
+  0x73, 0x2f, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e, 0x64, 0x3a, 0x20, 0x52,
+  0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x53, 0x65, 0x74, 0x0a, 0x6d, 0x65,
+  0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x6e, 0x61,
+  0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65,
+  0x73, 0x74, 0x2d, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x0a,
+  0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a,
+  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a,
+  0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69,
+  0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63,
+  0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x65, 0x72, 0x3a, 0x20,
+  0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x0a, 0x73, 0x70, 0x65,
+  0x63, 0x3a, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61,
+  0x73, 0x3a, 0x20, 0x31, 0x0a, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63,
+  0x74, 0x6f, 0x72, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x74,
+  0x63, 0x68, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x65, 0x72, 0x3a, 0x20, 0x66, 0x72,
+  0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x74, 0x65, 0x6d,
+  0x70, 0x6c, 0x61, 0x74, 0x65, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d,
+  0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x65, 0x72, 0x3a,
+  0x20, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73,
+  0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6e, 0x61,
+  0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65,
+  0x73, 0x74, 0x2d, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x2d,
+  0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x67, 0x63, 0x72, 0x2e,
+  0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5f, 0x73, 0x61,
+  0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x67, 0x62, 0x2d, 0x66, 0x72, 0x6f,
+  0x6e, 0x74, 0x65, 0x6e, 0x64, 0x3a, 0x76, 0x33, 0x0a, 0x2d, 0x2d, 0x2d,
+  0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a,
+  0x20, 0x61, 0x70, 0x70, 0x73, 0x2f, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e,
+  0x64, 0x3a, 0x20, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e,
+  0x74, 0x0a, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a,
+  0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
+  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x6e, 0x67, 0x69, 0x6e, 0x78,
+  0x2d, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x0a,
+  0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a,
+  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a,
+  0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69,
+  0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79,
+  0x6d, 0x65, 0x6e, 0x74, 0x0a, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x0a, 0x20,
+  0x20, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x3a, 0x20, 0x32,
+  0x0a, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x3a,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x61,
+  0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74,
+  0x65, 0x73, 0x74, 0x2d, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65,
+  0x6e, 0x74, 0x0a, 0x20, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74,
+  0x65, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64,
+  0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c,
+  0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
+  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x64, 0x65, 0x70, 0x6c, 0x6f,
+  0x79, 0x6d, 0x65, 0x6e, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70,
+  0x65, 0x63, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f,
+  0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x3a, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20,
+  0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x6e,
+  0x67, 0x69, 0x6e, 0x78, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x6e, 0x67, 0x69, 0x6e,
+  0x78, 0x3a, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x3a, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x63, 0x6f,
+  0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x3a,
+  0x20, 0x38, 0x30, 0x38, 0x30, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70,
+  0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x61, 0x70,
+  0x70, 0x73, 0x2f, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e, 0x64, 0x3a, 0x20,
+  0x53, 0x74, 0x61, 0x74, 0x65, 0x66, 0x75, 0x6c, 0x53, 0x65, 0x74, 0x0a,
+  0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20,
+  0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+  0x74, 0x65, 0x73, 0x74, 0x2d, 0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x77,
+  0x65, 0x62, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
+  0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65,
+  0x73, 0x74, 0x0a, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x0a, 0x20, 0x20, 0x73,
+  0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x3a, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73,
+  0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a,
+  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d,
+  0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x77, 0x65, 0x62, 0x0a, 0x20, 0x20,
+  0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x3a,
+  0x20, 0x22, 0x6e, 0x67, 0x69, 0x6e, 0x78, 0x22, 0x0a, 0x20, 0x20, 0x72,
+  0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x3a, 0x20, 0x33, 0x0a, 0x20,
+  0x20, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x3a, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73,
+  0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
+  0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c,
+  0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
+  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x6e, 0x67, 0x69, 0x6e, 0x78,
+  0x2d, 0x77, 0x65, 0x62, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x74, 0x69, 0x65, 0x72, 0x3a, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x65,
+  0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70, 0x65, 0x63, 0x3a,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x72, 0x6d, 0x69,
+  0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x72, 0x61, 0x63, 0x65, 0x50,
+  0x65, 0x72, 0x69, 0x6f, 0x64, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73,
+  0x3a, 0x20, 0x31, 0x30, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63,
+  0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x3a, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a,
+  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d,
+  0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x77, 0x65, 0x62, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x3a,
+  0x20, 0x6b, 0x38, 0x73, 0x2e, 0x67, 0x63, 0x72, 0x2e, 0x69, 0x6f, 0x2f,
+  0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x73, 0x6c, 0x69, 0x6d, 0x3a, 0x30,
+  0x2e, 0x38, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70,
+  0x6f, 0x72, 0x74, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+  0x72, 0x50, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x38, 0x30, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65,
+  0x3a, 0x20, 0x77, 0x65, 0x62, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x4d, 0x6f, 0x75, 0x6e,
+  0x74, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x2d, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
+  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x77, 0x77, 0x77, 0x2d, 0x64,
+  0x61, 0x74, 0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x3a,
+  0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2f,
+  0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x0a, 0x20,
+  0x20, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x43, 0x6c, 0x61, 0x69, 0x6d,
+  0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x3a, 0x0a, 0x20,
+  0x20, 0x2d, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a,
+  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d,
+  0x77, 0x77, 0x77, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65,
+  0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d,
+  0x6f, 0x64, 0x65, 0x73, 0x3a, 0x20, 0x5b, 0x20, 0x22, 0x52, 0x65, 0x61,
+  0x64, 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x6e, 0x63, 0x65, 0x22, 0x20,
+  0x5d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x6f,
+  0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x3a,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73,
+  0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x31, 0x47, 0x69, 0x0a,
+};
+unsigned int restore_object_data_len = 3984;
+
 /**
  * @brief Perform test backup.
  */
@@ -388,6 +724,22 @@ void perform_backup()
 
    if (regress_backup_other_file)
    {
+      // restore object
+      snprintf(buf, BIGBUFLEN, "RESTOREOBJ:TestRObject%d\n", mypid);
+      write_plugin('C', buf);
+      snprintf(buf, BIGBUFLEN, "RESTOREOBJ_LEN:%u\n", restore_object_data_len);
+      write_plugin('C', buf);
+      write_plugin_bin(restore_object_data, restore_object_data_len);
+      signal_eod();
+
+      snprintf(buf, BIGBUFLEN, "RESTOREOBJ:OtherObject%d\n", mypid);
+      write_plugin('C', buf);
+      const char *r_data = "/* here comes a file data contents */";
+      snprintf(buf, BIGBUFLEN, "RESTOREOBJ_LEN:%u\n", strlen(r_data) + 1);
+      write_plugin('C', buf);
+      write_plugin('D', r_data);
+      signal_eod();
+
       // next file
       snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/vm222-other-file.iso\n", PLUGINPREFIX, mypid);
       write_plugin('C', buf);
@@ -520,7 +872,7 @@ void perform_backup()
    write_plugin('I', "TEST17 - big file block");
    write_plugin('C', "DATA\n");
    {
-      char *bigfileblock_ptr = (char*)malloc(bigfileblock);
+      unsigned char *bigfileblock_ptr = (unsigned char*)malloc(bigfileblock);
       memset(bigfileblock_ptr, 0xA1, bigfileblock);
       for (int s = bigfilesize; s > 0; s -= bigfileblock) {
          write_plugin_bin(bigfileblock_ptr, bigfileblock);
@@ -901,7 +1253,7 @@ void perform_queryparam(const char *query)
       write_plugin('C', buf);
    } else
    if (strcmp(query, "m_json") == 0) {
-      write_plugin_bin((const char*)m_json, m_json_len);
+      write_plugin_bin(m_json, m_json_len);
       write_plugin('D', "UmFkb3PFgmF3IEtvcnplbmlld3NraQo=\n");
    }
 
@@ -981,7 +1333,7 @@ void perform_restore()
       }
 
       /* check for METADATA stream */
-      if (strncmp(buf, "METADATA_STREAM", 15) == 0){
+      if (strncmp(buf, "METADATA_STREAM", 15) == 0) {
          // handle metadata
          read_plugin_data_stream();
          /* signal OK */
@@ -998,6 +1350,20 @@ void perform_restore()
          continue;
       }
 
+      /* Restore Object stream */
+      if (strncmp(buf, "RESTOREOBJ", 10) == 0) {
+         read_plugin(buf);    // RESTOREOBJ_LEN
+
+         // handle object data
+         read_plugin_data_stream();
+         /* signal OK */
+         LOG("#> RESTOREOBJ data saved.");
+
+         write_plugin('I', "TEST6R - RO saved.");
+         write_plugin('C', "OK\n");
+         continue;
+      }
+
       /* check if DATA command, so read the data packets */
       if (strcmp(buf, "DATA\n") == 0){
          int len = read_plugin(buf);