]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
metaplugin: Add accurate mode query.
authorRadosław Korzeniewski <radoslaw@korzeniewski.net>
Wed, 25 Aug 2021 14:52:53 +0000 (16:52 +0200)
committerEric Bollengier <eric@baculasystems.com>
Thu, 24 Mar 2022 08:03:03 +0000 (09:03 +0100)
This patch implements a basic accurate mode query to the metaplugin
protocol. In this extension the backend can issue `CHECK:$fname`
command followed by a standard `STAT:...` and `TSTAMP:...` commands
to ask Bacula if it should backup $fname in this job.
The metaplugin will response with simple "OK", you should backup this
file or "SEEN" it before, backup is not required. This feature will work
with Accurate jobs only. If job is not accurate then user will get
an error job message.

bacula/src/plugins/fd/Makefile.inc.in
bacula/src/plugins/fd/pluginlib/Makefile
bacula/src/plugins/fd/pluginlib/metaplugin.cpp
bacula/src/plugins/fd/pluginlib/metaplugin.h
bacula/src/plugins/fd/pluginlib/pluginlib.h
bacula/src/plugins/fd/pluginlib/ptcomm.cpp
bacula/src/plugins/fd/pluginlib/ptcomm.h

index de286475a73875aa7e1f3fde4d356eddb9d8e883..545c2be52194fd21f5058d9c5177fc7d58a18dc8 100644 (file)
@@ -38,7 +38,7 @@ PLUGINLIBDIR = $(FDPLUGDIR)/pluginlib
 UNITTESTSOBJ = $(LIBDIR)/unittests.lo
 LIBBACOBJ = $(LIBDIR)/libbac.la
 PLUGINLIBOBJ = $(PLUGINLIBDIR)/pluginlib.lo
-METAPLUGINOBJ = $(PLUGINLIBOBJ) $(PLUGINLIBDIR)/ptcomm.lo $(PLUGINLIBDIR)/metaplugin.lo $(PLUGINLIBDIR)/metaplugin_stat.lo
+METAPLUGINOBJ = $(PLUGINLIBOBJ) $(PLUGINLIBDIR)/ptcomm.lo $(PLUGINLIBDIR)/metaplugin.lo $(PLUGINLIBDIR)/metaplugin_attributes.lo
 
 .SUFFIXES:    .c .cpp   .lo
 
@@ -60,8 +60,8 @@ $(PLUGINLIBDIR)/ptcomm.lo: $(PLUGINLIBDIR)/ptcomm.cpp $(PLUGINLIBDIR)/ptcomm.h
 $(PLUGINLIBDIR)/metaplugin.lo: $(PLUGINLIBDIR)/metaplugin.cpp $(PLUGINLIBDIR)/metaplugin.h
        $(MAKE) -C $(PLUGINLIBDIR) metaplugin.lo
 
-$(PLUGINLIBDIR)/metaplugin_stat.lo: $(PLUGINLIBDIR)/metaplugin_stat.cpp $(PLUGINLIBDIR)/metaplugin_stat.h
-       $(MAKE) -C $(PLUGINLIBDIR) metaplugin_stat.lo
+$(PLUGINLIBDIR)/metaplugin_attributes.lo: $(PLUGINLIBDIR)/metaplugin_attributes.cpp $(PLUGINLIBDIR)/metaplugin_attributes.h
+       $(MAKE) -C $(PLUGINLIBDIR) metaplugin_attributes.lo
 
 $(PLUGINLIBDIR)/iso8601.lo: $(PLUGINLIBDIR)/iso8601.cpp $(PLUGINLIBDIR)/iso8601.h
        $(MAKE) -C $(PLUGINLIBDIR) iso8601.lo
index 89b6238d756b97cc10b383a534f3970532f454df..a6a13ddb523378283b15672d3a7fb83a99e1ef36 100644 (file)
@@ -27,7 +27,9 @@ PTCOMMOBJ = $(filter %.lo,$(PTCOMMSRC:.cpp=.lo))
 COMMCTXSRC = commctx.h
 SMARTALISTSRC = smartalist.h
 SMARTPTRSRC = smartptr.h
