From: Radosław Korzeniewski Date: Wed, 25 Aug 2021 14:52:53 +0000 (+0200) Subject: metaplugin: Add accurate mode query. X-Git-Tag: Release-11.3.2~370 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ecbb5b3d6039c7630e6e1a1979a6cba130a87735;p=thirdparty%2Fbacula.git metaplugin: Add accurate mode query. 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. --- diff --git a/bacula/src/plugins/fd/Makefile.inc.in b/bacula/src/plugins/fd/Makefile.inc.in index de286475a..545c2be52 100644 --- a/bacula/src/plugins/fd/Makefile.inc.in +++ b/bacula/src/plugins/fd/Makefile.inc.in @@ -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 diff --git a/bacula/src/plugins/fd/pluginlib/Makefile b/bacula/src/plugins/fd/pluginlib/Makefile index 89b6238d7..a6a13ddb5 100644 --- a/bacula/src/plugins/fd/pluginlib/Makefile +++ b/bacula/src/plugins/fd/pluginlib/Makefile @@ -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) diff --git a/bacula/src/plugins/fd/pluginlib/metaplugin.cpp b/bacula/src/plugins/fd/pluginlib/metaplugin.cpp index cce6282f3..28f265178 100644 --- a/bacula/src/plugins/fd/pluginlib/metaplugin.cpp +++ b/bacula/src/plugins/fd/pluginlib/metaplugin.cpp @@ -27,6 +27,7 @@ */ #include "metaplugin.h" +#include "metaplugin_attributes.h" #include #include #include @@ -1261,6 +1262,7 @@ bRC METAPLUGIN::handlePluginEvent(bpContext *ctx, bEvent *event, void *value) /* Plugin command e.g. plugin = :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 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 */ diff --git a/bacula/src/plugins/fd/pluginlib/metaplugin.h b/bacula/src/plugins/fd/pluginlib/metaplugin.h index 58549fc62..923511f04 100644 --- a/bacula/src/plugins/fd/pluginlib/metaplugin.h +++ b/bacula/src/plugins/fd/pluginlib/metaplugin.h @@ -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); diff --git a/bacula/src/plugins/fd/pluginlib/pluginlib.h b/bacula/src/plugins/fd/pluginlib/pluginlib.h index 8fd2a7a1d..9916313db 100644 --- a/bacula/src/plugins/fd/pluginlib/pluginlib.h +++ b/bacula/src/plugins/fd/pluginlib/pluginlib.h @@ -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 \ diff --git a/bacula/src/plugins/fd/pluginlib/ptcomm.cpp b/bacula/src/plugins/fd/pluginlib/ptcomm.cpp index 462fe81cd..88dd921ed 100644 --- a/bacula/src/plugins/fd/pluginlib/ptcomm.cpp +++ b/bacula/src/plugins/fd/pluginlib/ptcomm.cpp @@ -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 - * - 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 * - 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; diff --git a/bacula/src/plugins/fd/pluginlib/ptcomm.h b/bacula/src/plugins/fd/pluginlib/ptcomm.h index 22a6faf13..0ac2e7ab8 100644 --- a/bacula/src/plugins/fd/pluginlib/ptcomm.h +++ b/bacula/src/plugins/fd/pluginlib/ptcomm.h @@ -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 * - 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);