From 02ae61c285a57a19f6249d30c4e610d9890126a7 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Fri, 17 Aug 2012 20:11:23 +0200 Subject: [PATCH] backport code from master --- bacula/.gitignore | 3 + bacula/Makefile.in | 1 - bacula/src/bacula.h | 2 - bacula/src/dird/msgchan.c | 11 +- bacula/src/dird/ua_tree.c | 9 +- bacula/src/filed/accurate.c | 4 + bacula/src/filed/backup.c | 8 +- bacula/src/filed/fd_plugins.c | 369 +++++++++++++++++++--- bacula/src/filed/fd_plugins.h | 9 +- bacula/src/filed/job.c | 8 + bacula/src/filed/protos.h | 1 + bacula/src/findlib/bfile.c | 4 +- bacula/src/findlib/find.c | 12 +- bacula/src/findlib/find_one.c | 11 +- bacula/src/findlib/protos.h | 1 + bacula/src/jcr.h | 10 +- bacula/src/lib/plugins.c | 2 +- bacula/src/lib/rblist.c | 11 +- bacula/src/lib/workq.c | 4 +- bacula/src/plugins/fd/bpipe-fd.c | 15 +- bacula/src/plugins/fd/example-plugin-fd.c | 18 +- bacula/src/plugins/fd/test-plugin-fd.c | 259 ++++++++++++++- bacula/src/qt-console/bat.pro.in | 2 +- bacula/src/stored/acquire.c | 5 +- bacula/src/stored/block.c | 10 +- bacula/src/stored/butil.c | 10 +- bacula/src/stored/device.c | 4 +- bacula/src/stored/label.c | 2 +- bacula/src/stored/mac.c | 14 + bacula/src/stored/mount.c | 6 +- bacula/src/stored/sd_plugins.c | 4 +- bacula/src/stored/vol_mgr.c | 26 +- bacula/src/tools/bsmtp.c | 3 +- bacula/src/version.h | 8 +- regress/do_all_no_setup | 2 + regress/tests/acl-xattr-test | 36 +-- 36 files changed, 762 insertions(+), 142 deletions(-) create mode 100755 regress/do_all_no_setup diff --git a/bacula/.gitignore b/bacula/.gitignore index 07fc982dd5..85929de9fa 100644 --- a/bacula/.gitignore +++ b/bacula/.gitignore @@ -194,6 +194,7 @@ scripts/Makefile scripts/bacula scripts/btraceback scripts/fd +scripts/reset-storageid scripts/startit scripts/startmysql scripts/stopit @@ -379,6 +380,7 @@ src/plugins/dir/*.o src/plugins/dir/*.so src/plugins/dir/main src/plugins/dir/Makefile +src/plugins/dir/.libs # src/plugins/fd/ src/plugins/fd/*.o @@ -479,6 +481,7 @@ src/qt-console/tray-monitor/Makefile.mingw32 src/qt-console/tray-monitor/Makefile.mingw32.Debug src/qt-console/tray-monitor/Makefile.mingw32.Release src/qt-console/tray-monitor/debug/ +src/qt-console/tray-monitor/release/ src/qt-console/tray-monitor/moc/ src/qt-console/tray-monitor/tray-monitor.conf src/qt-console/tray-monitor/tray-monitor.pro diff --git a/bacula/Makefile.in b/bacula/Makefile.in index c970d91282..1abc14ae14 100755 --- a/bacula/Makefile.in +++ b/bacula/Makefile.in @@ -1,5 +1,4 @@ # -# Version $Id$ # Master Makefile # @MCOMMON@ diff --git a/bacula/src/bacula.h b/bacula/src/bacula.h index 2c2b2bdae0..ccaa978693 100644 --- a/bacula/src/bacula.h +++ b/bacula/src/bacula.h @@ -67,8 +67,6 @@ #ifndef __sgi #include #endif -#elif HAVE_INTTYPES_H -#include #endif #if HAVE_STDARG_H #include diff --git a/bacula/src/dird/msgchan.c b/bacula/src/dird/msgchan.c index b3f5e8fd11..1e7cfc7038 100644 --- a/bacula/src/dird/msgchan.c +++ b/bacula/src/dird/msgchan.c @@ -375,6 +375,7 @@ extern "C" void *msg_thread(void *arg) JCR *jcr = (JCR *)arg; BSOCK *sd; int JobStatus; + int n; char Job[MAX_NAME_LENGTH]; uint32_t JobFiles, JobErrors; uint64_t JobBytes; @@ -388,7 +389,8 @@ extern "C" void *msg_thread(void *arg) /* Read the Storage daemon's output. */ Dmsg0(100, "Start msg_thread loop\n"); - while (!job_canceled(jcr) && bget_dirmsg(sd) >= 0) { + n = 0; + while (!job_canceled(jcr) && (n=bget_dirmsg(sd)) >= 0) { Dmsg1(400, "msg); if (sscanf(sd->msg, Job_start, Job) == 1) { continue; @@ -403,6 +405,13 @@ extern "C" void *msg_thread(void *arg) } Dmsg1(400, "end loop use=%d\n", jcr->use_count()); } + if (n == BNET_HARDEOF) { + /* + * This probably should be M_FATAL, but I am not 100% sure + * that this return *always* corresponds to a dropped line. + */ + Qmsg(jcr, M_ERROR, 0, _("Director's comm line to SD dropped.\n")); + } if (is_bnet_error(sd)) { jcr->SDJobStatus = JS_ErrorTerminated; } diff --git a/bacula/src/dird/ua_tree.c b/bacula/src/dird/ua_tree.c index 0cebf3a51a..0f97b0a4d4 100644 --- a/bacula/src/dird/ua_tree.c +++ b/bacula/src/dird/ua_tree.c @@ -224,9 +224,12 @@ int insert_tree_handler(void *ctx, int num_fields, char **row) tree_remove_node(tree->root, node); } else { - Dmsg3(0, "Something is wrong with Delta, skipt it " - "fname=%s d1=%d d2=%d\n", - row[1], node->delta_seq, delta_seq); + tree->ua->warning_msg(_("Something is wrong with the Delta sequence of %s, " + "skiping new parts. Current sequence is %d\n"), + row[1], node->delta_seq); + + Dmsg3(0, "Something is wrong with Delta, skip it " + "fname=%s d1=%d d2=%d\n", row[1], node->delta_seq, delta_seq); } return 0; } diff --git a/bacula/src/filed/accurate.c b/bacula/src/filed/accurate.c index 04bbfe43ab..a4c7cc4429 100644 --- a/bacula/src/filed/accurate.c +++ b/bacula/src/filed/accurate.c @@ -265,6 +265,10 @@ bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt) return true; } + if (!jcr->file_list) { + return true; /* Not initialized properly */ + } + strip_path(ff_pkt); if (S_ISDIR(ff_pkt->statp.st_mode)) { diff --git a/bacula/src/filed/backup.c b/bacula/src/filed/backup.c index 080e4cf2e9..44d7e29d5c 100644 --- a/bacula/src/filed/backup.c +++ b/bacula/src/filed/backup.c @@ -459,6 +459,9 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level) jcr->JobErrors++; return 1; } + case FT_DELETED: + Dmsg1(130, "FT_DELETED: %s\n", ff_pkt->fname); + break; default: Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d; not saved: %s\n"), ff_pkt->type, ff_pkt->fname); @@ -576,7 +579,10 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level) if (IS_FT_OBJECT(ff_pkt->type)) { goto good_rtn; } - + /** Meta data only for deleted files */ + if (ff_pkt->type == FT_DELETED) { + goto good_rtn; + } /** Set up the encryption context and send the session data to the SD */ if (has_file_data && jcr->crypto.pki_encrypt) { if (!crypto_session_send(jcr, sd)) { diff --git a/bacula/src/filed/fd_plugins.c b/bacula/src/filed/fd_plugins.c index 89895b6473..2e4767ccb2 100644 --- a/bacula/src/filed/fd_plugins.c +++ b/bacula/src/filed/fd_plugins.c @@ -80,6 +80,7 @@ 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 @@ -91,7 +92,6 @@ 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 = { @@ -118,7 +118,8 @@ static bFuncs bfuncs = { baculaNewOptions, baculaNewInclude, baculaNewPreInclude, - baculaCheckChanges + baculaCheckChanges, + baculaAcceptFile }; /* @@ -132,9 +133,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 +171,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); } @@ -159,12 +185,13 @@ void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) bpContext *plugin_ctx; bEvent event; Plugin *plugin; - int i; char *name = NULL; + int i; int len = 0; bool call_if_canceled = false; restore_object_pkt *rop; + Dsm_check(999); if (!bplugin_list || !jcr || !jcr->plugin_ctx_list) { return; /* Return if no plugins loaded */ } @@ -195,7 +222,7 @@ 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_index(i, plugin, bplugin_list) { @@ -204,19 +231,13 @@ void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) } 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,13 +252,30 @@ void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) * is set, we pass it only to the plugin with that name. */ foreach_alist_index(i, plugin, bplugin_list) { - if (name && !for_this_plug(plugin, name, len)) { + if (!for_this_plugin(plugin, name, len)) { + Dmsg2(dbglvl, "Not for this plugin name=%s NULL=%d\n", + name, name==NULL?1:0); continue; } + /* + * 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)) { continue; } + 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; @@ -252,6 +290,7 @@ bool plugin_check_file(JCR *jcr, char *fname) int rc = bRC_OK; int i; + Dsm_check(999); if (!bplugin_list || !jcr || !jcr->plugin_ctx_list || jcr->is_job_canceled()) { return false; /* Return if no plugins loaded */ } @@ -276,6 +315,7 @@ bool plugin_check_file(JCR *jcr, char *fname) } } + Dsm_check(999); jcr->plugin = NULL; jcr->plugin_ctx = NULL; return rc == bRC_Seen; @@ -284,7 +324,7 @@ bool plugin_check_file(JCR *jcr, char *fname) /* Get the first part of the the plugin command * 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 @@ -294,6 +334,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; } @@ -313,12 +354,14 @@ 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) { @@ -331,11 +374,24 @@ static void update_ff_pkt(FF_PKT *ff_pkt, struct save_pkt *sp) 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 */ @@ -349,6 +405,7 @@ bRC plugin_option_handle_file(JCR *jcr, FF_PKT *ff_pkt, struct save_pkt *sp) 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); @@ -373,13 +430,17 @@ 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_index(i, plugin, bplugin_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)) { + if (!for_this_plugin(plugin, cmd, len)) { continue; } + Dsm_check(999); if (is_plugin_disabled(&plugin_ctx_list[i])) { goto bail_out; } + + jcr->plugin_ctx = &plugin_ctx_list[i]; + jcr->plugin = plugin; ret = plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], &event, sp); @@ -392,11 +453,17 @@ bRC plugin_option_handle_file(JCR *jcr, FF_PKT *ff_pkt, struct save_pkt *sp) 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: + Dsm_check(999); return ret; } @@ -418,14 +485,15 @@ bail_out: int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) { Plugin *plugin; - int i; 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); + Dsm_check(999); if (!bplugin_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 */ @@ -442,7 +510,7 @@ 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_index(i, plugin, bplugin_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)) { + if (!for_this_plugin(plugin, cmd, len)) { continue; } /* @@ -450,6 +518,7 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) * 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,10 +536,12 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) 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; @@ -500,6 +571,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); @@ -525,6 +597,7 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) if (rc == bRC_More || rc == bRC_OK) { accurate_mark_file_as_seen(jcr, fname.c_str()); } + Dsm_check(999); if (rc == bRC_More) { continue; } @@ -535,6 +608,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; @@ -564,6 +638,7 @@ int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level) POOL_MEM link(PM_FNAME); ATTR attr; + Dsm_check(999); if (!bplugin_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 */ @@ -580,7 +655,7 @@ 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_index(i, plugin, bplugin_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)) { + if (!for_this_plugin(plugin, cmd, len)) { continue; } /* @@ -588,6 +663,7 @@ int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level) * 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)) { @@ -601,6 +677,7 @@ int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level) } /* Loop getting filenames to backup then saving them */ while (!jcr->is_job_canceled()) { + Dsm_check(999); memset(&sp, 0, sizeof(sp)); sp.pkt_size = sizeof(sp); sp.pkt_end = sizeof(sp); @@ -626,8 +703,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) { @@ -652,6 +743,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; } @@ -662,6 +754,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; @@ -677,6 +770,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,13 +784,15 @@ bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start) } 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); @@ -704,6 +800,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()); @@ -711,6 +808,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; } @@ -731,6 +829,7 @@ bool plugin_name_stream(JCR *jcr, char *name) 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); @@ -759,6 +858,7 @@ bool plugin_name_stream(JCR *jcr, char *name) jcr->plugin = NULL; goto bail_out; } + Dsm_check(999); if (!plugin_ctx_list) { goto bail_out; } @@ -773,36 +873,50 @@ bool plugin_name_stream(JCR *jcr, char *name) /* * Search for correct plugin as specified on the command */ + Dsm_check(999); foreach_alist_index(i, plugin, bplugin_list) { bEvent event; Dmsg3(dbglvl, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len); - if (!for_this_plug(plugin, cmd, len)) { + 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); + 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; } @@ -824,6 +938,7 @@ int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) int flags; int rc; + Dsm_check(999); if (!plugin || !plugin_ctx || !set_cmd_plugin(bfd, jcr) || jcr->is_job_canceled()) { return CF_ERROR; } @@ -850,8 +965,10 @@ int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) 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; } @@ -861,26 +978,31 @@ 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 */ + } + /* 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); @@ -893,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; } @@ -904,11 +1027,45 @@ 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; } @@ -945,6 +1102,7 @@ void load_fd_plugins(const char *plugin_dir) } bplugin_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 */ @@ -962,6 +1120,7 @@ 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 @@ -973,6 +1132,7 @@ void load_fd_plugins(const char *plugin_dir) } dbg_plugin_add_hook(dump_fd_plugin); + Dsm_check(999); } /** @@ -982,7 +1142,8 @@ 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"); + Dmsg0(dbglvl, "is_plugin_compatible called\n"); + Dsm_check(999); if (debug_level >= 50) { dump_fd_plugin(plugin, stdin); } @@ -1002,7 +1163,7 @@ 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 && 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", @@ -1016,6 +1177,7 @@ static bool is_plugin_compatible(Plugin *plugin) return false; } + Dsm_check(999); return true; } @@ -1030,6 +1192,7 @@ void new_plugins(JCR *jcr) Plugin *plugin; int i; + Dsm_check(999); if (!bplugin_list) { Dmsg0(dbglvl, "plugin list is NULL\n"); return; @@ -1050,6 +1213,7 @@ 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_index(i, plugin, bplugin_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)); @@ -1060,6 +1224,11 @@ void new_plugins(JCR *jcr) 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,13 +1243,16 @@ void free_plugins(JCR *jcr) 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_index(i, plugin, bplugin_list) { /* Free the plugin instance */ plug_func(plugin)->freePlugin(&plugin_ctx_list[i]); 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; } @@ -1092,6 +1264,7 @@ static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode struct io_pkt io; Dmsg1(dbglvl, "plugin_bopen flags=%x\n", flags); + Dsm_check(999); if (!plugin || !jcr->plugin_ctx) { return 0; } @@ -1113,7 +1286,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; } @@ -1123,6 +1297,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; @@ -1143,6 +1318,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; } @@ -1152,6 +1328,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; @@ -1173,6 +1350,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; } @@ -1182,8 +1360,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); @@ -1201,6 +1381,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; } @@ -1210,6 +1391,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; @@ -1229,6 +1411,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; } @@ -1245,6 +1428,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; @@ -1338,21 +1522,25 @@ 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 bVarFDName: /* get warning with g++ if we missed one */ case bVarWorkingDir: case bVarExePath: case bVarVersion: case bVarDistName: case bVarBEEF: - case bVarPrefixLinks: 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; } @@ -1371,6 +1559,7 @@ static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value) default: break; } + Dsm_check(999); return bRC_OK; } @@ -1379,6 +1568,7 @@ static bRC baculaRegisterEvents(bpContext *ctx, ...) va_list args; uint32_t event; + Dsm_check(999); if (!ctx) { return bRC_Error; } @@ -1388,6 +1578,7 @@ static bRC baculaRegisterEvents(bpContext *ctx, ...) Dmsg1(dbglvl, "Plugin wants event=%u\n", event); } va_end(args); + Dsm_check(999); return bRC_OK; } @@ -1398,6 +1589,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 { @@ -1408,6 +1600,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; } @@ -1417,10 +1610,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; } @@ -1445,6 +1640,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; } @@ -1466,20 +1662,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; } + + /* 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; } @@ -1490,23 +1704,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; } @@ -1514,6 +1741,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; } @@ -1521,6 +1749,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; } @@ -1529,6 +1758,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; } @@ -1537,6 +1767,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; } @@ -1544,6 +1775,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; } @@ -1552,6 +1784,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; } @@ -1559,10 +1792,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; } @@ -1570,10 +1805,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; } @@ -1581,6 +1818,7 @@ static bRC baculaNewPreInclude(bpContext *ctx) { JCR *jcr; bacula_ctx *bctx; + Dsm_check(999); if (!is_ctx_good(ctx, jcr, bctx)) { return bRC_Error; } @@ -1589,6 +1827,7 @@ static bRC baculaNewPreInclude(bpContext *ctx) new_options(jcr, bctx->include); set_incexe(jcr, bctx->include); + Dsm_check(999); return bRC_OK; } @@ -1602,6 +1841,7 @@ 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; } @@ -1637,10 +1877,53 @@ static bRC baculaCheckChanges(bpContext *ctx, struct save_pkt *sp) 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 diff --git a/bacula/src/filed/fd_plugins.h b/bacula/src/filed/fd_plugins.h index d20f17b6e2..40994f814c 100644 --- a/bacula/src/filed/fd_plugins.h +++ b/bacula/src/filed/fd_plugins.h @@ -215,7 +215,6 @@ typedef enum { bEventEndFileSet = 19, bEventPluginCommand = 20, /* Sent during FileSet creation */ bEventVssBeforeCloseRestore = 21, - /* Add drives to VSS snapshot * argument: char[27] drivelist * You need to add them without duplicates, @@ -223,7 +222,8 @@ typedef enum { */ bEventVssPrepareSnapshot = 22, bEventOptionPlugin = 23, - bEventHandleBackupFile = 24 /* Used with Options Plugin */ + bEventHandleBackupFile = 24, /* Used with Options Plugin */ + bEventComponentInfo = 25 /* Plugin component */ } bEventType; typedef struct s_bEvent { @@ -283,6 +283,7 @@ typedef struct s_baculaFuncs { bRC (*NewInclude)(bpContext *ctx); bRC (*NewPreInclude)(bpContext *ctx); bRC (*checkChanges)(bpContext *ctx, struct save_pkt *sp); + bRC (*AcceptFile)(bpContext *ctx, struct save_pkt *sp); /* Need fname and statp */ } bFuncs; @@ -299,9 +300,9 @@ typedef enum { pVarDescription = 2 } pVariable; +# define FD_PLUGIN_MAGIC "*FDPluginData*" -#define FD_PLUGIN_MAGIC "*FDPluginData*" -#define FD_PLUGIN_INTERFACE_VERSION 6 +#define FD_PLUGIN_INTERFACE_VERSION 7 typedef struct s_pluginInfo { uint32_t size; diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index c59f4cc3cf..230c626a00 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -890,6 +890,14 @@ void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file) } } +findINCEXE *get_incexe(JCR *jcr) +{ + if (jcr->ff && jcr->ff->fileset) { + return jcr->ff->fileset->incexe; + } + return NULL; +} + void set_incexe(JCR *jcr, findINCEXE *incexe) { findFILESET *fileset = jcr->ff->fileset; diff --git a/bacula/src/filed/protos.h b/bacula/src/filed/protos.h index dc793b9259..e4191940d6 100644 --- a/bacula/src/filed/protos.h +++ b/bacula/src/filed/protos.h @@ -69,6 +69,7 @@ bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream, char *content, uint32 /* from job.c */ findINCEXE *new_exclude(JCR *jcr); findINCEXE *new_preinclude(JCR *jcr); +findINCEXE *get_incexe(JCR *jcr); void set_incexe(JCR *jcr, findINCEXE *incexe); void new_options(JCR *jcr, findINCEXE *incexe); void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file); diff --git a/bacula/src/findlib/bfile.c b/bacula/src/findlib/bfile.c index 2c8884ccee..0d4c1062af 100644 --- a/bacula/src/findlib/bfile.c +++ b/bacula/src/findlib/bfile.c @@ -953,9 +953,9 @@ bool is_restore_stream_supported(int stream) int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode) { if (bfd->cmd_plugin && plugin_bopen) { - Dmsg1(50, "call plugin_bopen fname=%s\n", fname); + Dmsg1(400, "call plugin_bopen fname=%s\n", fname); bfd->fid = plugin_bopen(bfd, fname, flags, mode); - Dmsg1(50, "Plugin bopen stat=%d\n", bfd->fid); + Dmsg1(400, "Plugin bopen stat=%d\n", bfd->fid); return bfd->fid; } diff --git a/bacula/src/findlib/find.c b/bacula/src/findlib/find.c index d31714ec05..68c70efeff 100644 --- a/bacula/src/findlib/find.c +++ b/bacula/src/findlib/find.c @@ -50,7 +50,6 @@ int32_t path_max; /* path name max length */ #define bmalloc(x) sm_malloc(__FILE__, __LINE__, x) #endif static int our_callback(JCR *jcr, FF_PKT *ff, bool top_level); -static bool accept_file(FF_PKT *ff); static const int fnmode = 0; @@ -187,9 +186,12 @@ find_files(JCR *jcr, FF_PKT *ff, int file_save(JCR *jcr, FF_PKT *ff_pkt, bool to findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i); fileset->incexe = incexe; + /* Here, we reset some values between two different Include{} */ strcpy(ff->VerifyOpts, "V"); strcpy(ff->AccurateOpts, "Cmcs"); /* mtime+ctime+size by default */ strcpy(ff->BaseJobOpts, "Jspug5"); /* size+perm+user+group+chk */ + ff->plugin = NULL; + ff->opt_plugin = false; /* * By setting all options, we in effect OR the global options @@ -203,8 +205,10 @@ find_files(JCR *jcr, FF_PKT *ff, int file_save(JCR *jcr, FF_PKT *ff_pkt, bool to ff->strip_path = fo->strip_path; ff->fstypes = fo->fstype; ff->drivetypes = fo->drivetype; - ff->plugin = fo->plugin; /* TODO: generate a plugin event ? */ - ff->opt_plugin = (ff->plugin != NULL)? true : false; + if (fo->plugin != NULL) { + ff->plugin = fo->plugin; /* TODO: generate a plugin event ? */ + ff->opt_plugin = true; + } bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts)); /* TODO: Concat or replace? */ if (fo->AccurateOpts[0]) { bstrncpy(ff->AccurateOpts, fo->AccurateOpts, sizeof(ff->AccurateOpts)); @@ -285,7 +289,7 @@ bool is_in_fileset(FF_PKT *ff) } -static bool accept_file(FF_PKT *ff) +bool accept_file(FF_PKT *ff) { int i, j, k; int fnm_flags; diff --git a/bacula/src/findlib/find_one.c b/bacula/src/findlib/find_one.c index b2d7f98810..36708d3433 100644 --- a/bacula/src/findlib/find_one.c +++ b/bacula/src/findlib/find_one.c @@ -246,27 +246,32 @@ bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt) } if (statp.st_mtime != ff_pkt->statp.st_mtime) { - /* TODO: add time of changes */ Jmsg(jcr, M_ERROR, 0, _("%s mtime changed during backup.\n"), ff_pkt->fname); + Dmsg3(50, "%s mtime (%lld) changed during backup (%lld).\n", ff_pkt->fname, + (int64_t)ff_pkt->statp.st_mtime, (int64_t)statp.st_mtime); return true; } if (statp.st_ctime != ff_pkt->statp.st_ctime) { - /* TODO: add time of changes */ Jmsg(jcr, M_ERROR, 0, _("%s ctime changed during backup.\n"), ff_pkt->fname); + Dmsg3(50, "%s ctime (%lld) changed during backup (%lld).\n", ff_pkt->fname, + (int64_t)ff_pkt->statp.st_ctime, (int64_t)statp.st_ctime); return true; } if (statp.st_size != ff_pkt->statp.st_size) { /* TODO: add size change */ Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname); + Dmsg3(50, "%s size (%lld) changed during backup (%lld).\n", ff_pkt->fname, + (int64_t)ff_pkt->statp.st_size, (int64_t)statp.st_size); return true; } if ((statp.st_blksize != ff_pkt->statp.st_blksize) || (statp.st_blocks != ff_pkt->statp.st_blocks)) { - /* TODO: add size change */ Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname); + Dmsg3(50, "%s size (%lld) changed during backup (%lld).\n", ff_pkt->fname, + (int64_t)ff_pkt->statp.st_blocks, (int64_t)statp.st_blocks); return true; } diff --git a/bacula/src/findlib/protos.h b/bacula/src/findlib/protos.h index b39d25d3a1..5b218b3ca3 100644 --- a/bacula/src/findlib/protos.h +++ b/bacula/src/findlib/protos.h @@ -51,6 +51,7 @@ int match_files(JCR *jcr, FF_PKT *ff, int sub(JCR *, FF_PKT *ff_pkt, bool)); int term_find_files(FF_PKT *ff); int get_win32_driveletters(FF_PKT *ff, char* szDrives); bool is_in_fileset(FF_PKT *ff); +bool accept_file(FF_PKT *ff); /* From match.c */ void init_include_exclude_files(FF_PKT *ff); diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 3aecc9e75f..a017d1b04d 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2011 Free Software Foundation Europe e.V. + Copyright (C) 2000-2012 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. @@ -239,7 +239,9 @@ public: uint32_t JobFiles; /* Number of files written, this job */ uint32_t JobErrors; /* Number of non-fatal errors this job */ uint32_t JobWarnings; /* Number of warning messages */ + uint32_t LastRate; /* Last sample bytes/sec */ uint64_t JobBytes; /* Number of bytes processed this job */ + uint64_t LastJobBytes; /* Last sample number bytes */ uint64_t ReadBytes; /* Bytes read -- before compression */ FileId_t FileId; /* Last FileId used */ volatile int32_t JobStatus; /* ready, running, blocked, terminated */ @@ -247,6 +249,7 @@ public: time_t sched_time; /* job schedule time, i.e. when it should start */ time_t start_time; /* when job actually started */ time_t run_time; /* used for computing speed */ + time_t last_time; /* Last sample time */ time_t end_time; /* job end time */ time_t wait_time_sum; /* cumulative wait time since job start */ time_t wait_time; /* timestamp when job have started to wait */ @@ -328,6 +331,8 @@ public: uint32_t FileIndex; /* Last FileIndex processed */ utime_t MaxRunSchedTime; /* max run time in seconds from Scheduled time*/ POOLMEM *fname; /* name to put into catalog */ + POOLMEM *component_fname; /* Component info file name */ + FILE *component_fd; /* Component info file desc */ JOB_DBR jr; /* Job DB record for current job */ JOB_DBR previous_jr; /* previous job database record */ JOB *previous_job; /* Job resource of migration previous job */ @@ -398,6 +403,7 @@ public: FF_PKT *ff; /* Find Files packet */ char stored_addr[MAX_NAME_LENGTH]; /* storage daemon address */ char PrevJob[MAX_NAME_LENGTH]; /* Previous job name assiciated with since time */ + uint32_t ExpectedFiles; /* Expected restore files */ uint32_t StartFile; uint32_t EndFile; uint32_t StartBlock; @@ -410,7 +416,7 @@ public: CRYPTO_CTX crypto; /* Crypto ctx */ DIRRES* director; /* Director resource */ bool VSS; /* VSS used by FD */ - bool got_metadata; /* set when found job_metadata */ + bool got_metadata; /* set when found job_metatdata */ bool multi_restore; /* Dir can do multiple storage restore */ htable *file_list; /* Previous file list (accurate mode) */ uint64_t base_size; /* compute space saved with base job */ diff --git a/bacula/src/lib/plugins.c b/bacula/src/lib/plugins.c index 0cffff1194..e6cf7b03ad 100644 --- a/bacula/src/lib/plugins.c +++ b/bacula/src/lib/plugins.c @@ -164,7 +164,7 @@ bool load_plugins(void *binfo, void *bfuncs, const char *plugin_dir, plugin->file_len = strstr(plugin->file, type) - plugin->file; plugin->pHandle = dlopen(fname.c_str(), RTLD_NOW); if (!plugin->pHandle) { - char *error = (char *)dlerror(); + const char *error = dlerror(); Jmsg(NULL, M_ERROR, 0, _("dlopen plugin %s failed: ERR=%s\n"), fname.c_str(), NPRT(error)); Dmsg2(dbglvl, "dlopen plugin %s failed: ERR=%s\n", fname.c_str(), diff --git a/bacula/src/lib/rblist.c b/bacula/src/lib/rblist.c index 7bf0266904..2d5477ff1a 100644 --- a/bacula/src/lib/rblist.c +++ b/bacula/src/lib/rblist.c @@ -250,6 +250,10 @@ void *rblist::any(void *item) { void *x; + if (!item) { + return NULL; + } + x = item; if ((down && !left(x) && right(x)) || (!down && right(x))) { /* Move down to right one */ @@ -335,7 +339,6 @@ void rblist::destroy() x = first(); // printf("head=%p first=%p left=%p right=%p\n", head, x, left(x), right(x)); - for ( ; (y=any(x)); ) { /* Prune the last item */ if (parent(x)) { @@ -349,9 +352,9 @@ void rblist::destroy() if (head == x) { head = NULL; } -// if (num_items<30) { -// printf("free nitems=%d item=%p left=%p right=%p\n", num_items, x, left(x), right(x)); -// } +// if (num_items<30) { +// printf("free nitems=%d item=%p left=%p right=%p\n", num_items, x, left(x), right(x)); +// } free((void *)x); /* free previous node */ num_items--; } diff --git a/bacula/src/lib/workq.c b/bacula/src/lib/workq.c index ce1be8312a..e3f751747e 100644 --- a/bacula/src/lib/workq.c +++ b/bacula/src/lib/workq.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2001-2011 Free Software Foundation Europe e.V. + Copyright (C) 2001-2012 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. @@ -31,8 +31,6 @@ * * Kern Sibbald, January MMI * - * Version $Id$ - * * This code adapted from "Programming with POSIX Threads", by * David R. Butenhof * diff --git a/bacula/src/plugins/fd/bpipe-fd.c b/bacula/src/plugins/fd/bpipe-fd.c index 6828c8aac6..f4269ef583 100644 --- a/bacula/src/plugins/fd/bpipe-fd.c +++ b/bacula/src/plugins/fd/bpipe-fd.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2007-2010 Free Software Foundation Europe e.V. + Copyright (C) 2007-2012 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. @@ -66,6 +66,7 @@ static bRC startRestoreFile(bpContext *ctx, const char *cmd); static bRC endRestoreFile(bpContext *ctx); static bRC createFile(bpContext *ctx, struct restore_pkt *rp); static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp); +static bRC checkFile(bpContext *ctx, char *fname); static char *apply_rp_codes(struct plugin_ctx * p_ctx); @@ -82,7 +83,7 @@ static pInfo pluginInfo = { PLUGIN_AUTHOR, PLUGIN_DATE, PLUGIN_VERSION, - PLUGIN_DESCRIPTION, + PLUGIN_DESCRIPTION }; /* Plugin entry points for Bacula */ @@ -102,7 +103,8 @@ static pFuncs pluginFuncs = { endRestoreFile, pluginIO, createFile, - setFileAttributes + setFileAttributes, + checkFile }; /* @@ -475,6 +477,12 @@ static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp) return bRC_OK; } +/* When using Incremental dump, all previous dumps are necessary */ +static bRC checkFile(bpContext *ctx, char *fname) +{ + return bRC_OK; +} + /************************************************************************* * Apply codes in writer command: * %w -> "where" @@ -563,7 +571,6 @@ static char *apply_rp_codes(struct plugin_ctx * p_ctx) return omsg; } - #ifdef __cplusplus } #endif diff --git a/bacula/src/plugins/fd/example-plugin-fd.c b/bacula/src/plugins/fd/example-plugin-fd.c index dced30e274..47d5239a91 100644 --- a/bacula/src/plugins/fd/example-plugin-fd.c +++ b/bacula/src/plugins/fd/example-plugin-fd.c @@ -1,6 +1,6 @@ /* - Copyright (C) 2007-2010 Kern Sibbald + Copyright (C) 2007-2012 Kern Sibbald You may freely use this code to create your own plugin provided it is to write a plugin for Bacula licensed under AGPLv3 @@ -39,6 +39,7 @@ static bRC startRestoreFile(bpContext *ctx, const char *cmd); static bRC endRestoreFile(bpContext *ctx); static bRC createFile(bpContext *ctx, struct restore_pkt *rp); static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp); +static bRC checkFile(bpContext *ctx, char *fname); /* Pointers to Bacula functions */ @@ -72,7 +73,8 @@ static pFuncs pluginFuncs = { endRestoreFile, pluginIO, createFile, - setFileAttributes + setFileAttributes, + checkFile }; /* @@ -184,16 +186,18 @@ static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value) case bEventEndRestoreJob: printf("plugin: EndRestoreJob\n"); break; - /* Plugin command e.g. plugin = ::command */ case bEventRestoreCommand: printf("plugin: backup command=%s\n", NPRT((char *)value)); break; - case bEventBackupCommand: printf("plugin: backup command=%s\n", NPRT((char *)value)); break; + case bEventComponentInfo: + printf("plugin: Component=%s\n", NPRT((char *)value)); + break; + default: printf("plugin: unknown event=%d\n", event->eventType); } @@ -281,6 +285,12 @@ static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp) return bRC_OK; } +/* When using Incremental dump, all previous dumps are necessary */ +static bRC checkFile(bpContext *ctx, char *fname) +{ + return bRC_OK; +} + #ifdef __cplusplus } diff --git a/bacula/src/plugins/fd/test-plugin-fd.c b/bacula/src/plugins/fd/test-plugin-fd.c index 175e0741eb..765903ffd8 100644 --- a/bacula/src/plugins/fd/test-plugin-fd.c +++ b/bacula/src/plugins/fd/test-plugin-fd.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2007-2010 Free Software Foundation Europe e.V. + Copyright (C) 2007-2012 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. @@ -69,6 +69,7 @@ static bRC startRestoreFile(bpContext *ctx, const char *cmd); static bRC endRestoreFile(bpContext *ctx); static bRC createFile(bpContext *ctx, struct restore_pkt *rp); static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp); +static bRC checkFile(bpContext *ctx, char *fname); /* Pointers to Bacula functions */ static bFuncs *bfuncs = NULL; @@ -83,7 +84,7 @@ static pInfo pluginInfo = { PLUGIN_AUTHOR, PLUGIN_DATE, PLUGIN_VERSION, - PLUGIN_DESCRIPTION, + PLUGIN_DESCRIPTION }; /* Plugin entry points for Bacula */ @@ -103,7 +104,8 @@ static pFuncs pluginFuncs = { endRestoreFile, pluginIO, createFile, - setFileAttributes + setFileAttributes, + checkFile }; static struct ini_items test_items[] = { @@ -257,6 +259,7 @@ static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value) case bEventStartBackupJob: break; case bEventRestoreObject: + { printf("Plugin RestoreObject\n"); if (!value) { bfuncs->DebugMessage(ctx, fi, li, dbglvl, "test-plugin-fd: End restore objects\n"); @@ -264,13 +267,27 @@ static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value) } rop = (restore_object_pkt *)value; bfuncs->DebugMessage(ctx, fi, li, dbglvl, - "Get RestoreObject len=%d JobId=%d oname=%s type=%d data=%s\n", + "Get RestoreObject len=%d JobId=%d oname=%s type=%d data=%.127s\n", rop->object_len, rop->JobId, rop->object_name, rop->object_type, rop->object); + FILE *fp; + POOLMEM *q; + char *working; + static int _nb=0; + q = get_pool_memory(PM_FNAME); + + bfuncs->getBaculaValue(ctx, bVarWorkingDir, &working); + Mmsg(q, "%s/restore.%d", working, _nb++); + if ((fp = fopen(q, "w")) != NULL) { + fwrite(rop->object, rop->object_len, 1, fp); + fclose(fp); + } + + free_pool_memory(q); if (!strcmp(rop->object_name, INI_RESTORE_OBJECT_NAME)) { ConfigFile ini; - if (ini.dump_string(rop->object, rop->object_len)) { + if (!ini.dump_string(rop->object, rop->object_len)) { break; } ini.register_items(test_items, sizeof(struct ini_items)); @@ -283,12 +300,14 @@ static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value) } break; + } /* Plugin command e.g. plugin = ::read command:write command */ case bEventRestoreCommand: /* Fall-through wanted */ case bEventEstimateCommand: /* Fall-through wanted */ case bEventBackupCommand: + { char *p; bfuncs->DebugMessage(ctx, fi, li, dbglvl, "test-plugin-fd: pluginEvent cmd=%s\n", (char *)value); p_ctx->cmd = strdup((char *)value); @@ -316,10 +335,15 @@ static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value) printf("test-plugin-fd: plugin=%s fname=%s reader=%s writer=%s\n", p_ctx->cmd, p_ctx->fname, p_ctx->reader, p_ctx->writer); break; + } case bEventPluginCommand: break; case bEventVssBeforeCloseRestore: break; + case bEventComponentInfo: + printf("plugin: Component=%s\n", NPRT((char *)value)); + break; + default: printf("test-plugin-fd: unknown event=%d\n", event->eventType); break; @@ -337,15 +361,231 @@ static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp) return bRC_Error; } + if (p_ctx->nb_obj == 0) { + sp->fname = (char *)"takeme.h"; + bfuncs->DebugMessage(ctx, fi, li, dbglvl, "AcceptFile=%s = %d\n", + sp->fname, bfuncs->AcceptFile(ctx, sp)); + + sp->fname = (char *)"/path/to/excludeme.o"; + bfuncs->DebugMessage(ctx, fi, li, dbglvl, "AcceptFile=%s = %d\n", + sp->fname, bfuncs->AcceptFile(ctx, sp)); + + sp->fname = (char *)"/path/to/excludeme.c"; + bfuncs->DebugMessage(ctx, fi, li, dbglvl, "AcceptFile=%s = %d\n", + sp->fname, bfuncs->AcceptFile(ctx, sp)); + } + if (p_ctx->nb_obj == 0) { sp->object_name = (char *)"james.xml"; sp->object = (char *)"This is test data for the restore object. " "garbage=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" "\0secret"; sp->object_len = strlen(sp->object)+1+6+1; /* str + 0 + secret + 0 */ sp->type = FT_RESTORE_FIRST; + + static int _nb=0; + POOLMEM *q = get_pool_memory(PM_FNAME); + char *working; + FILE *fp; + + bfuncs->getBaculaValue(ctx, bVarWorkingDir, &working); + Mmsg(q, "%s/torestore.%d", working, _nb++); + if ((fp = fopen(q, "w")) != NULL) { + fwrite(sp->object, sp->object_len, 1, fp); + fclose(fp); + } + free_pool_memory(q); } else if (p_ctx->nb_obj == 1) { ConfigFile ini; @@ -370,7 +610,7 @@ static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp) sp->statp.st_blksize = 4096; sp->statp.st_blocks = 1; bfuncs->DebugMessage(ctx, fi, li, dbglvl, - "Creating RestoreObject len=%d oname=%s data=%s\n", + "Creating RestoreObject len=%d oname=%s data=%.127s\n", sp->object_len, sp->object_name, sp->object); printf("test-plugin-fd: startBackupFile\n"); @@ -457,6 +697,11 @@ static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp) return bRC_OK; } +/* When using Incremental dump, all previous dumps are necessary */ +static bRC checkFile(bpContext *ctx, char *fname) +{ + return bRC_OK; +} #ifdef __cplusplus } diff --git a/bacula/src/qt-console/bat.pro.in b/bacula/src/qt-console/bat.pro.in index 192bd872b1..60561d4809 100644 --- a/bacula/src/qt-console/bat.pro.in +++ b/bacula/src/qt-console/bat.pro.in @@ -12,7 +12,7 @@ bins.path = /$(DESTDIR)@sbindir@ bins.files = bat confs.path = /$(DESTDIR)@sysconfdir@ confs.commands = ./install_conf_file -help.path = /$(DESTDIR)@htmldir@ +help.path = /$(DESTDIR)@docdir@ help.files = help/*.html images/status.png images/mail-message-new.png TEMPLATE = app diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index 6ff562b61a..97936b9dc2 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -338,11 +338,11 @@ default_path: get_out: dev->dlock(); + dcr->clear_reserved(); /* If failed and not writing plugin close device */ - if (!ok && dev->num_writers == 0) { + if (!ok && dev->num_writers == 0 && dev->num_reserved() == 0) { generate_plugin_event(jcr, bsdEventDeviceClose, dcr); } - dcr->clear_reserved(); /* * Normally we are blocked, but in at least one error case above * we are not blocked because we unsuccessfully tried changing @@ -539,6 +539,7 @@ bool release_device(DCR *dcr) * there are no writers. It was probably reserved. */ volume_unused(dcr); + generate_plugin_event(jcr, bsdEventDeviceClose, dcr); } Dmsg3(100, "%d writers, %d reserve, dev=%s\n", dev->num_writers, dev->num_reserved(), dev->print_name()); diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index 1368e3903e..b796699b4e 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -748,8 +748,9 @@ static bool terminate_writing_volume(DCR *dcr) if (!dir_create_jobmedia_record(dcr)) { Dmsg0(50, "Error from create JobMedia\n"); dev->dev_errno = EIO; - Jmsg2(dcr->jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), + Mmsg2(dev->errmsg, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), dcr->getVolCatName(), dcr->jcr->Job); + Jmsg(dcr->jcr, M_FATAL, 0, "%s", dev->errmsg); ok = false; } dcr->block->write_failed = true; @@ -779,6 +780,7 @@ static bool terminate_writing_volume(DCR *dcr) } if (!dir_update_volume_info(dcr, false, true)) { + Mmsg(dev->errmsg, _("Error sending Volume info to Director.\n")); ok = false; Dmsg0(50, "Error updating volume info.\n"); } @@ -994,8 +996,9 @@ reread: dev->part <= dev->num_dvd_parts) { Dmsg0(400, "Call dvd_open_next_part\n"); if (dvd_open_next_part(dcr) < 0) { - Jmsg3(dcr->jcr, M_FATAL, 0, _("Unable to open device part=%d %s: ERR=%s\n"), + Mmsg3(dev->errmsg, _("Unable to open device part=%d %s: ERR=%s\n"), dev->part, dev->print_name(), dev->bstrerror()); + Jmsg(dcr->jcr, M_FATAL, 0, "%s", dev->errmsg); dev->dev_errno = EIO; return false; } @@ -1090,7 +1093,8 @@ reread: if (dev->is_tape()) { Dmsg0(250, "BSR for reread; block too big for buffer.\n"); if (!dev->bsr(1)) { - Jmsg(jcr, M_ERROR, 0, "%s", dev->bstrerror()); + Mmsg(dev->errmsg, "%s", dev->bstrerror()); + Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); block->read_len = 0; return false; } diff --git a/bacula/src/stored/butil.c b/bacula/src/stored/butil.c index 8d1f9c33a8..f6385f7d7a 100644 --- a/bacula/src/stored/butil.c +++ b/bacula/src/stored/butil.c @@ -51,23 +51,23 @@ static void my_free_jcr(JCR *jcr); extern char *configfile; #ifdef DEBUG -char *rec_state_to_str(DEV_RECORD *rec) +char *rec_state_bits_to_str(DEV_RECORD *rec) { static char buf[200]; buf[0] = 0; - if (rec->state & REC_NO_HEADER) { + if (rec->state_bits & REC_NO_HEADER) { strcat(buf, _("Nohdr,")); } if (is_partial_record(rec)) { strcat(buf, _("partial,")); } - if (rec->state & REC_BLOCK_EMPTY) { + if (rec->state_bits & REC_BLOCK_EMPTY) { strcat(buf, _("empty,")); } - if (rec->state & REC_NO_MATCH) { + if (rec->state_bits & REC_NO_MATCH) { strcat(buf, _("Nomatch,")); } - if (rec->state & REC_CONTINUATION) { + if (rec->state_bits & REC_CONTINUATION) { strcat(buf, _("cont,")); } if (buf[0]) { diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index 7f8366b613..f06b5cd189 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -122,7 +122,7 @@ bool fixup_device_block_write_error(DCR *dcr, int retries) edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2), bstrftime(dt, sizeof(dt), time(NULL))); - Dmsg0(050, "set_unload\n"); + Dmsg1(050, "set_unload dev=%s\n", dev->print_name()); dev->set_unload(); if (!dcr->mount_next_write_volume()) { free_block(label_blk); @@ -130,7 +130,7 @@ bool fixup_device_block_write_error(DCR *dcr, int retries) dev->dlock(); goto bail_out; } - Dmsg1(050, "must_unload=%d\n", dev->must_unload()); + Dmsg2(050, "must_unload=%d dev=%s\n", dev->must_unload(), dev->print_name()); dev->dlock(); /* lock again */ dev->VolCatInfo.VolCatJobs++; /* increment number of jobs on vol */ diff --git a/bacula/src/stored/label.c b/bacula/src/stored/label.c index bf8bf65120..d5f0043e0b 100644 --- a/bacula/src/stored/label.c +++ b/bacula/src/stored/label.c @@ -215,7 +215,7 @@ int read_dev_volume_label(DCR *dcr) } - if (debug_level >= 10) { + if (debug_level >= 200) { dump_volume_label(dev); } Dmsg0(130, "Leave read_volume_label() VOL_OK\n"); diff --git a/bacula/src/stored/mac.c b/bacula/src/stored/mac.c index 330ea8d2d0..7883c9da65 100644 --- a/bacula/src/stored/mac.c +++ b/bacula/src/stored/mac.c @@ -138,6 +138,20 @@ ok_out: commit_data_spool(jcr->dcr); } + /* + * Don't use time_t for job_elapsed as time_t can be 32 or 64 bits, + * and the subsequent Jmsg() editing will break + */ + int32_t job_elapsed = time(NULL) - jcr->run_time; + + if (job_elapsed <= 0) { + job_elapsed = 1; + } + + Jmsg(jcr, M_INFO, 0, _("Elapsed time=%02d:%02d:%02d, Transfer rate=%s Bytes/second\n"), + job_elapsed / 3600, job_elapsed % 3600 / 60, job_elapsed % 60, + edit_uint64_with_suffix(jcr->JobBytes / job_elapsed, ec1)); + if (ok && dev->is_dvd()) { ok = dvd_close_job(jcr->dcr); /* do DVD cleanup if any */ } diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c index f59bb6ae37..fac100785d 100644 --- a/bacula/src/stored/mount.c +++ b/bacula/src/stored/mount.c @@ -243,7 +243,7 @@ read_volume: * Check that volcatinfo is good */ if (!dev->haveVolCatInfo()) { - Dmsg0(100, "Do not have volcatinfo\n"); + Dmsg0(210, "Do not have volcatinfo\n"); if (!find_a_volume()) { goto mount_next_vol; } @@ -579,7 +579,11 @@ void DCR::do_swapping(bool is_writing) Dmsg2(100, "Vol=%s on dev=%s\n", dev->swap_dev->vol->vol_name, dev->swap_dev->print_name()); } + Dmsg2(100, "Set swap_dev=NULL for dev=%s swap_dev=%s\n", + dev->print_name(), dev->swap_dev->print_name()); dev->swap_dev = NULL; + } else { + Dmsg0(100, "No swap_dev set\n"); } } diff --git a/bacula/src/stored/sd_plugins.c b/bacula/src/stored/sd_plugins.c index 8ea73af96e..39cff87762 100644 --- a/bacula/src/stored/sd_plugins.c +++ b/bacula/src/stored/sd_plugins.c @@ -35,7 +35,7 @@ #include "stored.h" #include "sd_plugins.h" -const int dbglvl = 50; +const int dbglvl = 150; const char *plugin_type = "-sd.so"; @@ -261,7 +261,7 @@ void new_plugins(JCR *jcr) if (jcr->is_job_canceled()) { return; } - /* + /* * If plugins already loaded, just return */ if (jcr->plugin_ctx_list) { diff --git a/bacula/src/stored/vol_mgr.c b/bacula/src/stored/vol_mgr.c index e16e433471..0aae335691 100644 --- a/bacula/src/stored/vol_mgr.c +++ b/bacula/src/stored/vol_mgr.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2011 Free Software Foundation Europe e.V. + Copyright (C) 2000-2012 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. @@ -199,11 +199,11 @@ static void debug_list_volumes(const char *imsg) lock_volumes(); foreach_dlist(vol, vol_list) { if (vol->dev) { - Mmsg(msg, "List %s: %s in_use=%d on device %s\n", imsg, - vol->vol_name, vol->is_in_use(), vol->dev->print_name()); + Mmsg(msg, "List %s: %s in_use=%d swap=%d on device %s\n", imsg, + vol->vol_name, vol->is_in_use(), vol->is_swapping(), vol->dev->print_name()); } else { - Mmsg(msg, "List %s: %s in_use=%d no dev\n", imsg, vol->vol_name, - vol->is_in_use()); + Mmsg(msg, "List %s: %s in_use=%d swap=%d no dev\n", imsg, vol->vol_name, + vol->is_in_use(), vol->is_swapping()); } Dmsg1(dbglvl, "%s", msg.c_str()); } @@ -428,7 +428,7 @@ VOLRES *reserve_volume(DCR *dcr, const char *VolumeName) Dmsg3(dbglvl, "==== Swap vol=%s from dev=%s to %s\n", VolumeName, vol->dev->print_name(), dev->print_name()); free_volume(dev); /* free any volume attached to our drive */ - Dmsg0(50, "set_unload\n"); + Dmsg1(50, "set_unload dev=%s\n", dev->print_name()); dev->set_unload(); /* Unload any volume that is on our drive */ dcr->dev = vol->dev; /* temp point to other dev */ slot = get_autochanger_loaded_slot(dcr); /* get slot on other drive */ @@ -446,9 +446,11 @@ VOLRES *reserve_volume(DCR *dcr, const char *VolumeName) vol->dev->is_busy(), vol->is_swapping(), VolumeName, vol->dev->print_name(), dev->print_name()); if (vol->is_swapping() && dev->swap_dev) { - Dmsg2(dbglvl, "Swap vol=%s dev=%s\n", vol->vol_name, dev->swap_dev->print_name()); + Dmsg3(dbglvl, "Swap failed vol=%s from=%s to dev=%s\n", + vol->vol_name, dev->swap_dev->print_name(), dev->print_name()); } else { - Dmsg1(dbglvl, "swap_dev=%p\n", dev->swap_dev); + Dmsg3(dbglvl, "Swap failed vol=%s from=%p to dev=%s\n", + vol->vol_name, dev->swap_dev, dev->print_name()); } debug_list_volumes("failed swap"); vol = NULL; /* device busy */ @@ -573,10 +575,12 @@ bool volume_unused(DCR *dcr) debug_list_volumes("null vol cannot unreserve_volume"); return false; } + + Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name); + dev->vol->clear_in_use(); + if (dev->vol->is_swapping()) { Dmsg1(dbglvl, "vol_unused: vol being swapped on %s\n", dev->print_name()); - Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name); - dev->vol->clear_in_use(); debug_list_volumes("swapping vol cannot free_volume"); return false; } @@ -589,8 +593,6 @@ bool volume_unused(DCR *dcr) */ Dmsg4(dbglvl, "=== set not reserved vol=%s num_writers=%d dev_reserved=%d dev=%s\n", dev->vol->vol_name, dev->num_writers, dev->num_reserved(), dev->print_name()); - Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name); - dev->vol->clear_in_use(); if (dev->is_tape() || dev->is_autochanger()) { return true; } else { diff --git a/bacula/src/tools/bsmtp.c b/bacula/src/tools/bsmtp.c index 4ca89a22da..d502ead961 100644 --- a/bacula/src/tools/bsmtp.c +++ b/bacula/src/tools/bsmtp.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2001-2009 Free Software Foundation Europe e.V. + Copyright (C) 2001-2012 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. @@ -62,7 +62,6 @@ Note, the original W.Z. Venema smtp.c had no license and no copyright. See: http://archives.neohapsis.com/archives/postfix/2000-05/1520.html - */ #include "bacula.h" diff --git a/bacula/src/version.h b/bacula/src/version.h index e45404adf9..6f0e20b9eb 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ #undef VERSION -#define VERSION "5.2.10" -#define BDATE "28 June 2012" -#define LSMDATE "28Jun12" +#define VERSION "5.2.11" +#define BDATE "18 August 2012" +#define LSMDATE "18Aug12" #define PROG_COPYRIGHT "Copyright (C) %d-2012 Free Software Foundation Europe e.V.\n" #define BYEAR "2012" /* year for copyright messages in progs */ @@ -54,7 +54,7 @@ #define TRACE_FILE 1 /* If this is set stdout will not be closed on startup */ -/* #define DEVELOPER 1 */ +#define DEVELOPER 1 /* adjust DEVELOPER_MODE for status command */ #ifdef DEVELOPER diff --git a/regress/do_all_no_setup b/regress/do_all_no_setup new file mode 100755 index 0000000000..40e8bfe44a --- /dev/null +++ b/regress/do_all_no_setup @@ -0,0 +1,2 @@ +#!/bin/sh +./do_all_tests diff --git a/regress/tests/acl-xattr-test b/regress/tests/acl-xattr-test index d84e4bb503..9e0dfcafc1 100755 --- a/regress/tests/acl-xattr-test +++ b/regress/tests/acl-xattr-test @@ -103,20 +103,20 @@ cp ${cwd}/bin/bconsole $d case `uname -s` in Linux) - setfacl -m d:user:$uid:r-x $d/acl-dir - setfacl -m d:user:root:-wx $d/acl-dir - setfacl -m user:nobody:--- $d/acl-dir - setfacl -m user:nobody:--- $d/bconsole - setfacl -m group:nogroup:--x $d/bconsole + setfacl -m d:user:$uid:r-x $d/acl-dir 2>/dev/null 1>/dev/null + setfacl -m d:user:root:-wx $d/acl-dir 2>/dev/null 1>/dev/null + setfacl -m user:nobody:--- $d/acl-dir 2>/dev/null 1>/dev/null + setfacl -m user:nobody:--- $d/bconsole 2>/dev/null 1>/dev/null + setfacl -m group:nogroup:--x $d/bconsole 2>/dev/null 1>/dev/null cp ${cwd}/bin/bconsole $d/acl-dir cp ${cwd}/bin/bconsole $d/other setfattr -h -n user.bacula.test -v rulez $d/other 2>/dev/null 1>/dev/null setfattr -h -n user.bacula.secondtest -v rulez $d/other 2>/dev/null 1>/dev/null ( cd $cwd/build - getfacl -R acl > $cwd/tmp/org - getfattr -h -n user.bacula.test $d/other > $cwd/tmp/attr.org - getfattr -h -n user.bacula.secondtest $d/other >> $cwd/tmp/attr.org + getfacl -R acl 2>/dev/null > $cwd/tmp/org + getfattr -h -n user.bacula.test $d/other 2>/dev/null > $cwd/tmp/attr.org + getfattr -h -n user.bacula.secondtest $d/other 2>/dev/null >> $cwd/tmp/attr.org ) ;; Darwin) @@ -133,8 +133,8 @@ case `uname -s` in ( cd $cwd/build ls -lde -R acl > $cwd/tmp/org - xattr -p bacula.test $d/other > $cwd/tmp/attr.org - xattr -p bacula.secondtest $d/other >> $cwd/tmp/attr.org + xattr -p bacula.test $d/other 2>/dev/null > $cwd/tmp/attr.org + xattr -p bacula.secondtest $d/other 2>/dev/null >> $cwd/tmp/attr.org ) ;; SunOS) @@ -169,7 +169,7 @@ EOF ) ;; FreeBSD) - setfacl -m d:user:$uid:r-x $d/acl-dir + setfacl -m d:user:$uid:r-x $d/acl-dir setfacl -m d:user:root:-wx $d/acl-dir setfacl -m user:nobody:--- $d/acl-dir setfacl -m user:nobody:--- $d/bconsole @@ -184,8 +184,8 @@ EOF do getfacl $file done > $cwd/tmp/org - getextattr user bacula.test $d/other > $cwd/tmp/attr.org - getextattr user bacula.secondtest $d/other >> $cwd/tmp/attr.org + getextattr user bacula.test $d/other 2>/dev/null > $cwd/tmp/attr.org + getextattr user bacula.secondtest $d/other 2>/dev/null >> $cwd/tmp/attr.org ) ;; NetBSD) @@ -208,10 +208,10 @@ cat <${cwd}/tmp/bconcmds @$out /dev/null messages @$out ${cwd}/tmp/log1.out -label volume=TestVolume001 storage=File pool=File +label volume=TestVolume001 storage=File1 pool=File slot=1 drive=0 setdebug level=400 trace=1 client setdebug level=300 trace=1 director -setdebug level=300 trace=1 storage +setdebug level=300 trace=1 storage=File1 run job=$JobName yes wait messages @@ -227,15 +227,15 @@ quit END_OF_DATA run_bacula -check_for_zombie_jobs storage=File +check_for_zombie_jobs storage=File1 stop_bacula case `uname -s` in Linux) ( cd $cwd/tmp/bacula-restores/$cwd/build getfacl -R acl > $cwd/tmp/new - getfattr -h -n user.bacula.test $d/other > $cwd/tmp/attr.new - getfattr -h -n user.bacula.secondtest $d/other >> $cwd/tmp/attr.new + getfattr -h -n user.bacula.test $d/other 2>/dev/null > $cwd/tmp/attr.new + getfattr -h -n user.bacula.secondtest $d/other 2>/dev/null >> $cwd/tmp/attr.new ) ;; Darwin) -- 2.39.5