-METAPLUGINSRC = metaplugin.cpp metaplugin.h
+SMARTMUTEXSRC = smartmutex.h
+SMARTLOCKSRC = smartlock.h
+METAPLUGINSRC = metaplugin.cpp metaplugin.h metaplugin_attributes.cpp metaplugin_attributes.h $(SMARTMUTEXSRC) $(SMARTLOCKSRC) $(COMMCTXSRC)
 METAPLUGINOBJ = $(filter %.lo,$(METAPLUGINSRC:.cpp=.lo))
 
 PLUGINLIBSTEST = pluginlib_test.cpp $(PLUGINLIBSSRC) $(UNITTESTSOBJ)
index cce6282f3dad9573279901a010ac810b0be6283b..28f265178c741f818f8b68def721e55ee9bd0999 100644 (file)
@@ -27,6 +27,7 @@
  */
 
 #include "metaplugin.h"
+#include "metaplugin_attributes.h"
 #include <sys/stat.h>
 #include <signal.h>
 #include <sys/select.h>
@@ -1261,6 +1262,7 @@ bRC METAPLUGIN::handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
    /* Plugin command e.g. plugin = <plugin-name>:parameters */
    case bEventPluginCommand:
       DMSG(ctx, D2, "bEventPluginCommand value=%s\n", NPRT((char *)value));
+      getBaculaVar(bVarAccurate, (void *)&accurate_mode);
       if (isourplugincommand(PLUGINPREFIX, (char*)value) && !backend_available)
       {
          DMSG2(ctx, DERROR, "Unable to use backend: %s Err=%s\n", backend_cmd.c_str(), backend_error.c_str());
@@ -1726,6 +1728,11 @@ bRC METAPLUGIN::perform_read_metacommands(bpContext *ctx)
             // restoreobject = true;
             return bRC_OK;
          }
+         if (scan_parameter_str(cmd, "CHECK:", fname)){
+            /* got accurate check query */
+            perform_accurate_check(ctx);
+            continue;
+         }
          if (bstrcmp(cmd.c_str(), "ACL")){
             /* got ACL header */
             perform_read_acl(ctx);
@@ -1761,6 +1768,12 @@ bRC METAPLUGIN::perform_read_metacommands(bpContext *ctx)
    return bRC_Error;
 }
 
+/**
+ * @brief Respond to the file index query command from backend.
+ *
+ * @param ctx bpContext - for Bacula debug and jobinfo messages
+ * @return bRC bRC_OK when success, bRC_Error if not
+ */
 bRC METAPLUGIN::perform_file_index_query(bpContext *ctx)
 {
    POOL_MEM cmd(PM_FNAME);
@@ -1776,6 +1789,90 @@ bRC METAPLUGIN::perform_file_index_query(bpContext *ctx)
    return bRC_OK;
 }
 
