#include "filed.h"
extern CLIENT *me;
+extern DLL_IMP_EXP char *exepath;
const int dbglvl = 150;
#ifdef HAVE_WIN32
#endif
extern int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level);
+extern bool check_changes(JCR *jcr, FF_PKT *ff_pkt);
/* Function pointers to be set here */
extern DLL_IMP_EXP int (*plugin_bopen)(BFILE *bfd, const char *fname, int flags, mode_t mode);
static bRC baculaNewInclude(bpContext *ctx);
static bool is_plugin_compatible(Plugin *plugin);
static bool get_plugin_name(JCR *jcr, char *cmd, int *ret);
+static bRC baculaCheckChanges(bpContext *ctx, struct save_pkt *sp);
/*
* These will be plugged into the global pointer structure for
baculaAddRegex,
baculaAddWild,
baculaNewOptions,
- baculaNewInclude
+ baculaNewInclude,
+ baculaCheckChanges
};
/*
bEvent event;
Plugin *plugin;
int i = 0;
- char *name=NULL;
- int len;
+ char *name = NULL;
+ int len = 0;
+ bool call_if_canceled = false;
bRC rc;
- if (!plugin_list || !jcr || !jcr->plugin_ctx_list || jcr->is_job_canceled()) {
+ if (!plugin_list || !jcr || !jcr->plugin_ctx_list) {
return; /* Return if no plugins loaded */
}
- /* Some events are sent to only a particular plugin */
+ /*
+ * Some events are sent to only a particular plugin or must be
+ * called even if the job is canceled
+ */
switch(eventType) {
case bEventPluginCommand:
name = (char *)value;
return;
}
break;
+ case bEventEndBackupJob:
+ case bEventEndVerifyJob:
+ call_if_canceled = true;
+ break;
+ case bEventEndRestoreJob:
+ call_if_canceled = true;
+ if (jcr->plugin && jcr->plugin->restoreFileStarted) {
+ plug_func(jcr->plugin)->endRestoreFile(jcr->plugin_ctx);
+ jcr->plugin->restoreFileStarted = false;
+ }
+ break;
default:
break;
}
+ if (!call_if_canceled && jcr->is_job_canceled()) {
+ return;
+ }
+
bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
event.eventType = eventType;
* systemstate:/@SYSTEMSTATE/
* => ret = 11
* => can use strncmp(plugin_name, cmd, ret);
+ *
+ * The plugin command can contain only the plugin name
+ * Plugin = alldrives
+ * => ret = 9
*/
static bool get_plugin_name(JCR *jcr, char *cmd, int *ret)
{
char *p;
int len;
- if (!cmd) {
+ if (!cmd || (*cmd == '\0')) {
return false;
}
/* Handle plugin command here backup */
Dmsg1(dbglvl, "plugin cmd=%s\n", cmd);
- if (!(p = strchr(cmd, ':'))) {
- Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
- return false;
- }
- len = p - cmd;
- if (len <= 0) {
- return false;
+ if ((p = strchr(cmd, ':')) == NULL) {
+ if (strchr(cmd, ' ') == NULL) { /* we have just the plugin name */
+ len = strlen(cmd);
+ } else {
+ Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
+ return false;
+ }
+ } else { /* plugin:argument */
+ len = p - cmd;
+ if (len <= 0) {
+ return false;
+ }
}
*ret = len;
return true;
POOL_MEM link(PM_FNAME);
if (!plugin_list || !jcr->plugin_ctx_list || jcr->is_job_canceled()) {
- Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" not loaded.\n", cmd);
+ Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd);
return 1; /* Return if no plugins loaded */
}
sp.pkt_size = sizeof(sp);
sp.pkt_end = sizeof(sp);
sp.portable = true;
+ sp.flags = 0;
sp.cmd = cmd;
Dmsg3(dbglvl, "startBackup st_size=%p st_blocks=%p sp=%p\n", &sp.statp.st_size, &sp.statp.st_blocks,
&sp);
pm_strcpy(link, sp.link);
ff_pkt->fname = fname.c_str();
ff_pkt->link = link.c_str();
+ ff_pkt->delta_seq = sp.delta_seq;
+ if (sp.flags & FO_DELTA) {
+ ff_pkt->flags |= FO_DELTA;
+ ff_pkt->delta_seq++; /* make new delta sequence number */
+ } else {
+ ff_pkt->flags &= ~FO_DELTA; /* clean delta sequence number */
+ ff_pkt->delta_seq = 0;
+ }
}
memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp));
continue;
}
goto bail_out;
- }
+ } /* end while loop */
goto bail_out;
- }
+ } /* end loop over all plugins */
Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" not found.\n", cmd);
bail_out:
* End of plugin data, notify plugin, then clear flags
*/
Dmsg2(dbglvl, "End plugin data plugin=%p ctx=%p\n", jcr->plugin, jcr->plugin_ctx);
- if (jcr->plugin) {
+ if (jcr->plugin && jcr->plugin->restoreFileStarted) {
plug_func(jcr->plugin)->endRestoreFile(jcr->plugin_ctx);
+ jcr->plugin->restoreFileStarted = false;
}
jcr->plugin_ctx = NULL;
jcr->plugin = NULL;
goto bail_out;
}
/* ***FIXME**** check error code */
+ if (plugin->restoreFileStarted) {
+ plug_func(jcr->plugin)->endRestoreFile(jcr->plugin_ctx);
+ }
plug_func(plugin)->startRestoreFile((bpContext *)jcr->plugin_ctx, cmd);
+ plugin->restoreFileStarted = true;
goto bail_out;
}
Jmsg1(jcr, M_WARNING, 0, _("Plugin=%s not found.\n"), cmd);
rc, attr->ofname);
return CF_ERROR;
}
+ if (rp.create_status == CF_SKIP) {
+ return CF_SKIP;
+ }
if (rp.create_status == CF_ERROR) {
Qmsg1(jcr, M_ERROR, 0, _("Plugin createFile call failed. Returned CF_ERROR file=%s\n"),
attr->ofname);
static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value)
{
JCR *jcr;
- if (!value || !ctx) {
+ if (!value) {
return bRC_Error;
}
-// Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
+
+ switch (var) { /* General variables, no need of ctx */
+ case bVarFDName:
+ *((char **)value) = my_name;
+ break;
+ case bVarWorkingDir:
+ *(void **)value = me->working_directory;
+ break;
+ case bVarExePath:
+ *(char **)value = exepath;
+ break;
+ default:
+ break;
+ }
+
+ if (!ctx) { /* Other variables need context */
+ return bRC_Error;
+ }
+
jcr = ((bacula_ctx *)ctx->bContext)->jcr;
if (!jcr) {
return bRC_Error;
}
-// Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
+
switch (var) {
case bVarJobId:
*((int *)value) = jcr->JobId;
Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
break;
- case bVarFDName:
- *((char **)value) = my_name;
- Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name);
- break;
case bVarLevel:
*((int *)value) = jcr->getJobLevel();
Dmsg1(dbglvl, "Bacula: return bVarJobLevel=%d\n", jcr->getJobLevel());
}
#endif
return bRC_Error;
+ case bVarWhere:
+ *(char **)value = jcr->where;
+ break;
+ case bVarRegexWhere:
+ *(char **)value = jcr->RegexWhere;
+ break;
+
+ case bVarFDName: /* get warning with g++ if we missed one */
case bVarWorkingDir:
- *(void **)value = me->working_directory;
+ case bVarExePath:
break;
}
return bRC_OK;
}
+/*
+ * Check if a file have to be backuped using Accurate code
+ */
+static bRC baculaCheckChanges(bpContext *ctx, struct save_pkt *sp)
+{
+ JCR *jcr;
+ bacula_ctx *bctx;
+ FF_PKT *ff_pkt;
+ bRC ret = bRC_Error;
+
+ if (!is_ctx_good(ctx, jcr, bctx)) {
+ goto bail_out;
+ }
+ if (!sp) {
+ goto bail_out;
+ }
+
+ ff_pkt = jcr->ff;
+ /*
+ * Copy fname and link because save_file() zaps them. This
+ * avoids zaping the plugin's strings.
+ */
+ ff_pkt->type = sp->type;
+ if (!sp->fname) {
+ Jmsg0(jcr, M_FATAL, 0, _("Command plugin: no fname in baculaCheckChanges packet.\n"));
+ goto bail_out;
+ }
+
+ ff_pkt->fname = sp->fname;
+ ff_pkt->link = sp->link;
+ memcpy(&ff_pkt->statp, &sp->statp, sizeof(ff_pkt->statp));
+
+ if (check_changes(jcr, ff_pkt)) {
+ ret = bRC_OK;
+ } else {
+ ret = bRC_Seen;
+ }
+
+ /* check_changes() can update delta sequence number, return it to the
+ * plugin
+ */
+ sp->delta_seq = ff_pkt->delta_seq;
+
+bail_out:
+ Dmsg1(100, "checkChanges=%i\n", ret);
+ return ret;
+}
+
+
#ifdef TEST_PROGRAM
int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL;