*/
#include "lib/runscript.h"
+#include "lib/breg.h"
#include "dird_conf.h"
#define DIRECTOR_DAEMON 1
{"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 */
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));
}
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);
}
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) {
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 {
#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";
}
/* Send restore command */
- char replace, *where;
+ char replace, *where, *cmd;
char empty = '\0';
if (jcr->replace != 0) {
} 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)) {
#include "bacula.h"
#include "dird.h"
-
/* Imported functions */
extern void print_bsr(UAContext *ua, RBSR *bsr);
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);
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;
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 {
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 */
bfree(escaped_where_name);
}
+ if (regexp) {
+ bfree(regexp);
+ }
+
free_rx(&rx);
return 0;
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
};
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 */
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;
"level", /* 5 */
"storage", /* 6 */
"sd", /* 7 */
- "pool", /* 8 */
+ "rwhere", /* 8 where string as a bregexp */
"where", /* 9 */
"bootstrap", /* 10 */
"replace", /* 11 */
"cloned", /* 19 cloned */
"verifylist", /* 20 verify output list */
"migrationjob", /* 21 migration job name */
+ "pool", /* 22 */
NULL};
#define YES_POS 14
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;
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;
free(jcr->where);
}
jcr->where = bstrdup(where);
+ jcr->where_use_regexp = where_use_regexp;
}
if (when) {
} 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:
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++) {
jcr->replace = ReplaceOptions[opt].token;
}
goto try_again;
- case 10:
+ case 11:
/* JobId */
jid = NULL; /* force reprompt */
jcr->RestoreJobId = 0;
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) {
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"
"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(),
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"
"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(),
#include "acl.h"
#include "protos.h" /* file daemon prototypes */
#include "lib/runscript.h"
+#include "lib/breg.h"
#ifdef HAVE_LIBZ
#include <zlib.h> /* compression headers */
#else
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";
*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') {
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;
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 */
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 \
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@
#include "bacula.h"
#include "jcr.h"
-
+#include "lib/breg.h"
ATTR *new_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);
--- /dev/null
+/*
+ * Manipulation routines for BREGEXP list
+ *
+ * Eric Bollengier, March 2007
+ *
+ * Version $Id$
+ *
+ */
+/*
+ Bacula\81Â\81® - 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\81Â\81® is a registered trademark of John Walker.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Z\81Ã\81¼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));
+}
--- /dev/null
+/*
+ * 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 <regex.h>
+#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_ */
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;
{
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
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 */
};
/* 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);
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;