+/**
+ * @brief
+ *
+ * @param ctx bpContext - for Bacula debug and jobinfo messages
+ * @return bRC bRC_OK when success, bRC_Error if not
+ */
+bRC METAPLUGIN::perform_accurate_check(bpContext *ctx)
+{
+   if (strlen(fname.c_str()) == 0){
+      // input variable is not valid
+      return bRC_Error;
+   }
+
+   DMSG0(ctx, DDEBUG, "perform_accurate_check()\n");
+
+   POOL_MEM cmd(PM_FNAME);
+#if __cplusplus >= 201103L
+   struct save_pkt sp {0};
+#else
+   struct save_pkt sp;
+   memset(sp, 0, sizeof(sp));
+#endif
+
+   // supported sequence is `STAT` followed by `TSTAMP`
+   if (backend.ctx->read_command(ctx, cmd) < 0) {
+      // error
+      return bRC_Error;
+   }
+
+   metaplugin::attributes::Status status = metaplugin::attributes::read_scan_stat_command(ctx, cmd, &sp);
+   if (status == metaplugin::attributes::Status_OK) {
+      if (backend.ctx->read_command(ctx, cmd) < 0) {
+         // error
+         return bRC_Error;
+      }
+
+      status = metaplugin::attributes::read_scan_tstamp_command(ctx, cmd, &sp);
+      if (status == metaplugin::attributes::Status_OK) {
+         // success we can perform accurate check for stat packet
+         bRC rc = bRC_OK;  // return 'OK' as a default
+         if (accurate_mode) {
+            sp.fname = fname.c_str();
+            rc = checkChanges(&sp);
+         } else {
+            if (!accurate_mode_err) {
+               DMSG0(ctx, DERROR, "Backend CHECK command require accurate mode on!\n");
+               JMSG0(ctx, M_ERROR, "Backend CHECK command require accurate mode on!\n");
+               accurate_mode_err = true;
+            }
+         }
+
+         POOL_MEM checkstatus(PM_NAME);
+         Mmsg(checkstatus, "%s\n", rc == bRC_Seen ? "SEEN" : "OK");
+         DMSG1(ctx, DINFO, "perform_accurate_check(): %s", checkstatus.c_str());
+
+         if (!backend.ctx->write_command(ctx, checkstatus)) {
+            DMSG0(ctx, DERROR, "Cannot send checkChanges() response to backend\n");
+            JMSG0(ctx, backend.ctx->jmsg_err_level(), "Cannot send checkChanges() response to backend\n");
+            return bRC_Error;
+         }
+
+         return bRC_OK;
+      }
+   } else {
+      // check possible errors
+      switch (status)
+      {
+      case metaplugin::attributes::Invalid_File_Type:
+         JMSG2(ctx, M_ERROR, "Invalid file type: %c for %s\n", sp.type, fname.c_str());
+         return bRC_Error;
+
+      case metaplugin::attributes::Invalid_Stat_Packet:
+         JMSG1(ctx, backend.ctx->jmsg_err_level(), "Invalid stat packet: %s\n", cmd.c_str());
+         return bRC_Error;
+      default:
+         break;
+      }
+      // future extension for `ATTR` command
+      // ...
+   }
+
+   return bRC_Error;
+}
+
 /**
  * @brief
  *
@@ -2059,20 +2156,10 @@ bRC METAPLUGIN::setPluginValue(bpContext *ctx, pVariable var, void *value)
 bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp)
 {
    POOL_MEM cmd(PM_FNAME);
-   char type;
-   size_t size;
-   int uid, gid;
-   uint perms;
-   int nlinks;
-   int32_t nfi;
    int reqparams = 2;
 
-   {
-      // synchronie access to job_cancelled variable
-      // smart_lock<smart_mutex> lg(&mutex); - removed on request
-      if (job_cancelled) {
-         return bRC_Error;
-      }
+   if (job_cancelled) {
+      return bRC_Error;
    }
 
    /* The first file in Full backup, is the RestoreObject */
@@ -2115,7 +2202,7 @@ bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp)
       }
       sp->restore_obj.object_name = fname.c_str();
       sp->type = FT_RESTORE_FIRST;
-      size = sp->restore_obj.object_len;
+      sp->statp.st_size = sp->restore_obj.object_len;
       sp->statp.st_mode = 0700 | S_IFREG;
       {
          time_t now = time(NULL);
@@ -2131,7 +2218,7 @@ bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp)
          return bRC_Error;
       }
       sp->type = FT_PLUGIN_OBJECT;
-      size = sp->plugin_obj.object_size;
+      sp->statp.st_size = sp->plugin_obj.object_size;
       break;
    default:
       // here we handle standard file metadata information
