X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Ffiled%2Ffd_plugins.c;h=066541b2c508ea80ba976ad4753de40cef491480;hb=10cfd798ced2d27f61ead2de6fe9b1bcc8e3468d;hp=22649d6375480e205d38739a2dbe1908ca4ecc4f;hpb=0115d394bbdd185079d4c841d69bc2d69f93ba14;p=bacula%2Fbacula diff --git a/bacula/src/filed/fd_plugins.c b/bacula/src/filed/fd_plugins.c index 22649d6375..066541b2c5 100644 --- a/bacula/src/filed/fd_plugins.c +++ b/bacula/src/filed/fd_plugins.c @@ -1,29 +1,20 @@ /* - Bacula® - The Network Backup Solution - - Copyright (C) 2007-2011 Free Software Foundation Europe e.V. - - The main author of Bacula is Kern Sibbald, with contributions from - many others, a complete list can be found in the file AUTHORS. - This program is Free Software; you can redistribute it and/or - modify it under the terms of version three of the GNU Affero General Public - License as published by the Free Software Foundation, which is - listed in the file LICENSE. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. - - Bacula® is a registered trademark of Kern Sibbald. - The licensor of Bacula is the Free Software Foundation Europe - (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, - Switzerland, email:ftf@fsfeurope.org. + Bacula(R) - The Network Backup Solution + + Copyright (C) 2000-2015 Kern Sibbald + + The original author of Bacula is Kern Sibbald, with contributions + from many others, a complete list can be found in the file AUTHORS. + + You may use this file and others of this release according to the + license defined in the LICENSE file, which includes the Affero General + Public License, v3.0 ("AGPLv3") and some additional permissions and + terms pursuant to its AGPLv3 Section 7. + + This notice must be preserved when any source code is + conveyed and/or propagated. + + Bacula(R) is a registered trademark of Kern Sibbald. */ /** * Main program to test loading and running Bacula plugins. @@ -38,7 +29,6 @@ extern CLIENT *me; extern DLL_IMP_EXP char *exepath; extern DLL_IMP_EXP char *version; extern DLL_IMP_EXP char *dist_name; -extern DLL_IMP_EXP int beef; const int dbglvl = 150; #ifdef HAVE_WIN32 @@ -51,7 +41,7 @@ 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); +extern DLL_IMP_EXP int (*plugin_bopen)(BFILE *bfd, const char *fname, uint64_t flags, mode_t mode); extern DLL_IMP_EXP int (*plugin_bclose)(BFILE *bfd); extern DLL_IMP_EXP ssize_t (*plugin_bread)(BFILE *bfd, void *buf, size_t count); extern DLL_IMP_EXP ssize_t (*plugin_bwrite)(BFILE *bfd, void *buf, size_t count); @@ -80,23 +70,23 @@ static bRC baculaNewPreInclude(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); +static bRC baculaAcceptFile(bpContext *ctx, struct save_pkt *sp); /* * These will be plugged into the global pointer structure for * the findlib. */ -static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode); +static int my_plugin_bopen(BFILE *bfd, const char *fname, uint64_t flags, mode_t mode); static int my_plugin_bclose(BFILE *bfd); static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count); static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count); static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence); -#define for_this_plug(plugin, str, len) (((len) == (plugin)->file_len) && strncmp((plugin)->file, str, len) == 0) /* Bacula info */ static bInfo binfo = { sizeof(bInfo), - FD_PLUGIN_INTERFACE_VERSION + FD_PLUGIN_INTERFACE_VERSION }; /* Bacula entry points */ @@ -118,10 +108,11 @@ static bFuncs bfuncs = { baculaNewOptions, baculaNewInclude, baculaNewPreInclude, - baculaCheckChanges + baculaCheckChanges, + baculaAcceptFile }; -/* +/* * Bacula private context */ struct bacula_ctx { @@ -132,9 +123,34 @@ struct bacula_ctx { findINCEXE *include; /* pointer to include/exclude files */ }; -static bool is_plugin_disabled(bpContext *plugin_ctx) +/* + * Test if event is for this plugin + */ +static bool for_this_plugin(Plugin *plugin, char *name, int len) +{ + Dmsg4(dbglvl, "name=%s len=%d plugin=%s plen=%d\n", name, len, plugin->file, plugin->file_len); + if (!name) { /* if no plugin name, all plugins get it */ + return true; + } + /* Return global VSS job metadata to all plugins */ + if (strcmp("job", name) == 0) { /* old V4.0 name for VSS job metadata */ + return true; + } + if (strcmp("*all*", name) == 0) { /* new v6.0 name for VSS job metadata */ + return true; + } + /* Check if this is the correct plugin */ + if (len == plugin->file_len && strncmp(plugin->file, name, len) == 0) { + return true; + } + return false; +} + + +bool is_plugin_disabled(bpContext *plugin_ctx) { bacula_ctx *b_ctx; + Dsm_check(999); if (!plugin_ctx) { return true; } @@ -145,7 +161,7 @@ static bool is_plugin_disabled(bpContext *plugin_ctx) return b_ctx->disabled; } -static bool is_plugin_disabled(JCR *jcr) +bool is_plugin_disabled(JCR *jcr) { return is_plugin_disabled(jcr->plugin_ctx); } @@ -154,22 +170,22 @@ static bool is_plugin_disabled(JCR *jcr) * Create a plugin event When receiving bEventCancelCommand, this function is * called by an other thread. */ -void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) +void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) { bpContext *plugin_ctx; bEvent event; Plugin *plugin; - int i = 0; char *name = NULL; + int i; int len = 0; bool call_if_canceled = false; restore_object_pkt *rop; - bRC rc; - if (!bplugin_list || !jcr || !jcr->plugin_ctx_list) { + Dsm_check(999); + if (!b_plugin_list || !jcr || !jcr->plugin_ctx_list) { return; /* Return if no plugins loaded */ } - + /* * Some events are sent to only a particular plugin or must be * called even if the job is canceled @@ -196,28 +212,22 @@ void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) break; case bEventEndBackupJob: case bEventEndVerifyJob: - call_if_canceled = true; + call_if_canceled = true; /* plugin *must* see this call */ break; case bEventStartRestoreJob: - foreach_alist(plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { plugin->restoreFileStarted = false; plugin->createFileCalled = false; } break; case bEventEndRestoreJob: - call_if_canceled = true; - if (jcr->plugin && jcr->plugin->restoreFileStarted) { - plug_func(jcr->plugin)->endRestoreFile(jcr->plugin_ctx); - } - if (jcr->plugin) { - jcr->plugin->restoreFileStarted = false; - jcr->plugin->createFileCalled = false; - } + call_if_canceled = true; /* plugin *must* see this call */ break; default: break; } + /* If call_if_canceled is set, we call the plugin anyway */ if (!call_if_canceled && jcr->is_job_canceled()) { return; } @@ -231,19 +241,33 @@ void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) * Pass event to every plugin (except if name is set). If name * is set, we pass it only to the plugin with that name. */ - foreach_alist(plugin, bplugin_list) { - if (name && !for_this_plug(plugin, name, len)) { - i++; + foreach_alist_index(i, plugin, b_plugin_list) { + if (!for_this_plugin(plugin, name, len)) { + Dmsg2(dbglvl, "Not for this plugin name=%s NULL=%d\n", + name, name==NULL?1:0); continue; } - plugin_ctx = &plugin_ctx_list[i++]; + /* + * Note, at this point do not change + * jcr->plugin or jcr->plugin_ctx + */ + Dsm_check(999); + plugin_ctx = &plugin_ctx_list[i]; if (is_plugin_disabled(plugin_ctx)) { + Dmsg1(50, "Plugin %s disabled\n", plugin->file); continue; } - rc = plug_func(plugin)->handlePluginEvent(plugin_ctx, &event, value); - if (rc != bRC_OK) { - break; + if (eventType == bEventEndRestoreJob) { + Dmsg0(50, "eventType==bEventEndRestoreJob\n"); + if (jcr->plugin && jcr->plugin->restoreFileStarted) { + plug_func(jcr->plugin)->endRestoreFile(jcr->plugin_ctx); + } + if (jcr->plugin) { + jcr->plugin->restoreFileStarted = false; + jcr->plugin->createFileCalled = false; + } } + plug_func(plugin)->handlePluginEvent(plugin_ctx, &event, value); } return; } @@ -255,9 +279,10 @@ bool plugin_check_file(JCR *jcr, char *fname) { Plugin *plugin; int rc = bRC_OK; - int i = 0; + int i; - if (!bplugin_list || !jcr || !jcr->plugin_ctx_list || jcr->is_job_canceled()) { + Dsm_check(999); + if (!b_plugin_list || !jcr || !jcr->plugin_ctx_list || jcr->is_job_canceled()) { return false; /* Return if no plugins loaded */ } @@ -266,8 +291,8 @@ bool plugin_check_file(JCR *jcr, char *fname) Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId); /* Pass event to every plugin */ - foreach_alist(plugin, bplugin_list) { - jcr->plugin_ctx = &plugin_ctx_list[i++]; + foreach_alist_index(i, plugin, b_plugin_list) { + jcr->plugin_ctx = &plugin_ctx_list[i]; jcr->plugin = plugin; if (is_plugin_disabled(jcr)) { continue; @@ -281,15 +306,16 @@ bool plugin_check_file(JCR *jcr, char *fname) } } + Dsm_check(999); jcr->plugin = NULL; jcr->plugin_ctx = NULL; return rc == bRC_Seen; } /* Get the first part of the the plugin command - * systemstate:/@SYSTEMSTATE/ + * systemstate:/@SYSTEMSTATE/ * => ret = 11 - * => can use for_this_plug(plug, cmd, ret); + * => can use for_this_plugin(plug, cmd, ret); * * The plugin command can contain only the plugin name * Plugin = alldrives @@ -299,6 +325,7 @@ static bool get_plugin_name(JCR *jcr, char *cmd, int *ret) { char *p; int len; + Dsm_check(999); if (!cmd || (*cmd == '\0')) { return false; } @@ -318,12 +345,15 @@ static bool get_plugin_name(JCR *jcr, char *cmd, int *ret) } } *ret = len; + Dsm_check(999); return true; } static void update_ff_pkt(FF_PKT *ff_pkt, struct save_pkt *sp) { + Dsm_check(999); + ff_pkt->no_read = sp->no_read; ff_pkt->delta_seq = sp->delta_seq; if (sp->flags & FO_DELTA) { ff_pkt->flags |= FO_DELTA; @@ -332,14 +362,27 @@ static void update_ff_pkt(FF_PKT *ff_pkt, struct save_pkt *sp) ff_pkt->flags &= ~FO_DELTA; /* clean delta sequence number */ ff_pkt->delta_seq = 0; } - + if (sp->flags & FO_OFFSETS) { ff_pkt->flags |= FO_OFFSETS; + } else { + ff_pkt->flags &= ~FO_OFFSETS; + } + /* Sparse code doesn't work with plugins + * that use FIFO or STDOUT/IN to communicate + */ + if (sp->flags & FO_SPARSE) { + ff_pkt->flags |= FO_SPARSE; + } else { + ff_pkt->flags &= ~FO_SPARSE; } if (sp->flags & FO_PORTABLE_DATA) { ff_pkt->flags |= FO_PORTABLE_DATA; + } else { + ff_pkt->flags &= ~FO_PORTABLE_DATA; } ff_pkt->flags |= FO_PLUGIN; /* data from plugin */ + Dsm_check(999); } /* Ask to a Option Plugin what to do with the current file */ @@ -347,12 +390,14 @@ bRC plugin_option_handle_file(JCR *jcr, FF_PKT *ff_pkt, struct save_pkt *sp) { Plugin *plugin; bRC ret = bRC_Error; + bool found=false; char *cmd = ff_pkt->plugin; int len; int i=0; bEvent event; event.eventType = bEventHandleBackupFile; + Dsm_check(999); bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list; memset(sp, 0, sizeof(struct save_pkt)); sp->pkt_size = sp->pkt_end = sizeof(struct save_pkt); @@ -363,8 +408,9 @@ bRC plugin_option_handle_file(JCR *jcr, FF_PKT *ff_pkt, struct save_pkt *sp) sp->statp = ff_pkt->statp; sp->fname = ff_pkt->fname; sp->delta_seq = ff_pkt->delta_seq; + sp->accurate_found = ff_pkt->accurate_found; - if (!bplugin_list || !jcr->plugin_ctx_list || jcr->is_job_canceled()) { + if (!b_plugin_list || !jcr->plugin_ctx_list || jcr->is_job_canceled()) { Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd); goto bail_out; /* Return if no plugins loaded */ } @@ -374,37 +420,51 @@ bRC plugin_option_handle_file(JCR *jcr, FF_PKT *ff_pkt, struct save_pkt *sp) } /* Note, we stop the loop on the first plugin that matches the name */ - foreach_alist(plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { Dmsg4(dbglvl, "plugin=%s plen=%d cmd=%s len=%d\n", plugin->file, plugin->file_len, cmd, len); - if (!for_this_plug(plugin, cmd, len)) { - i++; + if (!for_this_plugin(plugin, cmd, len)) { continue; } + found=true; + + Dsm_check(999); if (is_plugin_disabled(&plugin_ctx_list[i])) { goto bail_out; } - - ret = plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], + + jcr->plugin_ctx = &plugin_ctx_list[i]; + jcr->plugin = plugin; + + ret = plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], &event, sp); - + /* TODO: would be better to set this in save_file() */ if (ret == bRC_OK) { jcr->opt_plugin = true; jcr->plugin = plugin; jcr->plugin_sp = sp; /* Unset sp in save_file */ - jcr->plugin_ctx = &plugin_ctx_list[i++]; + jcr->plugin_ctx = &plugin_ctx_list[i]; update_ff_pkt(ff_pkt, sp); + + /* reset plugin in JCR if not used this time */ + } else { + jcr->plugin_ctx = NULL; + jcr->plugin = NULL; } goto bail_out; } /* end foreach loop */ bail_out: + if (!found) { + Jmsg1(jcr, M_FATAL, 0, "Options plugin \"%s\" not found.\n", cmd); + } + Dsm_check(999); return ret; } -/** +/** * Sequence of calls for a backup: * 1. plugin_save() here is called with ff_pkt * 2. we find the plugin requested on the command string @@ -422,15 +482,16 @@ bail_out: int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) { Plugin *plugin; - int i = 0; int len; + int i; char *cmd = ff_pkt->top_fname; struct save_pkt sp; bEvent event; POOL_MEM fname(PM_FNAME); POOL_MEM link(PM_FNAME); - if (!bplugin_list || !jcr->plugin_ctx_list || jcr->is_job_canceled()) { + Dsm_check(999); + if (!b_plugin_list || !jcr->plugin_ctx_list || jcr->is_job_canceled()) { Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd); return 1; /* Return if no plugins loaded */ } @@ -444,17 +505,17 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) } /* Note, we stop the loop on the first plugin that matches the name */ - foreach_alist(plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { Dmsg4(dbglvl, "plugin=%s plen=%d cmd=%s len=%d\n", plugin->file, plugin->file_len, cmd, len); - if (!for_this_plug(plugin, cmd, len)) { - i++; + if (!for_this_plugin(plugin, cmd, len)) { continue; } - /* + /* * We put the current plugin pointer, and the plugin context * into the jcr, because during save_file(), the plugin * will be called many times and these values are needed. */ + Dsm_check(999); jcr->plugin_ctx = &plugin_ctx_list[i]; jcr->plugin = plugin; if (is_plugin_disabled(jcr)) { @@ -467,15 +528,17 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) goto bail_out; } /* Loop getting filenames to backup then saving them */ - while (!jcr->is_job_canceled()) { + while (!jcr->is_job_canceled()) { memset(&sp, 0, sizeof(sp)); sp.pkt_size = sizeof(sp); sp.pkt_end = sizeof(sp); sp.portable = true; + sp.no_read = false; 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); + Dsm_check(999); /* Get the file save parameters. I.e. the stat pkt ... */ if (plug_func(plugin)->startBackupFile(jcr->plugin_ctx, &sp) != bRC_OK) { goto bail_out; @@ -488,7 +551,7 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) jcr->plugin_sp = &sp; ff_pkt = jcr->ff; /* - * Copy fname and link because save_file() zaps them. This + * Copy fname and link because save_file() zaps them. This * avoids zaping the plugin's strings. */ ff_pkt->type = sp.type; @@ -505,6 +568,7 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) ff_pkt->object = sp.object; ff_pkt->object_len = sp.object_len; } else { + Dsm_check(999); if (!sp.fname) { Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no fname in startBackupFile packet.\n"), cmd); @@ -523,13 +587,14 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) Dmsg2(dbglvl, "startBackup returned type=%d, fname=%s\n", sp.type, sp.fname); if (sp.object) { Dmsg2(dbglvl, "index=%d object=%s\n", sp.index, sp.object); - } + } /* Call Bacula core code to backup the plugin's file */ save_file(jcr, ff_pkt, true); bRC rc = plug_func(plugin)->endBackupFile(jcr->plugin_ctx); if (rc == bRC_More || rc == bRC_OK) { accurate_mark_file_as_seen(jcr, fname.c_str()); } + Dsm_check(999); if (rc == bRC_More) { continue; } @@ -540,6 +605,7 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" not found.\n", cmd); bail_out: + Dsm_check(999); jcr->cmd_plugin = false; jcr->plugin = NULL; jcr->plugin_ctx = NULL; @@ -547,7 +613,7 @@ bail_out: } -/** +/** * Sequence of calls for a estimate: * 1. plugin_estimate() here is called with ff_pkt * 2. we find the plugin requested on the command string @@ -560,8 +626,8 @@ bail_out: int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level) { Plugin *plugin; - int i = 0; int len; + int i; char *cmd = ff_pkt->top_fname; struct save_pkt sp; bEvent event; @@ -569,7 +635,8 @@ int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level) POOL_MEM link(PM_FNAME); ATTR attr; - if (!bplugin_list || !jcr->plugin_ctx_list) { + Dsm_check(999); + if (!b_plugin_list || !jcr->plugin_ctx_list) { Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd); return 1; /* Return if no plugins loaded */ } @@ -583,17 +650,17 @@ int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level) } /* Note, we stop the loop on the first plugin that matches the name */ - foreach_alist(plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { Dmsg4(dbglvl, "plugin=%s plen=%d cmd=%s len=%d\n", plugin->file, plugin->file_len, cmd, len); - if (!for_this_plug(plugin, cmd, len)) { - i++; + if (!for_this_plugin(plugin, cmd, len)) { continue; } - /* + /* * We put the current plugin pointer, and the plugin context * into the jcr, because during save_file(), the plugin * will be called many times and these values are needed. */ + Dsm_check(999); jcr->plugin_ctx = &plugin_ctx_list[i]; jcr->plugin = plugin; if (is_plugin_disabled(jcr)) { @@ -606,7 +673,8 @@ int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level) goto bail_out; } /* Loop getting filenames to backup then saving them */ - while (!jcr->is_job_canceled()) { + while (!jcr->is_job_canceled()) { + Dsm_check(999); memset(&sp, 0, sizeof(sp)); sp.pkt_size = sizeof(sp); sp.pkt_end = sizeof(sp); @@ -632,8 +700,22 @@ int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level) goto bail_out; } + /* Count only files backed up */ + switch (sp.type) { + case FT_REGE: + case FT_REG: + case FT_LNK: + case FT_DIREND: + case FT_SPEC: + case FT_RAW: + case FT_FIFO: + case FT_LNKSAVED: + jcr->JobFiles++; /* increment number of files backed up */ + break; + default: + break; + } jcr->num_files_examined++; - jcr->JobFiles++; /* increment number of files seen */ if (sp.type != FT_LNKSAVED && S_ISREG(sp.statp.st_mode)) { if (sp.statp.st_size > 0) { @@ -658,6 +740,7 @@ int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level) if (rc == bRC_More || rc == bRC_OK) { accurate_mark_file_as_seen(jcr, sp.fname); } + Dsm_check(999); if (rc == bRC_More) { continue; } @@ -668,6 +751,7 @@ int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level) Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" not found.\n", cmd); bail_out: + Dsm_check(999); jcr->cmd_plugin = false; jcr->plugin = NULL; jcr->plugin_ctx = NULL; @@ -683,6 +767,7 @@ bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start) int index = jcr->JobFiles; struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp; + Dsm_check(999); if (!sp) { Jmsg0(jcr, M_FATAL, 0, _("Plugin save packet not found.\n")); return false; @@ -690,19 +775,21 @@ bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start) if (jcr->is_job_canceled()) { return false; } - + if (start) { index++; /* JobFiles not incremented yet */ } Dmsg1(dbglvl, "send_plugin_name=%s\n", sp->cmd); /* Send stream header */ + Dsm_check(999); if (!sd->fsend("%ld %d 0", index, STREAM_PLUGIN_NAME)) { Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror()); return false; } - Dmsg1(50, "send plugin name hdr: %s\n", sd->msg); + Dmsg1(dbglvl, "send plugin name hdr: %s\n", sd->msg); + Dsm_check(999); if (start) { /* Send data -- not much */ stat = sd->fsend("%ld 1 %d %s%c", index, sp->portable, sp->cmd, 0); @@ -710,6 +797,7 @@ bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start) /* Send end of data */ stat = sd->fsend("%ld 0", jcr->JobFiles); } + Dsm_check(999); if (!stat) { Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror()); @@ -717,6 +805,7 @@ bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start) } Dmsg1(dbglvl, "send plugin start/end: %s\n", sd->msg); sd->signal(BNET_EOD); /* indicate end of plugin name data */ + Dsm_check(999); return true; } @@ -727,16 +816,17 @@ bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start) * Returns: true if start of stream * false if end of steam */ -bool plugin_name_stream(JCR *jcr, char *name) +bool plugin_name_stream(JCR *jcr, char *name) { char *p = name; char *cmd; bool start; Plugin *plugin; int len; - int i = 0; + int i; bpContext *plugin_ctx_list = jcr->plugin_ctx_list; + Dsm_check(999); Dmsg1(dbglvl, "Read plugin stream string=%s\n", name); skip_nonspaces(&p); /* skip over jcr->JobFiles */ skip_spaces(&p); @@ -751,7 +841,7 @@ bool plugin_name_stream(JCR *jcr, char *name) cmd = p; } else { /* - * End of plugin data, notify plugin, then clear flags + * 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 && jcr->plugin->restoreFileStarted) { @@ -765,10 +855,11 @@ bool plugin_name_stream(JCR *jcr, char *name) jcr->plugin = NULL; goto bail_out; } + Dsm_check(999); if (!plugin_ctx_list) { goto bail_out; } - + /* * After this point, we are dealing with a restore start */ @@ -777,39 +868,52 @@ bool plugin_name_stream(JCR *jcr, char *name) } /* - * Search for correct plugin as specified on the command + * Search for correct plugin as specified on the command */ - foreach_alist(plugin, bplugin_list) { + Dsm_check(999); + foreach_alist_index(i, plugin, b_plugin_list) { bEvent event; Dmsg3(dbglvl, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len); - if (!for_this_plug(plugin, cmd, len)) { - i++; + if (!for_this_plugin(plugin, cmd, len)) { continue; } + Dsm_check(999); jcr->plugin_ctx = &plugin_ctx_list[i]; jcr->plugin = plugin; if (is_plugin_disabled(jcr)) { + Dmsg1(dbglvl, "Plugin %s disabled\n", cmd); goto bail_out; } - Dmsg1(000, "Restore Command plugin = %s\n", cmd); - event.eventType = bEventRestoreCommand; - if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx, + Dmsg1(dbglvl, "Restore Command plugin = %s\n", cmd); + event.eventType = bEventRestoreCommand; + if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx, &event, cmd) != bRC_OK) { + Dmsg1(dbglvl, "Handle event failed. Plugin=%s\n", cmd); goto bail_out; } if (plugin->restoreFileStarted) { - Jmsg2(jcr, M_FATAL, 0, "Unbalanced call to startRestoreFile. plugin=%s cmd=%s\n", plugin->file, cmd); + Jmsg2(jcr, M_FATAL, 0, "Second call to startRestoreFile. plugin=%s cmd=%s\n", plugin->file, cmd); plugin->restoreFileStarted = false; goto bail_out; } if (plug_func(plugin)->startRestoreFile(jcr->plugin_ctx, cmd) == bRC_OK) { plugin->restoreFileStarted = true; + goto ok_out; + } else { + Dmsg1(dbglvl, "startRestoreFile failed. plugin=%s\n", cmd); } goto bail_out; } Jmsg1(jcr, M_WARNING, 0, _("Plugin=%s not found.\n"), cmd); + goto bail_out; + +ok_out: + return start; bail_out: + Dsm_check(999); + jcr->plugin = NULL; + jcr->plugin_ctx = NULL; return start; } @@ -831,7 +935,8 @@ int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) int flags; int rc; - if (!plugin || !plugin_ctx || !set_cmd_plugin(bfd, jcr) || jcr->is_job_canceled()) { + Dsm_check(999); + if (!plugin || !plugin_ctx || jcr->is_job_canceled()) { return CF_ERROR; } @@ -852,13 +957,15 @@ int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) 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", + 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) { Dmsg1(dbglvl, "attrEx=\"%s\"\n", rp.attrEx); } + Dsm_check(999); if (!plugin->restoreFileStarted || plugin->createFileCalled) { - Jmsg0(jcr, M_FATAL, 0, "Unbalanced call to createFile\n"); + Jmsg2(jcr, M_FATAL, 0, "Unbalanced call to createFile=%d %d\n", + plugin->createFileCalled, plugin->restoreFileStarted); plugin->createFileCalled = false; return CF_ERROR; } @@ -868,26 +975,34 @@ int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) rc, attr->ofname); return CF_ERROR; } - if (rp.create_status == CF_CORE) { - return CF_CORE; /* Let Bacula core handle the file creation */ - } - 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); return CF_ERROR; } + + if (rp.create_status == CF_SKIP) { + return CF_SKIP; + } + + if (rp.create_status == CF_CORE) { + return CF_CORE; /* Let Bacula core handle the file creation */ + } + + /* Use the bfile for plugin */ + set_cmd_plugin(bfd, jcr); + /* Created link or directory? */ if (rp.create_status == CF_CREATED) { return rp.create_status; /* yes, no need to bopen */ } + Dsm_check(999); + flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY; Dmsg0(dbglvl, "call bopen\n"); int stat = bopen(bfd, attr->ofname, flags, S_IRUSR | S_IWUSR); - Dmsg1(50, "bopen status=%d\n", stat); + Dmsg1(dbglvl, "bopen status=%d\n", stat); if (stat < 0) { berrno be; be.set_errno(bfd->berrno); @@ -900,6 +1015,7 @@ int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) if (!is_bopen(bfd)) { Dmsg0(000, "===== BFD is not open!!!!\n"); } + Dsm_check(999); return CF_EXTRACT; } @@ -911,11 +1027,245 @@ int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) */ bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) { + Plugin *plugin = (Plugin *)jcr->plugin; + struct restore_pkt rp; + Dmsg0(dbglvl, "plugin_set_attributes\n"); - if (is_bopen(ofd)) { - bclose(ofd); + + if (!plugin || !jcr->plugin_ctx) { + return false; + } + + memset(&rp, 0, sizeof(rp)); + rp.pkt_size = sizeof(rp); + rp.pkt_end = sizeof(rp); + 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; + + plug_func(plugin)->setFileAttributes(jcr->plugin_ctx, &rp); + + if (rp.create_status == CF_CORE) { + set_attributes(jcr, attr, ofd); + } else { + if (is_bopen(ofd)) { + bclose(ofd); + } + pm_strcpy(attr->ofname, "*none*"); } - pm_strcpy(attr->ofname, "*none*"); + + Dsm_check(999); + return true; +} + +/* + * The Plugin ACL data backup. We are using a new Plugin callback: + * handleXACLdata() for that. The new callback get a pointer to + * struct xacl_pkt as a main argument which consist of the following + * data: + * xacl.func - could be the one of BACL_BACKUP, BACL_RESTORE, + * BXATTR_BACKUP, BXATTR_RESTORE + * xacl.count - the length of data at the content buffer + * xacl.content - the buffer itself + * The buffer (xacl.content) is supplied by Bacula during restore and has to + * be supplied by a Plugin during backup. + * The new callback should return bRC_OK on success and bRC_Error on + * any error. + * + * in: + * jcr - Job Control Record + * ff_pkt - file save packet + * data is a pointer to variable returned + * out: + * data - the pointer to data buffer returned from plugin + * 0 - Success, no more data to save + * > 0 - Success and the number of bytes returned in **data buffer + * -1 - Error, no acls data to backup + */ +int plugin_backup_acl(JCR *jcr, FF_PKT *ff_pkt, char **data) +{ + struct xacl_pkt xacl; + Plugin *plugin = (Plugin *)jcr->plugin; + bRC rc; + + Dmsg0(dbglvl, "plugin_backup_acl\n"); + + /* check of input variables */ + if (!plugin || !jcr->plugin_ctx || !data) { + return 0; + } + + /* prepare the xacl packet */ + memset(&xacl, 0, sizeof(xacl)); + xacl.pkt_size = sizeof(xacl); + xacl.pkt_end = sizeof(xacl); + xacl.func = BACL_BACKUP; + + rc = plug_func(plugin)->handleXACLdata(jcr->plugin_ctx, &xacl); + + /* check out status */ + if (rc != bRC_OK){ + Dmsg0(dbglvl, "plugin->handleXACLdata returned error\n"); + return -1; + } + if (xacl.count > 0){ + /* we have something to save, so prepare return data */ + *data = xacl.content; + return xacl.count; + } + + return 0; +} + +/* + * Called here when Bacula got ACL stream to restore but not every stream but + * a specific one: STREAM_XACL_PLUGIN_ACL which means a plugin has to + * be called. + * + * in: + * jcr - Job Control Record + * data - content to restore + * length - the length of the content to restore + * out: + * true - when successful + * false - on any Error + */ +bool plugin_restore_acl(JCR *jcr, char *data, uint32_t length) +{ + struct xacl_pkt xacl; + Plugin *plugin = (Plugin *)jcr->plugin; + bRC rc; + + Dmsg0(dbglvl, "plugin_restore_acl\n"); + + /* check of input variables */ + if (!plugin || !jcr->plugin_ctx || !data || length == 0) { + return true; + } + + /* prepare the xacl packet */ + memset(&xacl, 0, sizeof(xacl)); + xacl.pkt_size = sizeof(xacl); + xacl.pkt_end = sizeof(xacl); + xacl.func = BACL_RESTORE; + xacl.content = data; + xacl.count = length; + + rc = plug_func(plugin)->handleXACLdata(jcr->plugin_ctx, &xacl); + + /* check out status */ + if (rc != bRC_OK){ + Dmsg0(dbglvl, "plugin->handleXACLdata returned error\n"); + return false; + } + + return true; +} + +/* + * The Plugin XATTR data backup. We are using a new Plugin callback: + * handleXACLdata() for that. Check plugin_backup_acl for new callback + * description. + * + * in: + * jcr - Job Control Record + * ff_pkt - file save packet + * data is a pointer to variable returned + * out: + * data - the pointer to data buffer returned from plugin + * 0 - Success, no more data to save + * >0 - Success and the number of bytes returned in **data buffer + * <0 - Error + */ +int plugin_backup_xattr(JCR *jcr, FF_PKT *ff_pkt, char **data) +{ + + struct xacl_pkt xacl; + Plugin *plugin = (Plugin *)jcr->plugin; + bRC rc; + + Dmsg0(dbglvl, "plugin_backup_xattr\n"); + + /* check of input variables */ + if (!plugin || !jcr->plugin_ctx || !data) { + return 0; + } + + /* prepare the xacl packet */ + memset(&xacl, 0, sizeof(xacl)); + xacl.pkt_size = sizeof(xacl); + xacl.pkt_end = sizeof(xacl); + xacl.func = BXATTR_BACKUP; + + rc = plug_func(plugin)->handleXACLdata(jcr->plugin_ctx, &xacl); + + /* check out status */ + if (rc != bRC_OK){ + Dmsg0(dbglvl, "plugin->handleXACLdata returned error\n"); + return -1; + } + if (xacl.count > 0){ + /* we have something to save, so prepare return data */ + *data = xacl.content; + return xacl.count; + } + + return 0; +} + +/* + * Called here when Bacula got XATTR stream to restore but not every stream but + * a specific one: STREAM_XACL_PLUGIN_XATTR which means a plugin has to + * be called. + * + * in: + * jcr - Job Control Record + * data - content to restore + * length - the length of the content to restore + * out: + * true - when successful + * false - on any Error + */ +bool plugin_restore_xattr(JCR *jcr, char *data, uint32_t length) +{ + struct xacl_pkt xacl; + Plugin *plugin = (Plugin *)jcr->plugin; + bRC rc; + + Dmsg0(dbglvl, "plugin_restore_xattr\n"); + + /* check of input variables */ + if (!plugin || !jcr->plugin_ctx || !data || length == 0) { + return true; + } + + /* prepare the xacl packet */ + memset(&xacl, 0, sizeof(xacl)); + xacl.pkt_size = sizeof(xacl); + xacl.pkt_end = sizeof(xacl); + xacl.func = BXATTR_RESTORE; + xacl.content = data; + xacl.count = length; + + rc = plug_func(plugin)->handleXACLdata(jcr->plugin_ctx, &xacl); + + /* check out status */ + if (rc != bRC_OK){ + Dmsg0(dbglvl, "plugin->handleXACLdata returned error\n"); + return false; + } + return true; } @@ -944,19 +1294,21 @@ void dump_fd_plugin(Plugin *plugin, FILE *fp) void load_fd_plugins(const char *plugin_dir) { Plugin *plugin; + int i; if (!plugin_dir) { Dmsg0(dbglvl, "plugin dir is NULL\n"); return; } - bplugin_list = New(alist(10, not_owned_by_alist)); + b_plugin_list = New(alist(10, not_owned_by_alist)); + Dsm_check(999); if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type, is_plugin_compatible)) { /* Either none found, or some error */ - if (bplugin_list->size() == 0) { - delete bplugin_list; - bplugin_list = NULL; + if (b_plugin_list->size() == 0) { + delete b_plugin_list; + b_plugin_list = NULL; Dmsg0(dbglvl, "No plugins loaded\n"); return; } @@ -968,17 +1320,19 @@ void load_fd_plugins(const char *plugin_dir) plugin_bread = my_plugin_bread; plugin_bwrite = my_plugin_bwrite; plugin_blseek = my_plugin_blseek; + Dsm_check(999); - /* + /* * Verify that the plugin is acceptable, and print information * about it. */ - foreach_alist(plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file); Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file); } dbg_plugin_add_hook(dump_fd_plugin); + Dsm_check(999); } /** @@ -988,8 +1342,9 @@ void load_fd_plugins(const char *plugin_dir) static bool is_plugin_compatible(Plugin *plugin) { pInfo *info = (pInfo *)plugin->pinfo; - Dmsg0(50, "is_plugin_compatible called\n"); - if (debug_level >= 50) { + Dmsg0(dbglvl, "is_plugin_compatible called\n"); + Dsm_check(999); + if (chk_dbglvl(50)) { dump_fd_plugin(plugin, stdin); } if (strcmp(info->plugin_magic, FD_PLUGIN_MAGIC) != 0) { @@ -1008,7 +1363,8 @@ static bool is_plugin_compatible(Plugin *plugin) return false; } if (strcmp(info->plugin_license, "Bacula AGPLv3") != 0 && - strcmp(info->plugin_license, "AGPLv3") != 0) { + strcmp(info->plugin_license, "AGPLv3") != 0 && + strcmp(info->plugin_license, "Bacula Systems(R) SA") != 0) { Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"), plugin->file, info->plugin_license); Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n", @@ -1021,22 +1377,24 @@ static bool is_plugin_compatible(Plugin *plugin) plugin->file, sizeof(pInfo), info->size); return false; } - + + Dsm_check(999); return true; } /** * Create a new instance of each plugin for this Job - * Note, bplugin_list can exist but jcr->plugin_ctx_list can + * Note, b_plugin_list can exist but jcr->plugin_ctx_list can * be NULL if no plugins were loaded. */ void new_plugins(JCR *jcr) { Plugin *plugin; - int i = 0; + int i; - if (!bplugin_list) { + Dsm_check(999); + if (!b_plugin_list) { Dmsg0(dbglvl, "plugin list is NULL\n"); return; } @@ -1044,7 +1402,7 @@ void new_plugins(JCR *jcr) return; } - int num = bplugin_list->size(); + int num = b_plugin_list->size(); if (num == 0) { Dmsg0(dbglvl, "No plugins loaded\n"); @@ -1055,17 +1413,24 @@ void new_plugins(JCR *jcr) bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list; Dmsg2(dbglvl, "Instantiate plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId); - foreach_alist(plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { + Dsm_check(999); /* Start a new instance of each plugin */ bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx)); memset(b_ctx, 0, sizeof(bacula_ctx)); b_ctx->jcr = jcr; 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) { + if (plug_func(plugin)->newPlugin(&plugin_ctx_list[i]) != bRC_OK) { + Dmsg1(000, "Plugin %s will be disabled\n", plugin->file); b_ctx->disabled = true; } } + if (i > num) { + Jmsg2(jcr, M_ABORT, 0, "Num plugins=%d exceeds list size=%d\n", + i, num); + } + Dsm_check(999); } /** @@ -1074,30 +1439,34 @@ void new_plugins(JCR *jcr) void free_plugins(JCR *jcr) { Plugin *plugin; - int i = 0; + int i; - if (!bplugin_list || !jcr->plugin_ctx_list) { + if (!b_plugin_list || !jcr->plugin_ctx_list) { return; /* no plugins, nothing to do */ } + Dsm_check(999); bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list; Dmsg2(dbglvl, "Free instance plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId); - foreach_alist(plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { /* Free the plugin instance */ plug_func(plugin)->freePlugin(&plugin_ctx_list[i]); - free(plugin_ctx_list[i++].bContext); /* free Bacula private context */ + free(plugin_ctx_list[i].bContext); /* free Bacula private context */ + Dsm_check(999); } + Dsm_check(999); free(plugin_ctx_list); jcr->plugin_ctx_list = NULL; } -static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode) +static int my_plugin_bopen(BFILE *bfd, const char *fname, uint64_t flags, mode_t mode) { JCR *jcr = bfd->jcr; Plugin *plugin = (Plugin *)jcr->plugin; struct io_pkt io; Dmsg1(dbglvl, "plugin_bopen flags=%x\n", flags); + Dsm_check(999); if (!plugin || !jcr->plugin_ctx) { return 0; } @@ -1111,6 +1480,7 @@ static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode io.mode = mode; io.win32 = false; io.lerror = 0; + io.status = -1; plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io); bfd->berrno = io.io_errno; if (io.win32) { @@ -1119,7 +1489,8 @@ static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode errno = io.io_errno; bfd->lerror = io.lerror; } - Dmsg1(50, "Return from plugin open status=%d\n", io.status); + Dmsg1(dbglvl, "Return from plugin open status=%d\n", io.status); + Dsm_check(999); return io.status; } @@ -1129,6 +1500,7 @@ static int my_plugin_bclose(BFILE *bfd) Plugin *plugin = (Plugin *)jcr->plugin; struct io_pkt io; + Dsm_check(999); Dmsg0(dbglvl, "===== plugin_bclose\n"); if (!plugin || !jcr->plugin_ctx) { return 0; @@ -1140,6 +1512,7 @@ static int my_plugin_bclose(BFILE *bfd) io.buf = NULL; io.win32 = false; io.lerror = 0; + io.status = -1; plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io); bfd->berrno = io.io_errno; if (io.win32) { @@ -1149,6 +1522,7 @@ static int my_plugin_bclose(BFILE *bfd) bfd->lerror = io.lerror; } Dmsg1(dbglvl, "plugin_bclose stat=%d\n", io.status); + Dsm_check(999); return io.status; } @@ -1158,6 +1532,7 @@ static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count) Plugin *plugin = (Plugin *)jcr->plugin; struct io_pkt io; + Dsm_check(999); Dmsg0(dbglvl, "plugin_bread\n"); if (!plugin || !jcr->plugin_ctx) { return 0; @@ -1170,6 +1545,7 @@ static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count) io.win32 = false; io.offset = 0; io.lerror = 0; + io.status = -1; plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io); bfd->offset = io.offset; bfd->berrno = io.io_errno; @@ -1179,6 +1555,7 @@ static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count) errno = io.io_errno; bfd->lerror = io.lerror; } + Dsm_check(999); return (ssize_t)io.status; } @@ -1188,8 +1565,10 @@ static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count) Plugin *plugin = (Plugin *)jcr->plugin; struct io_pkt io; + Dsm_check(999); Dmsg0(dbglvl, "plugin_bwrite\n"); if (!plugin || !jcr->plugin_ctx) { + Dmsg0(0, "No plugin context\n"); return 0; } io.pkt_size = sizeof(io); @@ -1199,6 +1578,7 @@ static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count) io.buf = (char *)buf; io.win32 = false; io.lerror = 0; + io.status = -1; plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io); bfd->berrno = io.io_errno; if (io.win32) { @@ -1207,6 +1587,7 @@ static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count) errno = io.io_errno; bfd->lerror = io.lerror; } + Dsm_check(999); return (ssize_t)io.status; } @@ -1216,6 +1597,7 @@ static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence) Plugin *plugin = (Plugin *)jcr->plugin; struct io_pkt io; + Dsm_check(999); Dmsg0(dbglvl, "plugin_bseek\n"); if (!plugin || !jcr->plugin_ctx) { return 0; @@ -1235,6 +1617,7 @@ static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence) errno = io.io_errno; bfd->lerror = io.lerror; } + Dsm_check(999); return (boffset_t)io.offset; } @@ -1251,6 +1634,7 @@ static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value) return bRC_Error; } + Dsm_check(999); switch (var) { /* General variables, no need of ctx */ case bVarFDName: *((char **)value) = my_name; @@ -1267,8 +1651,11 @@ static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value) case bVarDistName: *(char **)value = dist_name; break; - case bVarBEEF: - *((int *)value) = beef; + case bVarPrevJobName: + break; + case bVarPrefixLinks: + break; + case bVarxxx: break; default: break; @@ -1304,6 +1691,10 @@ static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value) *((char **)value) = jcr->Job; Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job); break; + case bVarPrevJobName: + *((char **)value) = jcr->PrevJob; + Dmsg1(dbglvl, "Bacula: return Previous Job name=%s\n", jcr->PrevJob); + break; case bVarJobStatus: *((int *)value) = jcr->JobStatus; Dmsg1(dbglvl, "Bacula: return bVarJobStatus=%d\n", jcr->JobStatus); @@ -1316,22 +1707,26 @@ static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value) *((int *)value) = (int)jcr->accurate; Dmsg1(dbglvl, "Bacula: return accurate=%d\n", (int)jcr->accurate); break; + case bVarInteractiveSession: + *(int *)value = (int)jcr->interactive_session; + break; + case bVarFileIndex: + *(int *)value = (int)jcr->JobFiles; + break; case bVarFileSeen: break; /* a write only variable, ignore read request */ case bVarVssObject: #ifdef HAVE_WIN32 - if (g_pVSSClient) { - *(void **)value = g_pVSSClient->GetVssObject(); + if (jcr->pVSSClient) { + *(void **)value = jcr->pVSSClient->GetVssObject(); break; } #endif return bRC_Error; case bVarVssDllHandle: #ifdef HAVE_WIN32 - if (g_pVSSClient) { - *(void **)value = g_pVSSClient->GetVssDllHandle(); - break; - } + *(void **)value = vsslib; + break; #endif return bRC_Error; case bVarWhere: @@ -1340,21 +1735,29 @@ static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value) case bVarRegexWhere: *(char **)value = jcr->RegexWhere; break; - + case bVarPrefixLinks: + *(int *)value = (int)jcr->prefix_links; + break; + case bVarReplace: + *((int*)value) = jcr->replace; + Dmsg1(dbglvl, "Bacula: return replace=%c\n", jcr->replace); + break; case bVarFDName: /* get warning with g++ if we missed one */ case bVarWorkingDir: case bVarExePath: case bVarVersion: case bVarDistName: - case bVarBEEF: + case bVarxxx: break; } + Dsm_check(999); return bRC_OK; } static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value) { JCR *jcr; + Dsm_check(999); if (!value || !ctx) { return bRC_Error; } @@ -1363,16 +1766,20 @@ static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value) if (!jcr) { return bRC_Error; } -// Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr); +// Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr); switch (var) { case bVarFileSeen: if (!accurate_mark_file_as_seen(jcr, (char *)value)) { return bRC_Error; - } + } + break; + case bVarInteractiveSession: + jcr->interactive_session = (((intptr_t) value) == 1); break; default: break; } + Dsm_check(999); return bRC_OK; } @@ -1381,6 +1788,7 @@ static bRC baculaRegisterEvents(bpContext *ctx, ...) va_list args; uint32_t event; + Dsm_check(999); if (!ctx) { return bRC_Error; } @@ -1390,6 +1798,7 @@ static bRC baculaRegisterEvents(bpContext *ctx, ...) Dmsg1(dbglvl, "Plugin wants event=%u\n", event); } va_end(args); + Dsm_check(999); return bRC_OK; } @@ -1400,6 +1809,7 @@ static bRC baculaJobMsg(bpContext *ctx, const char *file, int line, char buf[2000]; JCR *jcr; + Dsm_check(999); if (ctx) { jcr = ((bacula_ctx *)ctx->bContext)->jcr; } else { @@ -1410,6 +1820,7 @@ static bRC baculaJobMsg(bpContext *ctx, const char *file, int line, bvsnprintf(buf, sizeof(buf), fmt, arg_ptr); va_end(arg_ptr); Jmsg(jcr, type, mtime, "%s", buf); + Dsm_check(999); return bRC_OK; } @@ -1419,10 +1830,12 @@ static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line, va_list arg_ptr; char buf[2000]; + Dsm_check(999); va_start(arg_ptr, fmt); bvsnprintf(buf, sizeof(buf), fmt, arg_ptr); va_end(arg_ptr); d_msg(file, line, level, "%s", buf); + Dsm_check(999); return bRC_OK; } @@ -1447,6 +1860,7 @@ static void baculaFree(bpContext *ctx, const char *file, int line, void *mem) static bool is_ctx_good(bpContext *ctx, JCR *&jcr, bacula_ctx *&bctx) { + Dsm_check(999); if (!ctx) { return false; } @@ -1468,20 +1882,38 @@ static bool is_ctx_good(bpContext *ctx, JCR *&jcr, bacula_ctx *&bctx) static bRC baculaAddExclude(bpContext *ctx, const char *file) { JCR *jcr; + findINCEXE *old; bacula_ctx *bctx; + Dsm_check(999); if (!is_ctx_good(ctx, jcr, bctx)) { return bRC_Error; } if (!file) { return bRC_Error; } - if (!bctx->exclude) { + + /* Save the include context */ + old = get_incexe(jcr); + + /* Not right time to add exlude */ + if (!old) { + return bRC_Error; + } + + if (!bctx->exclude) { bctx->exclude = new_exclude(jcr); - new_options(jcr, bctx->exclude); } + + /* Set the Exclude context */ set_incexe(jcr, bctx->exclude); + add_file_to_fileset(jcr, file, true); + + /* Restore the current context */ + set_incexe(jcr, old); + Dmsg1(100, "Add exclude file=%s\n", file); + Dsm_check(999); return bRC_OK; } @@ -1492,23 +1924,36 @@ static bRC baculaAddExclude(bpContext *ctx, const char *file) static bRC baculaAddInclude(bpContext *ctx, const char *file) { JCR *jcr; + findINCEXE *old; bacula_ctx *bctx; + + Dsm_check(999); if (!is_ctx_good(ctx, jcr, bctx)) { return bRC_Error; } if (!file) { return bRC_Error; } + + /* Save the include context */ + old = get_incexe(jcr); + /* Not right time to add include */ - if (!(jcr->ff && jcr->ff->fileset && jcr->ff->fileset->incexe)) { + if (!old) { return bRC_Error; } if (!bctx->include) { - bctx->include = jcr->ff->fileset->incexe; + bctx->include = old; } + set_incexe(jcr, bctx->include); add_file_to_fileset(jcr, file, true); + + /* Restore the current context */ + set_incexe(jcr, old); + Dmsg1(100, "Add include file=%s\n", file); + Dsm_check(999); return bRC_OK; } @@ -1516,6 +1961,7 @@ static bRC baculaAddOptions(bpContext *ctx, const char *opts) { JCR *jcr; bacula_ctx *bctx; + Dsm_check(999); if (!is_ctx_good(ctx, jcr, bctx)) { return bRC_Error; } @@ -1523,6 +1969,7 @@ static bRC baculaAddOptions(bpContext *ctx, const char *opts) return bRC_Error; } add_options_to_fileset(jcr, opts); + Dsm_check(999); Dmsg1(1000, "Add options=%s\n", opts); return bRC_OK; } @@ -1531,6 +1978,7 @@ static bRC baculaAddRegex(bpContext *ctx, const char *item, int type) { JCR *jcr; bacula_ctx *bctx; + Dsm_check(999); if (!is_ctx_good(ctx, jcr, bctx)) { return bRC_Error; } @@ -1539,6 +1987,7 @@ static bRC baculaAddRegex(bpContext *ctx, const char *item, int type) } add_regex_to_fileset(jcr, item, type); Dmsg1(100, "Add regex=%s\n", item); + Dsm_check(999); return bRC_OK; } @@ -1546,6 +1995,7 @@ static bRC baculaAddWild(bpContext *ctx, const char *item, int type) { JCR *jcr; bacula_ctx *bctx; + Dsm_check(999); if (!is_ctx_good(ctx, jcr, bctx)) { return bRC_Error; } @@ -1554,6 +2004,7 @@ static bRC baculaAddWild(bpContext *ctx, const char *item, int type) } add_wild_to_fileset(jcr, item, type); Dmsg1(100, "Add wild=%s\n", item); + Dsm_check(999); return bRC_OK; } @@ -1561,10 +2012,12 @@ static bRC baculaNewOptions(bpContext *ctx) { JCR *jcr; bacula_ctx *bctx; + Dsm_check(999); if (!is_ctx_good(ctx, jcr, bctx)) { return bRC_Error; } (void)new_options(jcr, NULL); + Dsm_check(999); return bRC_OK; } @@ -1572,10 +2025,12 @@ static bRC baculaNewInclude(bpContext *ctx) { JCR *jcr; bacula_ctx *bctx; + Dsm_check(999); if (!is_ctx_good(ctx, jcr, bctx)) { return bRC_Error; } (void)new_include(jcr); + Dsm_check(999); return bRC_OK; } @@ -1583,6 +2038,7 @@ static bRC baculaNewPreInclude(bpContext *ctx) { JCR *jcr; bacula_ctx *bctx; + Dsm_check(999); if (!is_ctx_good(ctx, jcr, bctx)) { return bRC_Error; } @@ -1591,10 +2047,11 @@ static bRC baculaNewPreInclude(bpContext *ctx) new_options(jcr, bctx->include); set_incexe(jcr, bctx->include); + Dsm_check(999); return bRC_OK; } -/* +/* * Check if a file have to be backuped using Accurate code */ static bRC baculaCheckChanges(bpContext *ctx, struct save_pkt *sp) @@ -1604,16 +2061,17 @@ static bRC baculaCheckChanges(bpContext *ctx, struct save_pkt *sp) FF_PKT *ff_pkt; bRC ret = bRC_Error; + Dsm_check(999); 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 + * Copy fname and link because save_file() zaps them. This * avoids zaping the plugin's strings. */ ff_pkt->type = sp->type; @@ -1633,19 +2091,63 @@ static bRC baculaCheckChanges(bpContext *ctx, struct save_pkt *sp) } /* check_changes() can update delta sequence number, return it to the - * plugin + * plugin */ sp->delta_seq = ff_pkt->delta_seq; + sp->accurate_found = ff_pkt->accurate_found; bail_out: + Dsm_check(999); Dmsg1(100, "checkChanges=%i\n", ret); return ret; } +/* + * Check if a file would be saved using current Include/Exclude code + */ +static bRC baculaAcceptFile(bpContext *ctx, struct save_pkt *sp) +{ + JCR *jcr; + FF_PKT *ff_pkt; + bacula_ctx *bctx; + + char *old; + struct stat oldstat; + bRC ret = bRC_Error; + + Dsm_check(999); + if (!is_ctx_good(ctx, jcr, bctx)) { + goto bail_out; + } + if (!sp) { + goto bail_out; + } + + ff_pkt = jcr->ff; + + /* Probably not needed, but keep a copy */ + old = ff_pkt->fname; + oldstat = ff_pkt->statp; + + ff_pkt->fname = sp->fname; + ff_pkt->statp = sp->statp; + + if (accept_file(ff_pkt)) { + ret = bRC_OK; + } else { + ret = bRC_Skip; + } + + ff_pkt->fname = old; + ff_pkt->statp = oldstat; + +bail_out: + return ret; +} #ifdef TEST_PROGRAM -int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL; +int (*plugin_bopen)(JCR *jcr, const char *fname, uint64_t flags, mode_t mode) = NULL; int (*plugin_bclose)(JCR *jcr) = NULL; ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL; ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL; @@ -1669,7 +2171,7 @@ int main(int argc, char *argv[]) JCR *jcr2 = &mjcr2; strcpy(my_name, "test-fd"); - + getcwd(plugin_dir, sizeof(plugin_dir)-1); load_fd_plugins(plugin_dir);