From: Eric Bollengier Date: Sun, 22 Apr 2007 18:16:43 +0000 (+0000) Subject: ebl Commit file relocation X-Git-Tag: Release-7.0.0~6534 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=403736c5990d6411296a3c460f391947a38025e8;p=bacula%2Fbacula ebl Commit file relocation git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@4594 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/dird/dird.h b/bacula/src/dird/dird.h index c0b5393e92..baab1821c5 100644 --- a/bacula/src/dird/dird.h +++ b/bacula/src/dird/dird.h @@ -34,6 +34,7 @@ */ #include "lib/runscript.h" +#include "lib/breg.h" #include "dird_conf.h" #define DIRECTOR_DAEMON 1 diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index c18eed8552..43fe648a4e 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -268,6 +268,10 @@ RES_ITEM job_items[] = { {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0}, /* Root of where to restore files */ {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0}, + {"whereuseregexp", store_bool, ITEM(res_job.where_use_regexp), 0, 0, 0}, + {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0}, + {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0}, + {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0}, /* Where to find bootstrap during restore */ {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0}, /* Where to write bootstrap file during backup */ @@ -611,6 +615,9 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm if (res->res_job.RestoreWhere) { sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere)); } + if (res->res_job.where_use_regexp) { + sendit(sock, _(" --> RWhere=%u\n"), res->res_job.where_use_regexp); + } if (res->res_job.RestoreBootstrap) { sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap)); } @@ -1143,6 +1150,15 @@ void free_resource(RES *sres, int type) if (res->res_job.RestoreWhere) { free(res->res_job.RestoreWhere); } + if (res->res_job.strip_prefix) { + free(res->res_job.strip_prefix); + } + if (res->res_job.add_prefix) { + free(res->res_job.add_prefix); + } + if (res->res_job.add_suffix) { + free(res->res_job.add_suffix); + } if (res->res_job.RestoreBootstrap) { free(res->res_job.RestoreBootstrap); } @@ -1299,6 +1315,25 @@ void save_resource(int type, RES_ITEM *items, int pass) res->res_job.jobdefs = res_all.res_job.jobdefs; res->res_job.run_cmds = res_all.res_job.run_cmds; res->res_job.RunScripts = res_all.res_job.RunScripts; + if (res->res_job.strip_prefix || + res->res_job.add_suffix || + res->res_job.add_prefix) + { + if (res->res_job.RestoreWhere) { + free(res->res_job.RestoreWhere); + } + int len = bregexp_get_build_where_size(res->res_job.strip_prefix, + res->res_job.add_prefix, + res->res_job.add_suffix); + res->res_job.RestoreWhere = (char *) bmalloc (len * sizeof(char)); + bregexp_build_where(res->res_job.RestoreWhere, len, + res->res_job.strip_prefix, + res->res_job.add_prefix, + res->res_job.add_suffix); + res->res_job.where_use_regexp = true; + + /* TODO: test bregexp */ + } break; case R_COUNTER: if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) { diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 0bb0455158..0364f5b5fe 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -356,6 +356,10 @@ public: int Priority; /* Job priority */ int RestoreJobId; /* What -- JobId to restore */ char *RestoreWhere; /* Where on disk to restore -- directory */ + char *strip_prefix; /* remove prefix from filename */ + char *add_prefix; /* add prefix to filename */ + char *add_suffix; /* add suffix to filename -- .old */ + bool where_use_regexp; /* true if RestoreWhere is a BREGEXP */ char *RestoreBootstrap; /* Bootstrap file */ alist *RunScripts; /* Run {client} program {after|before} Job */ union { diff --git a/bacula/src/dird/restore.c b/bacula/src/dird/restore.c index 186e665580..cb6eed17cd 100644 --- a/bacula/src/dird/restore.c +++ b/bacula/src/dird/restore.c @@ -50,8 +50,9 @@ #include "dird.h" /* Commands sent to File daemon */ -static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n"; -static char storaddr[] = "storage address=%s port=%d ssl=0\n"; +static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n"; +static char restorecmdR[] = "restore replace=%c prelinks=%d rwhere=%s\n"; +static char storaddr[] = "storage address=%s port=%d ssl=0\n"; /* Responses received from File daemon */ static char OKrestore[] = "2000 OK restore\n"; @@ -172,7 +173,7 @@ bool do_restore(JCR *jcr) } /* Send restore command */ - char replace, *where; + char replace, *where, *cmd; char empty = '\0'; if (jcr->replace != 0) { @@ -189,9 +190,17 @@ bool do_restore(JCR *jcr) } else { where = ∅ /* None */ } + jcr->prefix_links = jcr->job->PrefixLinks; + + if (jcr->where_use_regexp) { + cmd = restorecmdR; + } else { + cmd = restorecmd; + } + bash_spaces(where); - bnet_fsend(fd, restorecmd, replace, jcr->prefix_links, where); + bnet_fsend(fd, cmd, replace, jcr->prefix_links, where); unbash_spaces(where); if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) { diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index b3ec5f4206..3c2579a966 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -44,7 +44,6 @@ #include "bacula.h" #include "dird.h" - /* Imported functions */ extern void print_bsr(UAContext *ua, RBSR *bsr); @@ -83,6 +82,9 @@ int restore_cmd(UAContext *ua, const char *cmd) JCR *jcr = ua->jcr; char *escaped_bsr_name = NULL; char *escaped_where_name = NULL; + bool where_use_regexp = false; + char *strip_prefix, *add_prefix, *add_suffix, *regexp; + strip_prefix = add_prefix = add_suffix = regexp = NULL; memset(&rx, 0, sizeof(rx)); rx.path = get_pool_memory(PM_FNAME); @@ -94,6 +96,45 @@ int restore_cmd(UAContext *ua, const char *cmd) i = find_arg_with_value(ua, "where"); if (i >= 0) { rx.where = ua->argv[i]; + } + + i = find_arg_with_value(ua, "strip_prefix"); + if (i >= 0) { + strip_prefix = ua->argv[i]; + } + + i = find_arg_with_value(ua, "add_prefix"); + if (i >= 0) { + add_prefix = ua->argv[i]; + } + + i = find_arg_with_value(ua, "add_suffix"); + if (i >= 0) { + add_suffix = ua->argv[i]; + } + + i = find_arg(ua, "where_use_regexp"); + if (i >= 0) { + where_use_regexp = true; + } + + i = find_arg_with_value(ua, "rwhere"); + if (i >= 0) { + where_use_regexp = true; + rx.where = ua->argv[i]; + } + + if (strip_prefix || add_suffix || add_prefix) { + int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix); + regexp = (char *) bmalloc (len * sizeof(char)); + + bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix); + where_use_regexp = true; + + rx.where = regexp; + } + + if (rx.where) { if (!acl_access_ok(ua, Where_ACL, rx.where)) { ua->error_msg(_("\"where\" specification not authorized.\n")); goto bail_out; @@ -195,9 +236,10 @@ int restore_cmd(UAContext *ua, const char *cmd) Mmsg(ua->cmd, "run job=\"%s\" client=\"%s\" storage=\"%s\" bootstrap=\"%s\"" - " where=\"%s\" files=%d catalog=\"%s\"", + " %swhere=\"%s\" files=%d catalog=\"%s\"", job->name(), rx.ClientName, rx.store?rx.store->name():"", escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, + where_use_regexp ? "r" : "", escaped_where_name ? escaped_where_name : rx.where, rx.selected_files, ua->catalog->name()); } else { @@ -216,6 +258,10 @@ int restore_cmd(UAContext *ua, const char *cmd) if (escaped_where_name != NULL) { bfree(escaped_where_name); } + + if (regexp) { + bfree(regexp); + } if (find_arg(ua, NT_("yes")) > 0) { pm_strcat(ua->cmd, " yes"); /* pass it on to the run command */ @@ -235,6 +281,10 @@ bail_out: bfree(escaped_where_name); } + if (regexp) { + bfree(regexp); + } + free_rx(&rx); return 0; @@ -333,23 +383,28 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx) const char *kw[] = { /* These keywords are handled in a for loop */ - "jobid", /* 0 */ - "current", /* 1 */ - "before", /* 2 */ - "file", /* 3 */ - "directory", /* 4 */ - "select", /* 5 */ - "pool", /* 6 */ - "all", /* 7 */ + "jobid", /* 0 */ + "current", /* 1 */ + "before", /* 2 */ + "file", /* 3 */ + "directory", /* 4 */ + "select", /* 5 */ + "pool", /* 6 */ + "all", /* 7 */ /* The keyword below are handled by individual arg lookups */ - "client", /* 8 */ - "storage", /* 9 */ - "fileset", /* 10 */ - "where", /* 11 */ - "yes", /* 12 */ - "bootstrap", /* 13 */ - "done", /* 14 */ + "client", /* 8 */ + "storage", /* 9 */ + "fileset", /* 10 */ + "where", /* 11 */ + "yes", /* 12 */ + "bootstrap", /* 13 */ + "done", /* 14 */ + "strip_prefix", /* 15 */ + "add_prefix", /* 16 */ + "add_suffix", /* 17 */ + "where_use_regexp",/* 18 */ + "rwhere", /* 19 like where + where_use_regexp */ NULL }; diff --git a/bacula/src/dird/ua_run.c b/bacula/src/dird/ua_run.c index 9ddb351f55..914b826617 100644 --- a/bacula/src/dird/ua_run.c +++ b/bacula/src/dird/ua_run.c @@ -41,6 +41,7 @@ static void select_job_level(UAContext *ua, JCR *jcr); static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, char *verify_list, char *jid, const char *replace); +static void select_where_regexp(UAContext *ua, JCR *jcr); /* Imported variables */ @@ -71,6 +72,7 @@ int run_cmd(UAContext *ua, const char *cmd) int Priority = 0; int i, j, opt, files = 0; bool kw_ok; + bool where_use_regexp = false; JOB *job = NULL; JOB *verify_job = NULL; JOB *previous_job = NULL; @@ -87,7 +89,7 @@ int run_cmd(UAContext *ua, const char *cmd) "level", /* 5 */ "storage", /* 6 */ "sd", /* 7 */ - "pool", /* 8 */ + "rwhere", /* 8 where string as a bregexp */ "where", /* 9 */ "bootstrap", /* 10 */ "replace", /* 11 */ @@ -101,6 +103,7 @@ int run_cmd(UAContext *ua, const char *cmd) "cloned", /* 19 cloned */ "verifylist", /* 20 verify output list */ "migrationjob", /* 21 migration job name */ + "pool", /* 22 */ NULL}; #define YES_POS 14 @@ -188,15 +191,11 @@ int run_cmd(UAContext *ua, const char *cmd) store_name = ua->argv[i]; kw_ok = true; break; - case 8: /* pool */ - if (pool_name) { - ua->send_msg(_("Pool specified twice.\n")); - return 0; - } - pool_name = ua->argv[i]; - kw_ok = true; - break; + case 8: /* rwhere */ case 9: /* where */ + /* TODO: this is ugly ... */ + where_use_regexp = (j == 9)?false:true; /* rwhere or where ? */ + if (where) { ua->send_msg(_("Where specified twice.\n")); return 0; @@ -287,7 +286,14 @@ int run_cmd(UAContext *ua, const char *cmd) previous_job_name = ua->argv[i]; kw_ok = true; break; - + case 22: /* pool */ + if (pool_name) { + ua->send_msg(_("Pool specified twice.\n")); + return 0; + } + pool_name = ua->argv[i]; + kw_ok = true; + break; default: break; @@ -478,6 +484,7 @@ int run_cmd(UAContext *ua, const char *cmd) free(jcr->where); } jcr->where = bstrdup(where); + jcr->where_use_regexp = where_use_regexp; } if (when) { @@ -595,8 +602,9 @@ try_again: } else if (jcr->JobType == JT_RESTORE) { add_prompt(ua, _("Bootstrap")); /* 7 */ add_prompt(ua, _("Where")); /* 8 */ - add_prompt(ua, _("Replace")); /* 9 */ - add_prompt(ua, _("JobId")); /* 10 */ + add_prompt(ua, _("File Relocation"));/* 9 */ + add_prompt(ua, _("Replace")); /* 10 */ + add_prompt(ua, _("JobId")); /* 11 */ } switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) { case 0: @@ -719,8 +727,13 @@ try_again: ua->cmd[0] = 0; } jcr->where = bstrdup(ua->cmd); + jcr->where_use_regexp = false; goto try_again; - case 9: + case 9: + /* File relocation */ + select_where_regexp(ua, jcr); + goto try_again; + case 10: /* Replace */ start_prompt(ua, _("Replace:\n")); for (i=0; ReplaceOptions[i].name; i++) { @@ -731,7 +744,7 @@ try_again: jcr->replace = ReplaceOptions[opt].token; } goto try_again; - case 10: + case 11: /* JobId */ jid = NULL; /* force reprompt */ jcr->RestoreJobId = 0; @@ -775,6 +788,134 @@ bail_out: return 0; /* do not run */ } +static void select_where_regexp(UAContext *ua, JCR *jcr) +{ + alist *regs; + char *strip_prefix, *add_prefix, *add_suffix, *rwhere; + strip_prefix = add_suffix = rwhere = add_prefix = NULL; + +try_again_reg: + ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"), + NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix)); + + start_prompt(ua, _("This will replace your current Where value\n")); + add_prompt(ua, _("Strip prefix")); /* 0 */ + add_prompt(ua, _("Add prefix")); /* 1 */ + add_prompt(ua, _("Add file suffix")); /* 2 */ + add_prompt(ua, _("Enter a regexp")); /* 3 */ + add_prompt(ua, _("Test filename manipulation")); /* 4 */ + add_prompt(ua, _("Use this ?")); /* 5 */ + + switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) { + case 0: + /* Strip prefix */ + if (get_cmd(ua, _("Please enter path prefix to strip: "))) { + if (strip_prefix) bfree(strip_prefix); + strip_prefix = bstrdup(ua->cmd); + } + + goto try_again_reg; + case 1: + /* Add prefix */ + if (get_cmd(ua, _("Please enter path prefix to add (/ for none): "))) { + if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') { + ua->cmd[0] = 0; + } + + if (add_prefix) bfree(add_prefix); + add_prefix = bstrdup(ua->cmd); + } + goto try_again_reg; + case 2: + /* Add suffix */ + if (get_cmd(ua, _("Please enter file suffix to add: "))) { + if (add_suffix) bfree(add_suffix); + add_suffix = bstrdup(ua->cmd); + } + goto try_again_reg; + case 3: + /* Add rwhere */ + if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) { + if (rwhere) bfree(rwhere); + rwhere = bstrdup(ua->cmd); + } + + goto try_again_reg; + case 4: + /* Test regexp */ + char *result; + char *regexp; + + if (rwhere && rwhere[0] != '\0') { + regs = get_bregexps(rwhere); + ua->send_msg(_("rwhere=%s\n"), NPRT(rwhere)); + } else { + int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix); + regexp = (char *) bmalloc (len * sizeof(char)); + bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix); + regs = get_bregexps(regexp); + ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"), + NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp)); + + bfree(regexp); + } + + if (!regs) { + ua->send_msg(_("Cannot use your regexp\n")); + goto try_again_reg; + } + + while (get_cmd(ua, _("Please enter filename to test: "))) { + apply_bregexps(ua->cmd, regs, &result); + ua->send_msg(_("%s -> %s\n"), ua->cmd, result); + } + free_bregexps(regs); + delete regs; + goto try_again_reg; + + case 5: + /* OK */ + break; + case -1: /* error or cancel */ + goto bail_out_reg; + default: + goto try_again_reg; + } + + /* replace the existing where */ + if (jcr->where) { + bfree(jcr->where); + jcr->where = NULL; + } + + if (rwhere) { + jcr->where = bstrdup(rwhere); + } else if (strip_prefix || add_prefix || add_suffix) { + int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix); + jcr->where = (char *) bmalloc(len*sizeof(char)); + bregexp_build_where(jcr->where, len, strip_prefix, add_prefix, add_suffix); + } + + regs = get_bregexps(jcr->where); + if (regs) { + free_bregexps(regs); + delete regs; + jcr->where_use_regexp = true; + } else { + if (jcr->where) { + bfree(jcr->where); + jcr->where = NULL; + } + ua->send_msg(_("Cannot use your regexp.\n")); + } + +bail_out_reg: + if (strip_prefix) bfree(strip_prefix); + if (add_prefix) bfree(add_prefix); + if (add_suffix) bfree(add_suffix); + if (rwhere) bfree(rwhere); +} + static void select_job_level(UAContext *ua, JCR *jcr) { if (jcr->JobType == JT_BACKUP) { @@ -938,7 +1079,7 @@ static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, char *veri ua->send_msg(_("Run Restore job\n" "JobName: %s\n" "Bootstrap: %s\n" - "Where: %s\n" + "%s %s\n" /* Where or RWhere */ "Replace: %s\n" "FileSet: %s\n" "Client: %s\n" @@ -948,6 +1089,7 @@ static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, char *veri "Priority: %d\n"), job->name(), NPRT(jcr->RestoreBootstrap), + jcr->where_use_regexp?"RWhere:":"Where: ", jcr->where?jcr->where:NPRT(job->RestoreWhere), replace, jcr->fileset->name(), @@ -961,7 +1103,7 @@ static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, char *veri ua->send_msg(_("Run Restore job\n" "JobName: %s\n" "Bootstrap: %s\n" - "Where: %s\n" + "%s %s\n" /* Where or RWhere */ "Replace: %s\n" "Client: %s\n" "Storage: %s\n" @@ -971,6 +1113,7 @@ static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, char *veri "Priority: %d\n"), job->name(), NPRT(jcr->RestoreBootstrap), + jcr->where_use_regexp?"RWhere:":"Where: ", jcr->where?jcr->where:NPRT(job->RestoreWhere), replace, jcr->client->name(), diff --git a/bacula/src/filed/filed.h b/bacula/src/filed/filed.h index 67ee9b3c18..56cc79c431 100644 --- a/bacula/src/filed/filed.h +++ b/bacula/src/filed/filed.h @@ -40,6 +40,7 @@ #include "acl.h" #include "protos.h" /* file daemon prototypes */ #include "lib/runscript.h" +#include "lib/breg.h" #ifdef HAVE_LIBZ #include /* compression headers */ #else diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index 13b094ec26..55ec529734 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -115,6 +115,7 @@ static char storaddr[] = "storage address=%s port=%d ssl=%d"; static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n"; static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n"; static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n"; +static char restorecmdR[] = "restore replace=%c prelinks=%d rwhere=%s\n"; static char verifycmd[] = "verify level=%30s"; static char estimatecmd[] = "estimate listing=%d"; static char runbefore[] = "RunBeforeJob %s"; @@ -1586,12 +1587,15 @@ static int restore_cmd(JCR *jcr) *where = 0; if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) { - if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) { - pm_strcpy(jcr->errmsg, dir->msg); - Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg); - return 0; + if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, where) != 3){ + if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) { + pm_strcpy(jcr->errmsg, dir->msg); + Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg); + return 0; + } + *where = 0; } - *where = 0; + jcr->where_use_regexp = true; } /* Turn / into nothing */ if (IsPathSeparator(where[0]) && where[1] == '\0') { @@ -1601,6 +1605,15 @@ static int restore_cmd(JCR *jcr) Dmsg2(150, "Got replace %c, where=%s\n", replace, where); unbash_spaces(where); jcr->where = bstrdup(where); + + if (jcr->where_use_regexp) { + jcr->where_bregexp = get_bregexps(jcr->where); + if (!jcr->where_bregexp) { + Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), jcr->where); + free_pool_memory(where); + return 0; + } + } free_pool_memory(where); jcr->replace = replace; jcr->prefix_links = prefix_links; diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index ff06afc9b2..c07e305e8a 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -173,6 +173,8 @@ public: MSGS *jcr_msgs; /* Copy of message resource -- actually used */ uint32_t ClientId; /* Client associated with Job */ char *where; /* prefix to restore files to */ + bool where_use_regexp; /* True if where is a bregexp */ + alist *where_bregexp; /* BREGEXP alist for path manipulation */ int cached_pnl; /* cached path length */ POOLMEM *cached_path; /* cached path */ bool prefix_links; /* Prefix links with Where path */ diff --git a/bacula/src/lib/Makefile.in b/bacula/src/lib/Makefile.in index 683eed556b..166fba57d8 100644 --- a/bacula/src/lib/Makefile.in +++ b/bacula/src/lib/Makefile.in @@ -32,7 +32,7 @@ LIBSRCS = attr.c base64.c berrno.c bsys.c bget_msg.c \ res.c rwlock.c scan.c serial.c sha1.c \ signal.c smartall.c rblist.c tls.c tree.c \ util.c var.c watchdog.c workq.c btimers.c \ - address_conf.c pythonlib.c + address_conf.c pythonlib.c breg.c LIBOBJS = attr.o base64.o berrno.o bsys.o bget_msg.o \ @@ -45,7 +45,7 @@ LIBOBJS = attr.o base64.o berrno.o bsys.o bget_msg.o \ res.o rwlock.o scan.o serial.o sha1.o \ signal.o smartall.o rblist.o tls.o tree.o \ util.o var.o watchdog.o workq.o btimers.o \ - address_conf.o pythonlib.o + address_conf.o pythonlib.o breg.o EXTRAOBJS = @OBJLIST@ diff --git a/bacula/src/lib/attr.c b/bacula/src/lib/attr.c index 47a5ee1b9e..138dad8ad4 100644 --- a/bacula/src/lib/attr.c +++ b/bacula/src/lib/attr.c @@ -35,7 +35,7 @@ #include "bacula.h" #include "jcr.h" - +#include "lib/breg.h" ATTR *new_attr() { @@ -148,9 +148,30 @@ void build_attr_output_fnames(JCR *jcr, ATTR *attr) * every filename if a prefix is supplied. * */ + if (jcr->where[0] == 0) { pm_strcpy(attr->ofname, attr->fname); pm_strcpy(attr->olname, attr->lname); + + } else if (jcr->where_bregexp) { + char *ret; + apply_bregexps(attr->fname, jcr->where_bregexp, &ret); + pm_strcpy(attr->ofname, ret); + + if (attr->type == FT_LNKSAVED || attr->type == FT_LNK) { + /* Always add prefix to hard links (FT_LNKSAVED) and + * on user request to soft links + */ + + if ((attr->type == FT_LNKSAVED || jcr->prefix_links)) { + apply_bregexps(attr->lname, jcr->where_bregexp, &ret); + pm_strcpy(attr->olname, ret); + + } else { + pm_strcpy(attr->olname, attr->lname); + } + } + } else { const char *fn; int wherelen = strlen(jcr->where); diff --git a/bacula/src/lib/breg.c b/bacula/src/lib/breg.c new file mode 100644 index 0000000000..6c9a4ef560 --- /dev/null +++ b/bacula/src/lib/breg.c @@ -0,0 +1,458 @@ +/* + * Manipulation routines for BREGEXP list + * + * Eric Bollengier, March 2007 + * + * Version $Id$ + * + */ +/* + BaculaÂ® - The Network Backup Solution + + Copyright (C) 2006-2006 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 two of the GNU General Public + License as published by the Free Software Foundation plus additions + that are 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 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 John Walker. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 ZÃ¼rich, + Switzerland, email:ftf@fsfeurope.org. +*/ + + +#include "bacula.h" + +#include "breg.h" +#include "mem_pool.h" + +BREGEXP *new_bregexp(const char *motif) +{ + Dmsg0(500, "bregexp: creating new bregexp object\n"); + BREGEXP *self = (BREGEXP *)bmalloc(sizeof(BREGEXP)); + memset(self, 0, sizeof(BREGEXP)); + + if (!self->extract_regexp(motif)) { + Dmsg0(100, "bregexp: extract_regexp error\n"); + free_bregexp(self); + return NULL; + } + + self->result = get_pool_memory(PM_FNAME); + self->result[0] = '\0'; + +#ifdef HAVE_REGEX_H + /* TODO: que devient cette memoire... */ + self->_regs_match = (int *) bmalloc (2*RE_NREGS * sizeof(int)); + + self->regs.num_regs = RE_NREGS; + self->regs.start = self->_regs_match; + self->regs.end = self->_regs_match+(RE_NREGS * sizeof(int)); +#endif + + return self; +} + +void free_bregexp(BREGEXP *self) +{ + Dmsg0(500, "bregexp: freeing BREGEXP object\n"); + + if (!self) { + return; + } + + if (self->expr) { + bfree(self->expr); + } + if (self->result) { + free_pool_memory(self->result); + } + if (self->_regs_match) { + bfree(self->_regs_match); + } + + regfree(&self->preg); + bfree(self); +} + +/* Free a bregexps alist + */ +void free_bregexps(alist *bregexps) +{ + Dmsg0(500, "bregexp: freeing all BREGEXP object\n"); + + BREGEXP *elt; + foreach_alist(elt, bregexps) { + free_bregexp(elt); + } +} + +/* Apply all regexps to fname + */ +bool apply_bregexps(const char *fname, alist *bregexps, char **result) +{ + BREGEXP *elt; + bool ok=false; + + char *ret = (char *) fname; + foreach_alist(elt, bregexps) { + ret = elt->replace(ret); + ok = ok || elt->success; + } + Dmsg2(500, "bregexp: fname=%s ret=%s\n", fname, ret); + + *result = ret; + return ok; +} + +/* return an alist of BREGEXP or return NULL if it's not a + * where=!tmp!opt!ig,!temp!opt!i + */ +alist *get_bregexps(const char *where) +{ + char *p = (char *)where; + alist *list = New(alist(10, not_owned_by_alist)); + BREGEXP *reg; + + reg = new_bregexp(p); + + while(reg) { + p = reg->eor; + list->append(reg); + reg = new_bregexp(p); + } + + if (list->size()) { + return list; + } else { + delete list; + return NULL; + } +} + +bool BREGEXP::extract_regexp(const char *motif) +{ + if ( !motif ) { + return false; + } + + char sep = motif[0]; + + if (!(sep == '!' || + sep == ':' || + sep == ';' || + sep == '|' || + sep == ',' || + sep == '&' || + sep == '%' || + sep == '=' || + sep == '~' || + sep == '/' || + sep == '#' )) + { + return false; + } + + char *search = (char *) motif + 1; + int options = REG_EXTENDED | REG_NEWLINE; + bool ok = false; + + /* extract 1st part */ + char *dest = expr = bstrdup(motif); + + while (*search && !ok) { + if (search[0] == '\\' && search[1] == sep) { + *dest++ = *++search; /* we skip separator */ + + } else if (search[0] == '\\' && search[1] == '\\') { + *dest++ = *++search; /* we skip the second \ */ + + } else if (*search == sep) { /* we found end of expression */ + *dest++ = '\0'; + + if (subst) { /* already have found motif */ + ok = true; + + } else { + *dest++ = *++search; /* we skip separator */ + subst = dest; /* get replaced string */ + } + + } else { + *dest++ = *search++; + } + } + *dest = '\0'; /* in case of */ + + if (!ok || !subst) { + /* bad regexp */ + return false; + } + + ok = false; + /* find options */ + while (*search && !ok) { + if (*search == 'i') { + options |= REG_ICASE; + + } else if (*search == 'g') { + /* recherche multiple*/ + + } else if (*search == sep) { + /* skip separator */ + + } else { /* end of options */ + ok = true; + } + search++; + } + + int rc = regcomp(&preg, expr, options); + if (rc != 0) { + char prbuf[500]; + regerror(rc, &preg, prbuf, sizeof(prbuf)); + Dmsg1(100, "bregexp: compile error: %s\n", prbuf); + return false; + } + + eor = search; /* useful to find the next regexp in where */ + + return true; +} + +#ifndef HAVE_REGEX_H + #define BREGEX_CAST unsigned +#else + #define BREGEX_CAST const +#endif + +/* return regexp->result */ +char *BREGEXP::replace(const char *fname) +{ + success = false; /* use this.success to known if it's ok */ + int flen = strlen(fname); +#ifndef HAVE_REGEX_H + int i; + check_pool_memory_size(lcase, flen); + for(i=0; fname[i] ; i++) { + lcase[i] = tolower(fname[i]); + } + lcase[i] = '\0'; + int rc = re_search(&preg, (BREGEX_CAST char*) lcase, flen, 0, flen, ®s); +#else + int rc = re_search(&preg, (BREGEX_CAST char*) fname, flen, 0, flen, ®s); +#endif + + if (rc < 0) { + Dmsg0(500, "bregexp: regex mismatch\n"); + return return_fname(fname, flen); + } + + int len = compute_dest_len(fname, ®s); + + if (len) { + result = check_pool_memory_size(result, len); + edit_subst(fname, ®s); + success = true; + Dmsg2(500, "bregexp: len = %i, result_len = %i\n", len, strlen(result)); + + } else { /* error in substitution */ + Dmsg0(100, "bregexp: error in substitution\n"); + return return_fname(fname, flen); + } + + return result; +} + +char *BREGEXP::return_fname(const char *fname, int len) +{ + result = check_pool_memory_size(result, len+1); + strcpy(result,fname); + return result; +} + +int BREGEXP::compute_dest_len(const char *fname, struct re_registers *regs) +{ + int len=0; + char *p; + char *psubst = subst; + int no; + + if (!fname || !regs) { + return 0; + } + + /* match failed ? */ + if (regs->start[0] < 0) { + return 0; + } + + for (p = psubst++; *p ; p = psubst++) { + /* match $1 \1 back references */ + if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) { + no = *psubst++ - '0'; + + /* we check if the back reference exists */ + /* references can not match if we are using (..)? */ + + if (regs->start[no] >= 0 && regs->end[no] >= 0) { + len += regs->end[no] - regs->start[no]; + } + + } else { + len++; + } + } + + /* $0 is replaced by subst */ + len -= regs->end[0] - regs->start[0]; + len += strlen(fname) + 1; + + return len; +} + +char *BREGEXP::edit_subst(const char *fname, struct re_registers *regs) +{ + int i; + char *p; + char *psubst = subst; + int no; + int len; + + /* il faut recopier fname dans dest + * on recopie le debut fname -> regs->start[0] + */ + + for (i = 0; i < regs->start[0] ; i++) { + result[i] = fname[i]; + } + + /* on recopie le motif de remplacement (avec tous les $x) */ + + for (p = psubst++; *p ; p = psubst++) { + /* match $1 \1 back references */ + if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) { + no = *psubst++ - '0'; + + /* have a back reference ? */ + if (regs->start[no] >= 0 && regs->end[no] >= 0) { + len = regs->end[no] - regs->start[no]; + bstrncpy(result + i, fname + regs->start[no], len + 1); + i += len ; + } + + } else { + result[i++] = *p; + } + } + + /* we copy what is out of the match */ + strcpy(result + i, fname + regs->end[0]); + + return result; +} + +/* escape sep char and \ + * dest must be long enough (src*2+1) + * return end of the string */ +char *bregexp_escape_string(char *dest, char *src, char sep) +{ + char *ret = dest; + while (*src) + { + if (*src == sep) { + *dest++ = '\\'; + } else if (*src == '\\') { + *dest++ = '\\'; + } + *dest++ = *src++; + } + *dest = '\0'; + + return ret; +} + +static char regexp_sep = '!'; +static char *str_strip_prefix = "!%s!!i"; +static char *str_add_prefix = "!^!%s!"; +static char *str_add_suffix = "!([^/])$!$1%s!"; + +int bregexp_get_build_where_size(char *strip_prefix, + char *add_prefix, + char *add_suffix) +{ + int str_size = ((strip_prefix?strlen(strip_prefix)+strlen(str_strip_prefix):0) + + (add_prefix?strlen(add_prefix)+strlen(str_add_prefix) :0) + + (add_suffix?strlen(add_suffix)+strlen(str_add_suffix) :0) ) + /* escape + 3*, + \0 */ + * 2 + 3 + 1; + + Dmsg1(1, "bregexp_get_build_where_size = %i\n", str_size); + return str_size; +} + +/* build a regexp string with user arguments + * Usage : + * + * int len = bregexp_get_build_where_size(a,b,c) ; + * char *dest = (char *) bmalloc (len * sizeof(char)); + * bregexp_build_where(dest, len, a, b, c); + * bfree(dest); + * + */ +char *bregexp_build_where(char *dest, int str_size, + char *strip_prefix, + char *add_prefix, + char *add_suffix) +{ + int len=0; + + POOLMEM *str_tmp = get_memory(str_size); + + *str_tmp = *dest = '\0'; + + if (strip_prefix) { + len += bsnprintf(dest, str_size - len, str_strip_prefix, + bregexp_escape_string(str_tmp, strip_prefix, regexp_sep)); + } + + if (add_suffix) { + if (len) dest[len++] = ','; + + len += bsnprintf(dest + len, str_size - len, str_add_suffix, + bregexp_escape_string(str_tmp, add_suffix, regexp_sep)); + } + + if (add_prefix) { + if (len) dest[len++] = ','; + + len += bsnprintf(dest + len, str_size - len, str_add_prefix, + bregexp_escape_string(str_tmp, add_prefix, regexp_sep)); + } + + free_pool_memory(str_tmp); + + return dest; +} + + +void BREGEXP::debug() +{ + printf("expr=[%s]\n", expr); + printf("subst=[%s]\n", subst); + printf("result=%s\n", NPRT(result)); +} diff --git a/bacula/src/lib/breg.h b/bacula/src/lib/breg.h new file mode 100644 index 0000000000..fa639f17a8 --- /dev/null +++ b/bacula/src/lib/breg.h @@ -0,0 +1,120 @@ +/* + * Bacula BREGEXP Structure definition for FileDaemon + * Eric Bollengier March 2007 + * Version $Id$ + */ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2006-2006 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 two of the GNU General Public + License as published by the Free Software Foundation plus additions + that are 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 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 John Walker. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ + + +#ifndef __BREG_H_ +#define __BREG_H_ 1 + +//#undef HAVE_REGEX_H + +#ifndef HAVE_REGEX_H +#include "bregex.h" +#else +#include +#endif + +/* Usage: + * + * #include "lib/breg.h" + * + * BREGEXP *breg = new_bregexp("!/prod!/test!"); + * char *filename = breg->replace("/prod/data.dat"); + * or + * char *filename = breg->result; + * free_bregexp(breg); + */ + +/* + * Structure for BREGEXP ressource + */ +class BREGEXP { +public: + POOLMEM *result; /* match result */ + bool success; /* match is ok */ + + char *replace(const char *fname); /* return this.result */ + void debug(); + + /* private */ + POOLMEM *expr; /* search epression */ + POOLMEM *subst; /* substitution */ + POOLMEM *lcase; /* fname in lower case when using bregexp.c */ + regex_t preg; /* regex_t result of regcomp() */ + struct re_registers regs; /* contains match */ + char *eor; /* end of regexp in expr */ + + int *_regs_match; + + char *return_fname(const char *fname, int len); /* return fname as result */ + char *edit_subst(const char *fname, struct re_registers *regs); + int compute_dest_len(const char *fname, struct re_registers *regs); + bool extract_regexp(const char *motif); +}; + +/* create new BREGEXP and compile regex_t */ +BREGEXP *new_bregexp(const char *motif); + +/* launch each bregexp on filename */ +int run_bregexp(alist *bregexps, const char *fname); + +/* free BREGEXP (and all POOLMEM) */ +void free_bregexp(BREGEXP *script); + +/* fill an alist with BREGEXP from where */ +alist *get_bregexps(const char *where); + +/* apply every regexps from the alist */ +bool apply_bregexps(const char *fname, alist *bregexps, char **result); + +/* foreach_alist free RUNSCRIPT */ +void free_bregexps(alist *bregexps); /* you have to free alist */ + +/* get regexp size */ +int bregexp_get_build_where_size(char *strip_prefix, + char *add_prefix, + char *add_suffix); + +/* get a bregexp string from user arguments + * you must allocate it with bregexp_get_build_where_size(); + */ +char *bregexp_build_where(char *dest, int str_size, + char *strip_prefix, + char *add_prefix, + char *add_suffix); + +/* escape a string to regexp format (sep and \) + * dest must be long enough (dest = 2*src + 1) + */ +char *bregexp_escape_string(char *dest, char *src, char sep); + +#endif /* __BREG_H_ */ diff --git a/bacula/src/lib/bregex.c b/bacula/src/lib/bregex.c index aa8b80244d..9ded1b67be 100644 --- a/bacula/src/lib/bregex.c +++ b/bacula/src/lib/bregex.c @@ -1459,6 +1459,10 @@ if (translate) \ int regcomp(regex_t * bufp, const char *regex, int cflags) { memset(bufp, 0, sizeof(regex_t)); + bufp->cflags = cflags; + if (bufp->cflags & REG_ICASE) { + // ICI passer regex en lcase + } re_compile_pattern(bufp, (unsigned char *)regex); if (got_error) { return -1; @@ -1471,6 +1475,7 @@ int regexec(regex_t * preg, const char *string, size_t nmatch, { int stat; int len = strlen(string); + // ICI passer string en lcase struct re_registers regs; stat = re_search(preg, (unsigned char *)string, len, 0, len, ®s); /* stat is the start position in the string base 0 where diff --git a/bacula/src/lib/bregex.h b/bacula/src/lib/bregex.h index ed5cb1f379..8c7778d1c3 100644 --- a/bacula/src/lib/bregex.h +++ b/bacula/src/lib/bregex.h @@ -106,6 +106,8 @@ struct regex_t int num_registers; /* number of registers used */ unsigned char anchor; /* anchor: 0=none 1=begline 2=begbuf */ char *errmsg; + int cflags; /* compilation flags */ + POOLMEM *str_lcase; /* use to store expression in lcase */ }; diff --git a/bacula/src/lib/jcr.c b/bacula/src/lib/jcr.c index 982f4d0a9b..76c164fa37 100644 --- a/bacula/src/lib/jcr.c +++ b/bacula/src/lib/jcr.c @@ -56,6 +56,9 @@ /* External variables we reference */ extern time_t watchdog_time; +/* External referenced functions */ +void free_bregexps(alist *bregexps); + /* Forward referenced functions */ extern "C" void timeout_handler(int sig); static void jcr_timeout_check(watchdog_t *self); @@ -381,6 +384,11 @@ static void free_common_jcr(JCR *jcr) free(jcr->where); jcr->where = NULL; } + if (jcr->where_bregexp) { + free_bregexps(jcr->where_bregexp); + delete jcr->where_bregexp; + jcr->where_bregexp = NULL; + } if (jcr->cached_path) { free_pool_memory(jcr->cached_path); jcr->cached_path = NULL;