@@ -2145,57 +2232,32 @@ bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp)
       while (backend.ctx->read_command(ctx, cmd) > 0)
       {
          DMSG(ctx, DINFO, "read_command(2): %s\n", cmd.c_str());
-         // int nrscan = sscanf(cmd.c_str(), "STAT:%c %ld %d %d %o %d", &type, &size, &uid, &gid, &perms, &nlinks);
-         nfi = -1;
-         int nrscan = sscanf(cmd.c_str(), "STAT:%c %ld %d %d %o %d %d", &type, &size, &uid, &gid, &perms, &nlinks, &nfi);
-         DMSG1(ctx, DVDEBUG, "read_command-nrscan: %d\n", nrscan);
-         if (nrscan >= 6)
+         metaplugin::attributes::Status status = metaplugin::attributes::read_scan_stat_command(ctx, cmd, sp);
+         switch (status)
          {
-            sp->statp.st_size = size;
-            sp->statp.st_nlink = nlinks;
-            sp->statp.st_uid = uid;
-            sp->statp.st_gid = gid;
-            sp->statp.st_mode = perms;
-            switch (type)
-            {
-            case 'F':
-               sp->type = FT_REG;
-               break;
-            case 'E':
-               sp->type = FT_REGE;
-               break;
-            case 'D':
-               sp->type = FT_DIREND;
-               sp->link = sp->fname;
-               break;
-            case 'S':
-               sp->type = FT_LNK;
-               reqparams++;
-               break;
-            case 'L':
-               if (nrscan > 6){
-                  sp->type = FT_LNKSAVED;
-                  sp->LinkFI = nfi;
-               } else {
-                  DMSG1(ctx, DERROR, "Invalid stat packet: %s\n", cmd.c_str());
-                  JMSG1(ctx, backend.ctx->jmsg_err_level(), "Invalid stat packet: %s\n", cmd.c_str());
-                  return bRC_Error;
-               }
-               break;
-            default:
-               /* we need to signal error */
-               sp->type = FT_REG;
-               DMSG2(ctx, DERROR, "Invalid file type: %c for %s\n", type, fname.c_str());
-               JMSG2(ctx, M_ERROR, "Invalid file type: %c for %s\n", type, fname.c_str());
+         case metaplugin::attributes::Invalid_File_Type:
+            JMSG2(ctx, M_ERROR, "Invalid file type: %c for %s\n", sp->type, fname.c_str());
+            return bRC_Error;
+
+         case metaplugin::attributes::Invalid_Stat_Packet:
+            JMSG1(ctx, backend.ctx->jmsg_err_level(), "Invalid stat packet: %s\n", cmd.c_str());
+            return bRC_Error;
+
+         case metaplugin::attributes::Status_OK:
+            if (sp->type != FT_LNK) {
+               reqparams--;
             }
-            DMSG4(ctx, DINFO, "STAT:%c size:%lld uid:%d gid:%d\n", type, size, uid, gid);
-            DMSG3(ctx, DINFO, " mode:%06o nl:%d fi:%d\n", perms, nlinks, nfi);
-            reqparams--;
             continue;
+         default:
+            break;
          }
-         if (bsscanf(cmd.c_str(), "TSTAMP:%ld %ld %ld", &sp->statp.st_atime, &sp->statp.st_mtime, &sp->statp.st_ctime) == 3){
-            DMSG3(ctx, DINFO, "TSTAMP:%ld(at) %ld(mt) %ld(ct)\n", sp->statp.st_atime, sp->statp.st_mtime, sp->statp.st_ctime);
+         status = metaplugin::attributes::read_scan_tstamp_command(ctx, cmd, sp);
+         switch (status)
+         {
+         case metaplugin::attributes::Status_OK:
             continue;
+         default:
+            break;
          }
          if (scan_parameter_str(cmd, "LSTAT:", lname) == 1) {
             sp->link = lname.c_str();
@@ -2256,9 +2318,10 @@ bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp)
 
    sp->portable = true;
    sp->statp.st_blksize = 4096;
-   sp->statp.st_blocks = size / 4096 + 1;
+   sp->statp.st_blocks = sp->statp.st_size / 4096 + 1;
 
-   // DMSG1(ctx, DVDEBUG, "sp->plug_meta = %p\n", sp->plug_meta);
+   DMSG3(ctx, DINFO, "TSDebug: %ld(at) %ld(mt) %ld(ct)\n",
+         sp->statp.st_atime, sp->statp.st_mtime, sp->statp.st_ctime);
 
    return bRC_OK;
 }
@@ -2344,7 +2407,7 @@ bRC METAPLUGIN::startRestoreFile(bpContext *ctx, const char *cmd)
             }
 
             /* send data */
-            if (backend.ctx->send_data(ctx, ropclass->data.c_str(), ropclass->length) != bRC_OK) {
+            if (backend.ctx->send_data(ctx, ropclass->data, ropclass->length) != bRC_OK) {
                DMSG0(ctx, DERROR, "Error sending RestoreObject data\n");
                return bRC_Error;
             }
@@ -2381,7 +2444,7 @@ bRC METAPLUGIN::endRestoreFile(bpContext *ctx)
 bRC METAPLUGIN::createFile(bpContext *ctx, struct restore_pkt *rp)
 {
    POOL_MEM cmd(PM_FNAME);
-   char type;
+   // char type;
 
    {
       // synchronie access to job_cancelled variable
@@ -2402,44 +2465,26 @@ bRC METAPLUGIN::createFile(bpContext *ctx, struct restore_pkt *rp)
       Mmsg(cmd, "FNAME:%s\n", rp->ofname);
       backend.ctx->write_command(ctx, cmd);
       DMSG(ctx, DINFO, "createFile:%s", cmd.c_str());
+
       /* STAT:... */
-      switch (rp->type)
-      {
-      case FT_REGE:
-         type = 'E';
-         break;
-      case FT_DIREND:
-         type = 'D';
-         break;
-      case FT_LNK:
-         type = 'S';
-         break;
-      case FT_LNKSAVED:
-         type = 'L';
-         break;
-      case FT_REG:
-      default:
-         type = 'F';
-         break;
-      }
-      last_type = rp->type;
-      Mmsg(cmd, "STAT:%c %lld %d %d %06o %d %d\n",
-           type, rp->statp.st_size, rp->statp.st_uid, rp->statp.st_gid,
-           rp->statp.st_mode, (int)rp->statp.st_nlink, rp->LinkFI);
+      metaplugin::attributes::make_stat_command(ctx, cmd, rp);
       backend.ctx->write_command(ctx, cmd);
+      last_type = rp->type;
       DMSG(ctx, DINFO, "createFile:%s", cmd.c_str());
+
       /* TSTAMP:... */
-      if (rp->statp.st_atime || rp->statp.st_mtime || rp->statp.st_ctime){
-         Mmsg(cmd, "TSTAMP:%ld %ld %ld\n", rp->statp.st_atime, rp->statp.st_mtime, rp->statp.st_ctime);
+      if (metaplugin::attributes::make_tstamp_command(ctx, cmd, rp) == metaplugin::attributes::Status_OK) {
          backend.ctx->write_command(ctx, cmd);
          DMSG(ctx, DINFO, "createFile:%s", cmd.c_str());
       }
+
       /* LSTAT:$link$ */
-      if (type == 'S' && rp->olname != NULL){
+      if (rp->type == FT_LNK && rp->olname != NULL){
          Mmsg(cmd, "LSTAT:%s\n", rp->olname);
          backend.ctx->write_command(ctx, cmd);
          DMSG(ctx, DINFO, "createFile:%s", cmd.c_str());
       }
+
       backend.ctx->signal_eod(ctx);
 
       /* check if backend accepted the file */
index 58549fc62dfc3555bbcde170c7c0a46e72e59802..923511f040bc7c0477cbd9a33de4c263588431f9 100644 (file)
@@ -143,6 +143,8 @@ public:
                   JobId(0),
                   JobName(NULL),
                   since(0),
+                  accurate_mode(0),
+                  accurate_mode_err(false),
                   where(NULL),
                   regexwhere(NULL),
                   replace(0),
@@ -206,6 +208,8 @@ private:
    int JobId;                    // Job ID
    char *JobName;                // Job name
    time_t since;                 // Job since parameter
+   int accurate_mode;            // if the job is accurate
+   bool accurate_mode_err;       // if true then no more errors about lack of accurate mode required
    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
@@ -274,6 +278,7 @@ private:
    bRC perform_write_xattr(bpContext *ctx, const xacl_pkt * xacl);
    bRC perform_read_metadata_info(bpContext *ctx, metadata_type type, struct save_pkt *sp);
    bRC perform_file_index_query(bpContext *ctx);
+   bRC perform_accurate_check(bpContext *ctx);
    // bRC perform_write_metadata_info(bpContext *ctx, struct meta_pkt *mp);
    metadata_type scan_metadata_type(bpContext *ctx, const POOL_MEM &cmd);
    const char *prepare_metadata_type(metadata_type type);
index 8fd2a7a1dd443974e1a90bf5302634ac36a9d0ea..9916313db15348d5c03a5b0af6b11cfe0b41b532 100644 (file)
@@ -91,6 +91,7 @@ extern const char *PLUGINNAME;
 #define DVDEBUG D4
 
 #define getBaculaVar(bvar,val)  bfuncs->getBaculaValue(ctx, bvar, val);
+#define checkChanges(sp)   bfuncs->checkChanges(ctx, sp);
 
 /* used for sanity check in plugin functions */
 #define ASSERT_CTX \
index 462fe81cd1451a2d60098d54cd18e8b0459ee630..88dd921ed1c9bf5d2a36b9159ae3ba69884fd4f0 100644 (file)
@@ -40,8 +40,6 @@
 #undef sscanf
 #endif
 
-#define SINGLE_SENDDATA
-
 /*
  * Closes external pipe if available (opened).
  *
@@ -574,10 +572,14 @@ int32_t PTCOMM::recvbackend_fixed(bpContext *ctx, char cmd, char *buf, int32_t b
  * @param cmd the packet status to send
  * @param buf the packet contents
  * @param len the length of the contents
+ * @param _single_senddata defines if function should optimize the send_data call
+ *    using POOLMEM* extra space (the default) or not.
+ *    Warning: the optimization works only(!) with POOLMEM/POOL_MEM memory.
+ *           Other memory buffers, i.e. a const buf will fail with SIGSEGV.
  * @return true success
  * @return false when encountered any error
  */
-bool PTCOMM::sendbackend(bpContext *ctx, char cmd, const POOLMEM *buf, int32_t len)
+bool PTCOMM::sendbackend(bpContext *ctx, char cmd, const POOLMEM *buf, int32_t len, bool _single_senddata)
 {
    PTHEADER *header;
    PTHEADER myheader;
@@ -595,23 +597,24 @@ bool PTCOMM::sendbackend(bpContext *ctx, char cmd, const POOLMEM *buf, int32_t l
       return false;
    }
 
-#ifdef SINGLE_SENDDATA
-   // The code at SINGLE_SENDDATA uses POOLMEM abufhead reserved space for
-   // packet header rendering in the same way as bsock.c do. The code was tested
-   // and is working fine. No memory leakage or corruption encountered.
-   // The only pros for this code is a single sendbackend_data call for a whole
-   // message instead of two sendbackend_data callse (header + data) for a standard
-   // method.
-   if (buf){
-      // we will prepare POOLMEM for sending data so we can render header here
-      header = (PTHEADER*) (buf - sizeof(PTHEADER));
+   if (_single_senddata) {
+      // The code at `_single_senddata` uses POOLMEM abufhead reserved space for
+      // packet header rendering in the same way as bsock.c do. The code was tested
+      // and is working fine. No memory leakage or corruption encountered.
+      // The only pros for this code is a single sendbackend_data call for a whole
+      // message instead of two sendbackend_data callse (header + data) for a standard
+      // method.
+      if (buf){
+         // we will prepare POOLMEM for sending data so we can render header here
+         header = (PTHEADER*) (buf - sizeof(PTHEADER));
+      } else {
+         // we will send header only
+         header = &myheader;
+      }
    } else {
-      // we will send header only
       header = &myheader;
    }
-#else
-   header = &myheader;
-#endif
+
    header->status = cmd;
 
    if (bsnprintf(header->length, sizeof(header->length), "%06i\n", len) != 7){
@@ -626,11 +629,14 @@ bool PTCOMM::sendbackend(bpContext *ctx, char cmd, const POOLMEM *buf, int32_t l
    char bindata[17];
    DMSG2(ctx, DDEBUG, "SENT: %s %s\n", asciidump((char*)header, sizeof(PTHEADER), hlendata, sizeof(hlendata)), asciidump(buf, len, bindata, sizeof(bindata)));
 
-#ifdef SINGLE_SENDDATA
-   if (!sendbackend_data(ctx, (char*)header, len + sizeof(PTHEADER))){
-#else
-   if (!sendbackend_data(ctx, (char*)header, sizeof(PTHEADER)) || !sendbackend_data(ctx, buf, len)){
-#endif
+   bool _status;
+   if (_single_senddata) {
+      _status = sendbackend_data(ctx, (char *)header, len + sizeof(PTHEADER));
+   } else {
+      _status = sendbackend_data(ctx, (char *)header, sizeof(PTHEADER)) && sendbackend_data(ctx, buf, len);
+   }
+
+   if (!_status){
       // error
       DMSG0(ctx, DERROR, "PTCOMM cannot write packet to backend.\n");
       JMSG0(ctx, is_fatal() ? M_FATAL : M_ERROR, "PTCOMM cannot write packet to backend.\n");
@@ -778,21 +784,19 @@ bool PTCOMM::read_ack(bpContext *ctx)
    return false;
 }
 
-/*
- * Sends a command to the backend.
+/**
+ * @brief Sends a command to the backend.
  *    The command has to be a nul terminated string.
  *
- * in:
- *    bpContext - for Bacula debug and jobinfo messages
- *    buf - a message buffer contains command to send
- * out:
- *    -1 - when encountered any error
- *    <n> - the number of bytes sent, success
+ * @param ctx for Bacula debug and jobinfo messages
+ * @param buf a message buffer contains command to send
+ * @return true success
+ * @return false when encountered any error
  */
-bool PTCOMM::write_command(bpContext *ctx, const char *buf)
+bool PTCOMM::write_command(bpContext *ctx, const char *buf, bool _single_senddata)
 {
    int32_t len = buf ? strlen(buf) : 0;
-   return sendbackend(ctx, 'C', buf, len);
+   return sendbackend(ctx, 'C', buf, len, _single_senddata);
 }
 
 /*
@@ -807,7 +811,7 @@ bool PTCOMM::write_command(bpContext *ctx, const char *buf)
  *    -1 - when encountered any error
  *    <n> - the number of bytes sent, success
  */
-int32_t PTCOMM::write_data(bpContext *ctx, const char *buf, int32_t len)
+int32_t PTCOMM::write_data(bpContext *ctx, const char *buf, int32_t len, bool _single_senddata)
 {
    int32_t status;
 
@@ -815,7 +819,7 @@ int32_t PTCOMM::write_data(bpContext *ctx, const char *buf, int32_t len)
       status = write(extpipe, buf, len);
    } else {
       status = len;
-      if (!sendbackend(ctx, 'D', buf, len)){
+      if (!sendbackend(ctx, 'D', buf, len, _single_senddata)){
          status = -1;
       }
    }
@@ -897,7 +901,7 @@ bool PTCOMM::handshake(bpContext *ctx, const char *pluginname, const char * plug
  * @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)
+bRC PTCOMM::send_data(bpContext *ctx, const char *buf, int32_t len, bool _single_senddata)
 {
    /* send data */
    int32_t offset = 0;
@@ -905,7 +909,7 @@ bRC PTCOMM::send_data(bpContext *ctx, const char *buf, int32_t len)
    while (offset < len)
    {
       int32_t count = MIN(len - offset, PTCOMM_MAX_PACKET_SIZE);
-      int32_t status = write_data(ctx, buf + offset, count);
+      int32_t status = write_data(ctx, buf + offset, count, _single_senddata);
       if (status < 0) {
          /* got some error */
          return bRC_Error;
index 22a6faf135ff6ce3310b2c1e8be357c543e7c1b5..0ac2e7ab80df4fd0119bef0c82d3dc8bd5aa8e79 100644 (file)
@@ -98,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);
 
-   bool sendbackend(bpContext *ctx, char cmd, const POOLMEM *buf, int32_t len);
+   bool sendbackend(bpContext *ctx, char cmd, const POOLMEM *buf, int32_t len, bool _single_senddata = true);
 
 public:
    PTCOMM(const char * command = NULL) :
@@ -130,9 +130,11 @@ public:
    int32_t read_data(bpContext *ctx, POOL_MEM &buf);
    int32_t read_data_fixed(bpContext *ctx, char *buf, int32_t len);
 
-   bool write_command(bpContext *ctx, const char *buf);
+   // we have to force non-optimized sendbackend path as origin of `*buf` is unknown
+   bool write_command(bpContext *ctx, const char *buf, bool _single_senddata = false);
 
-   bRC send_data(bpContext *ctx, const char *buf, int32_t len);
+   bRC send_data(bpContext *ctx, const char *buf, int32_t len, bool _single_senddata = false);
+   bRC send_data(bpContext *ctx, POOL_MEM &buf, int32_t len) { return send_data(ctx, buf.addr(), true); }
    bRC recv_data(bpContext *ctx, POOL_MEM &buf, int32_t *recv_len=NULL);
 
    /**
@@ -144,8 +146,8 @@ public:
     *    -1 - when encountered any error
     *    <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, const char *buf, int32_t len);
+   int32_t write_command(bpContext *ctx, POOL_MEM &buf) { return write_command(ctx, buf.addr(), true); }
+   int32_t write_data(bpContext *ctx, const char *buf, int32_t len, bool _single_senddata = false);
 
    bool read_ack(bpContext *ctx);
    bool send_ack(bpContext *ctx);