delete jcr->store_mngr;
- if (jcr->JobId != 0)
+ if (jcr->JobId != 0) {
write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
-
+ }
+ bfree_and_null(jcr->plugin_options);
if (jcr->plugin_config) {
free_plugin_config_items(jcr->plugin_config);
- delete jcr->plugin_config;
- jcr->plugin_config = NULL;
+ bdelete_and_null(jcr->plugin_config);
}
free_plugins(jcr); /* release instantiated plugins */
add_prompt(ua, _("Replace")); /* 10 */
add_prompt(ua, _("JobId")); /* 11 */
}
- if (jcr->getJobType() == JT_BACKUP || jcr->getJobType() == JT_RESTORE) {
+ if (jcr->getJobType() == JT_BACKUP || jcr->getJobType() == JT_RESTORE || jcr->is_JobType(JT_VERIFY)) {
add_prompt(ua, _("Plugin Options")); /* 12 */
}
switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
}
if (rc.plugin_options) {
- if (jcr->plugin_options) {
- free(jcr->plugin_options);
- }
+ bfree_and_null(jcr->plugin_options);
jcr->plugin_options = bstrdup(rc.plugin_options);
rc.plugin_options = NULL;
}
ua->signal(BNET_RUN_CMD);
ua->send_msg("Type: Verify\n"
"Title: Run Verify Job\n"
- "JobName: %s\n"
- "Level: %s\n"
- "Client: %s\n"
- "FileSet: %s\n"
- "Pool: %s (From %s)\n"
- "Storage: %s (From %s)\n"
- "Verify Job: %s\n"
- "Verify List: %s\n"
- "When: %s\n"
- "Priority: %d\n",
+ "JobName: %s\n"
+ "Level: %s\n"
+ "Client: %s\n"
+ "FileSet: %s\n"
+ "Pool: %s (From %s)\n"
+ "Storage: %s (From %s)\n"
+ "Verify Job: %s\n"
+ "Verify List: %s\n"
+ "When: %s\n"
+ "Priority: %d\n"
+ "Plugin Options: %s\n",
job->name(),
level_to_str(edl, sizeof(edl), jcr->getJobLevel()),
jcr->client->name(),
Name,
verify_list,
bstrutime(dt, sizeof(dt), jcr->sched_time),
- jcr->JobPriority);
+ jcr->JobPriority,
+ NPRT(jcr->plugin_options));
} else {
ua->send_msg(_("Run Verify Job\n"
- "JobName: %s\n"
- "Level: %s\n"
- "Client: %s\n"
- "FileSet: %s\n"
- "Pool: %s (From %s)\n"
- "Storage: %s (From %s)\n"
- "Verify Job: %s\n"
- "Verify List: %s\n"
- "When: %s\n"
- "Priority: %d\n"),
+ "JobName: %s\n"
+ "Level: %s\n"
+ "Client: %s\n"
+ "FileSet: %s\n"
+ "Pool: %s (From %s)\n"
+ "Storage: %s (From %s)\n"
+ "Verify Job: %s\n"
+ "Verify List: %s\n"
+ "When: %s\n"
+ "Priority: %d\n"
+ "Plugin Options: %s\n"),
job->name(),
level_to_str(edl, sizeof(edl), jcr->getJobLevel()),
jcr->client->name(),
Name,
verify_list,
bstrutime(dt, sizeof(dt), jcr->sched_time),
- jcr->JobPriority);
+ jcr->JobPriority,
+ NPRT(jcr->plugin_options));
}
}
break;
kw_ok = true;
break;
case 25: /* pluginoptions */
- ua->send_msg(_("Plugin Options not yet implemented.\n"));
- return false;
if (rc.plugin_options) {
ua->send_msg(_("Plugin Options specified twice.\n"));
return false;
}
rc.plugin_options = ua->argv[i];
if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
- ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
+ ua->send_msg(_("No authorization for \"PluginOptions\" specification.\n"));
return false;
}
kw_ok = true;
rc.verify_job = rc.job->verify_job;
}
+ if (rc.job->JobType == JT_VERIFY && rc.job->PluginOptions) {
+ rc.plugin_options = rc.job->PluginOptions;
+ }
+
if (rc.previous_job_name) {
rc.previous_job = GetJobResWithName(rc.previous_job_name);
if (!rc.previous_job) {
/* Responses received from File daemon */
static char OKverify[] = "2000 OK verify\n";
+static char OKPluginOptions[] = "2000 OK plugin options\n";
/* Commands received from Storage daemon */
static char OKbootstrap[] = "3000 OK bootstrap\n";
goto bail_out;
}
+ if (jcr->plugin_options) {
+ if (jcr->FDVersion < 15) {
+ Jmsg1(jcr, M_FATAL, 0, _("Unable to send PluginOptions to FD. Please upgrade the FD from %d to 15.\n"), jcr->FDVersion);
+ goto bail_out;
+ }
+ bash_spaces(jcr->plugin_options);
+ fd->fsend("pluginoptions=%s\n", jcr->plugin_options);
+ if (!response(jcr, fd, BSOCK_TYPE_FD, OKPluginOptions, "Verify", DISPLAY_ERROR)) {
+ goto bail_out;
+ }
+ }
+
/*
* Send verify command/level to File daemon
*/
static bRC baculaCheckChanges(bpContext *ctx, struct save_pkt *sp);
static bRC baculaAcceptFile(bpContext *ctx, struct save_pkt *sp);
static bRC baculaAccurateAttribs(bpContext *ctx, accurate_attribs_pkt *att);
+static void plugin_register_verify_data(bpContext *ctx);
/*
* These will be plugged into the global pointer structure for
bool disabled; /* set if plugin disabled */
bool restoreFileStarted;
bool createFileCalled;
+ bool verifyFileCalled; /* true if startVerifyFile() has been called */
bool cancelCalled; /* true if the plugin got the cancel event */
findINCEXE *exclude; /* pointer to exclude files */
findINCEXE *include; /* pointer to include/exclude files */
+ Plugin *plugin; /* pointer to the plugin itself */
};
static bacula_ctx *get_bacula_ctx(bpContext *plugin_ctx)
case bEventEndVerifyJob:
call_if_canceled = true; /* plugin *must* see this call */
break;
+ case bEventStartVerifyJob:
case bEventStartRestoreJob:
break;
case bEventEndRestoreJob:
if (is_plugin_disabled(jcr)) {
goto bail_out;
}
-
+ if (!plug_func(plugin)->startBackupFile || !plug_func(plugin)->endBackupFile) {
+ Dmsg1(dbglvl, "Plugin not suitable for Backup job %s\n", cmd);
+ goto bail_out;
+ }
Dmsg1(dbglvl, "Command plugin = %s\n", cmd);
/* Send the backup command to the right plugin*/
if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx, &event, cmd) != bRC_OK) {
if (is_plugin_disabled(jcr)) {
goto bail_out;
}
-
+ if (!plug_func(plugin)->startBackupFile || !plug_func(plugin)->endBackupFile) {
+ Dmsg1(dbglvl, "Plugin not suitable for Estimate job %s\n", cmd);
+ goto bail_out;
+ }
Dmsg1(dbglvl, "Command plugin = %s\n", cmd);
/* Send the backup command to the right plugin*/
if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx, &event, cmd) != bRC_OK) {
Dmsg1(dbglvl, "Plugin %s disabled\n", cmd);
goto bail_out;
}
+ if (!plug_func(plugin)->startRestoreFile || !plug_func(plugin)->endRestoreFile) {
+ Dmsg1(dbglvl, "Plugin not suitable for Restore job %s\n", cmd);
+ goto bail_out;
+ }
Dmsg1(dbglvl, "Restore Command plugin = %s\n", cmd);
event.eventType = bEventRestoreCommand;
if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx,
- &event, cmd) != bRC_OK) {
+ &event, cmd) != bRC_OK) {
Dmsg1(dbglvl, "Handle event failed. Plugin=%s\n", cmd);
goto bail_out;
}
return start;
}
+static void fill_restore_pkt(JCR *jcr, ATTR *attr, restore_pkt *rp)
+{
+ rp->pkt_size = sizeof(restore_pkt);
+ rp->pkt_end = sizeof(restore_pkt);
+ rp->delta_seq = attr->delta_seq;
+ rp->stream = attr->stream;
+ rp->data_stream = attr->data_stream;
+ rp->type = attr->type;
+ rp->file_index = attr->file_index;
+ rp->LinkFI = attr->LinkFI;
+ rp->uid = attr->uid;
+ rp->statp = attr->statp; /* structure assignment */
+ rp->attrEx = attr->attrEx;
+ if (jcr->is_JobType(JT_VERIFY)) {
+ rp->ofname = attr->fname;
+ } else {
+ rp->ofname = attr->ofname;
+ rp->olname = attr->olname;
+ }
+ rp->where = jcr->where;
+ rp->RegexWhere = jcr->RegexWhere;
+ rp->replace = jcr->replace;
+ rp->create_status = CF_ERROR;
+}
+
/**
* Tell the plugin to create the file. Return values are
* This is called only during Restore
if (!plugin || !plugin_ctx || jcr->is_job_canceled()) {
return CF_ERROR;
}
+ if (!plug_func(plugin)->createFile) {
+ Dmsg0(dbglvl, "Plugin not suitable for Restore job\n");
+ return CF_ERROR;
+ }
+
+ fill_restore_pkt(jcr, attr, &rp);
- rp.pkt_size = sizeof(rp);
- rp.pkt_end = sizeof(rp);
- rp.delta_seq = attr->delta_seq;
- rp.stream = attr->stream;
- rp.data_stream = attr->data_stream;
- rp.type = attr->type;
- rp.file_index = attr->file_index;
- rp.LinkFI = attr->LinkFI;
- rp.uid = attr->uid;
- rp.statp = attr->statp; /* structure assignment */
- rp.attrEx = attr->attrEx;
- rp.ofname = attr->ofname;
- rp.olname = attr->olname;
- rp.where = jcr->where;
- rp.RegexWhere = jcr->RegexWhere;
- rp.replace = jcr->replace;
- rp.create_status = CF_ERROR;
Dmsg4(dbglvl, "call plugin createFile stream=%d type=%d LinkFI=%d File=%s\n",
rp.stream, rp.type, rp.LinkFI, rp.ofname);
if (rp.attrEx) {
bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
memset(b_ctx, 0, sizeof(bacula_ctx));
b_ctx->jcr = jcr;
+ b_ctx->plugin = plugin;
plugin_ctx_list[i].bContext = (void *)b_ctx; /* Bacula private context */
plugin_ctx_list[i].pContext = NULL;
if (plug_func(plugin)->newPlugin(&plugin_ctx_list[i]) != bRC_OK) {
va_list args;
uint32_t event;
- Dsm_check(999);
- if (!ctx) {
- return bRC_Error;
- }
-
va_start(args, ctx);
while ((event = va_arg(args, uint32_t))) {
Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
+ switch (event) {
+ case bEventVerifyStream:
+ /* We will call specific function, maybe VerifyFile() + pluginIO */
+ plugin_register_verify_data(ctx);
+ break;
+ default:
+ Dmsg0(50, "Event registration not implemented\n");
+ break;
+ }
}
va_end(args);
Dsm_check(999);
return bRC_OK;
}
+bRC plugin_verify_data_close(JCR *jcr)
+{
+ bpContext *ctx;
+ bacula_ctx *bctx;
+ struct io_pkt io;
+ if (!jcr->plugin_verify) {
+ return bRC_Skip; // Nothing registered
+ }
+ foreach_alist(ctx, jcr->plugin_verify) {
+ bctx = get_bacula_ctx(ctx);
+ jcr->plugin_ctx = ctx;
+ jcr->plugin = bctx->plugin;
+ if (is_plugin_disabled(jcr)) {
+ continue;
+ }
+ if (bctx->verifyFileCalled) {
+ io.pkt_size = sizeof(io);
+ io.pkt_end = sizeof(io);
+ io.func = IO_CLOSE;
+ io.count = 0;
+ io.buf = NULL;
+ io.fname = NULL;
+ io.flags = 0;
+ io.mode = O_WRONLY;
+ io.win32 = false;
+ io.lerror = 0;
+ io.status = -1;
+ plug_func(jcr->plugin)->pluginIO(jcr->plugin_ctx, &io);
+ if (io.win32) {
+ errno = b_errno_win32;
+ } else {
+ errno = io.io_errno;
+ }
+ bctx->verifyFileCalled = false;
+ if (io.status >= 0) {
+ // Do something useful?
+ }
+ if (plug_func(jcr->plugin)->endVerifyFile) {
+ plug_func(jcr->plugin)->endVerifyFile(jcr->plugin_ctx); // Check the return code?
+ }
+ }
+ }
+ jcr->plugin_ctx = NULL;
+ jcr->plugin = NULL;
+ return bRC_OK;
+}
+
+
+bRC plugin_verify_data_update(JCR *jcr, char *data, int size)
+{
+ bpContext *ctx;
+ bacula_ctx *bctx;
+ struct io_pkt io;
+
+ if (!jcr->plugin_verify) {
+ return bRC_Skip; // Nothing registered
+ }
+ foreach_alist(ctx, jcr->plugin_verify) {
+ if (!is_ctx_good(ctx, jcr, bctx)) {
+ return bRC_Error;
+ }
+ jcr->plugin_ctx = ctx;
+ jcr->plugin = bctx->plugin;
+ if (is_plugin_disabled(jcr)) {
+ continue;
+ }
+ if (bctx->verifyFileCalled) {
+ io.pkt_size = sizeof(io);
+ io.pkt_end = sizeof(io);
+ io.func = IO_WRITE;
+ io.count = size;
+ io.buf = data;
+ io.fname = NULL;
+ io.flags = 0;
+ io.mode = O_WRONLY;
+ io.win32 = false;
+ io.lerror = 0;
+ io.status = -1;
+ plug_func(jcr->plugin)->pluginIO(jcr->plugin_ctx, &io);
+ if (io.win32) {
+ errno = b_errno_win32;
+ } else {
+ errno = io.io_errno;
+ }
+ if (io.status >= 0) {
+ // Do something useful? Maybe close
+ }
+
+ }
+ }
+ jcr->plugin_ctx = NULL;
+ jcr->plugin = NULL;
+ return bRC_OK;
+}
+
+/*
+ * @brief Bacula function called for each new file in verify data job
+ * @param JCR *jcr
+ * @param ATTR *attr
+ * @return int (file descriptor)
+ */
+bRC plugin_verify_data_open(JCR *jcr, ATTR *attr)
+{
+ bpContext *ctx;
+ restore_pkt rp;
+ bacula_ctx *bctx;
+ struct io_pkt io;
+ if (!jcr->plugin_verify) {
+ return bRC_Skip; // Nothing registered
+ }
+ foreach_alist(ctx, jcr->plugin_verify) {
+ if (!is_ctx_good(ctx, jcr, bctx)) {
+ return bRC_Error;
+ }
+ jcr->plugin_ctx = ctx;
+ jcr->plugin = bctx->plugin;
+ bctx->verifyFileCalled = false;
+ if (is_plugin_disabled(jcr)) {
+ continue;
+ }
+ fill_restore_pkt(jcr, attr, &rp);
+ if (plug_func(jcr->plugin)->startVerifyFile) {
+ if (plug_func(jcr->plugin)->startVerifyFile(jcr->plugin_ctx, &rp) == bRC_OK) {
+ io.pkt_size = sizeof(io);
+ io.pkt_end = sizeof(io);
+ io.func = IO_OPEN;
+ io.count = 0;
+ io.buf = NULL;
+ io.fname = attr->fname;
+ io.flags = 0;
+ io.mode = O_WRONLY;
+ io.win32 = false;
+ io.lerror = 0;
+ io.status = -1;
+ plug_func(jcr->plugin)->pluginIO(jcr->plugin_ctx, &io);
+ if (io.win32) {
+ errno = b_errno_win32;
+ } else {
+ errno = io.io_errno;
+ }
+ if (io.status >= 0) {
+ bctx->verifyFileCalled = true;
+ }
+ }
+ }
+ }
+ jcr->plugin_ctx = NULL;
+ jcr->plugin = NULL;
+ return bRC_OK;
+}
+
+/*
+ * @brief Bacula function to append a plugin registered to get a copy of the data
+ * during a Verify Data job
+ * @param JCR *jcr
+ * @param bpContext *ctx
+ * @return bool
+ */
+static void plugin_register_verify_data(bpContext *ctx)
+{
+ JCR *jcr;
+ bacula_ctx *bctx;
+ if (!is_ctx_good(ctx, jcr, bctx)) {
+ return;
+ }
+ if (!jcr->is_JobLevel(L_VERIFY_DATA)) {
+ return; /* Cannot register for non DATA job */
+ }
+ if (!jcr->plugin_verify) {
+ jcr->plugin_verify = New(alist(5, not_owned_by_alist));
+ }
+ jcr->plugin_verify->append(ctx);
+ /* TODO: check in me->plugins if we have options for this plugin */
+}
+
+
#ifdef TEST_PROGRAM
int (*plugin_bopen)(JCR *jcr, const char *fname, uint64_t flags, mode_t mode) = NULL;
bEventOptionPlugin = 23,
bEventHandleBackupFile = 24, /* Used with Options Plugin */
bEventComponentInfo = 25, /* Plugin component */
- bEventFeatures = 26 /* Ask for file list, ... "xxx,yyy,zzz" */
+ bEventFeatures = 26, /* Ask for file list, ... "xxx,yyy,zzz" */
+ bEventVerifyStream = 27, /* Register to get a copy of the data stream during verify */
} bEventType;
bool plugin_check_stream(JCR *jcr, int32_t &stream);
bool plugin_query_parameter(JCR *jcr, char *command, char *param, void sendit(JCR *jcr, const char *str));
bool plugin_backup_metadata(JCR *jcr, FF_PKT *ff_pkt);
+bRC plugin_verify_data_close(JCR *jcr);
+bRC plugin_verify_data_open(JCR *jcr, ATTR *attr);
+bRC plugin_verify_data_update(JCR *jcr, char *buf, int len);
#endif
#ifdef __cplusplus
bRC (*checkStream)(bpContext *ctx, struct stream_pkt *sp);
bRC (*queryParameter)(bpContext *ctx, struct query_pkt *qp);
bRC (*metadataRestore)(bpContext *ctx, struct meta_pkt *mp);
+ bRC (*startVerifyFile)(bpContext *ctx, struct restore_pkt *rp);
+ bRC (*endVerifyFile)(bpContext *ctx);
} pFuncs;
#define plug_func(plugin) ((pFuncs *)(plugin->pfuncs))
{"PidDirectory", store_dir, ITEM(res_client.pid_directory), 0, ITEM_REQUIRED, 0},
{"SubsysDirectory", store_dir, ITEM(res_client.subsys_directory), 0, 0, 0},
{"PluginDirectory", store_dir, ITEM(res_client.plugin_directory), 0, 0, 0},
+ {"Plugin", store_alist_str, ITEM(res_client.plugins), 0, 0, 0},
{"SnapshotCommand", store_str, ITEM(res_client.snapshot_command), 0, 0, 0},
{"ScriptsDirectory", store_dir, ITEM(res_client.scripts_directory), 0, 0, 0},
{"MaximumConcurrentJobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 20},
if (res->res_client.plugin_directory) {
free(res->res_client.plugin_directory);
}
+ if (res->res_client.plugins) {
+ delete res->res_client.plugins;
+ }
if (res->res_client.dedup_index_dir) {
free(res->res_client.dedup_index_dir);
}
char *pid_directory;
char *subsys_directory;
char *plugin_directory; /* Plugin directory */
+ alist *plugins; /* Non job specific Plugin options */
char *scripts_directory;
char *snapshot_command;
char *dedup_index_dir; /* Directory for local dedup cache (deprecated) */
extern int collect_cmd(JCR *jcr);
/* Forward referenced functions */
+static int pluginoptions_cmd(JCR *jcr);
static int backup_cmd(JCR *jcr);
static int component_cmd(JCR *jcr);
static int cancel_cmd(JCR *jcr);
{"restorefilelist", restorefilelist_cmd, 0},
{"statistics", collect_cmd, 0},
{"query", query_cmd, 0},
+ {"pluginoptions", pluginoptions_cmd, 0},
#ifdef DEVELOPER
{"exit", exit_cmd, 0},
#endif
#ifdef WIN32_VSS
VSSCleanup(jcr->pVSSClient);
#endif
+ bdelete_and_null(jcr->plugin_verify);
+ bdelete_and_null(jcr->plugin_options_list);
free_plugins(jcr); /* release instantiated plugins */
+
free_runscripts(jcr->RunScripts);
delete jcr->RunScripts;
free_path_list(jcr);
return 0;
}
+/*
+ * Get PluginOptions from the Director
+ *
+ */
+static int pluginoptions_cmd(JCR *jcr)
+{
+ POOL_MEM buf(PM_MESSAGE);
+ BSOCK *dir = jcr->dir_bsock;
+ buf.check_size(dir->msglen+1);
+ if (scan_string(dir->msg, "pluginoptions=%s", buf.c_str()) == 1) {
+ unbash_spaces(buf.c_str());
+ if (!jcr->plugin_options_list) {
+ jcr->plugin_options_list = New(alist(5, owned_by_alist));
+ }
+ jcr->plugin_options_list->append(bstrdup(buf.c_str()));
+
+ } else {
+ dir->fsend(_("2992 Bad pluginoptions command\n"));
+ return 0;
+ }
+ dir->fsend("2000 OK plugin options\n");
+ return 1;
+}
+
/*
* Small helper to manager a POLL request when the heartbeat is started
* When we send POLL, we get a OK message, but if the heartbeat is started
char digest[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)];
int stat;
int bget_ret = 0;
+ char *opts;
char *wbuf; /* write buffer */
uint32_t wsize; /* write size */
uint32_t rsize; /* read size */
dir = jcr->dir_bsock;
jcr->setJobStatus(JS_Running);
+ if (jcr->plugin_options_list) {
+ foreach_alist(opts, jcr->plugin_options_list) {
+ generate_plugin_event(jcr, bEventPluginCommand, (void *)opts);
+ }
+ }
+
LockRes();
CLIENT *client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
UnlockRes();
case STREAM_UNIX_ATTRIBUTES:
case STREAM_UNIX_ATTRIBUTES_EX:
Dmsg0(400, "Stream=Unix Attributes.\n");
+ if (plugin_verify_data_close(jcr) == bRC_Error) {
+ goto bail_out;
+ }
+
if (!vctx.close_previous_stream()) {
goto bail_out;
}
Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), dir->bstrerror());
goto bail_out;
}
+
+ } else if (jcr->is_JobLevel(L_VERIFY_DATA) && attr->type == FT_REG) {
+ if (plugin_verify_data_open(jcr, attr) == bRC_Error) {
+ goto bail_out;
+ }
}
break;
if (!jcr->crypto.digest) {
jcr->crypto.digest = crypto_digest_new(jcr, vctx.digesttype);
}
+ if (plugin_verify_data_close(jcr) == bRC_Error) {
+ goto bail_out;
+ }
vctx.close_previous_stream();
if (strncmp(digest, vctx.digest,
MIN(sizeof(digest), sizeof(vctx.digest))) != 0)
vctx.update_checksum(wbuf, wsize);
+ if (plugin_verify_data_update(jcr, wbuf, wsize) == bRC_Error) {
+ dequeue_messages(jcr);
+ goto bail_out;
+ }
+
if (vctx.stream == STREAM_WIN32_GZIP_DATA
|| vctx.stream == STREAM_WIN32_DATA
|| vctx.stream == STREAM_WIN32_COMPRESSED_DATA
if (bget_ret == BNET_EXT_TERMINATE) {
goto bail_out;
}
+ if (plugin_verify_data_close(jcr) == bRC_Error) {
+ goto bail_out;
+ }
if (!vctx.close_previous_stream()) {
goto bail_out;
}
DedupFiledInterface *dedup; /* help the FD to do deduplication */
bool dedup_use_cache; /* use client cache */
VSSClient *pVSSClient; /* VSS handler */
+ alist *plugin_verify; /* Registered plugins that need a copy of the data in verify job */
+ alist *plugin_options_list; /* list of the options to use in a job */
#endif /* FILE_DAEMON */
*/
#ifdef COMMUNITY
-#define FD_VERSION 14 /* make same as community Linux FD */
+#define FD_VERSION 15 /* make same as community Linux FD */
#else
-#define FD_VERSION 14 /* Enterprise FD version */
+#define FD_VERSION 15 /* Enterprise FD version */
#endif
/*