+++ /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
-Index: src/dird/ua_restore.c
-===================================================================
---- src/dird/ua_restore.c (révision 4588)
-+++ src/dird/ua_restore.c (copie de travail)
-@@ -44,7 +44,6 @@
- #include "bacula.h"
- #include "dird.h"
-
--
- /* Imported functions */
- extern void print_bsr(UAContext *ua, RBSR *bsr);
-
-@@ -83,6 +82,9 @@
- 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 @@
- 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 @@
-
- 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 @@
- 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 @@
- bfree(escaped_where_name);
- }
-
-+ if (regexp) {
-+ bfree(regexp);
-+ }
-+
- free_rx(&rx);
- return 0;
-
-@@ -333,23 +383,28 @@
-
- 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
- };
-
-Index: src/dird/restore.c
-===================================================================
---- src/dird/restore.c (révision 4588)
-+++ src/dird/restore.c (copie de travail)
-@@ -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 @@
- }
-
- /* Send restore command */
-- char replace, *where;
-+ char replace, *where, *cmd;
- char empty = '\0';
-
- if (jcr->replace != 0) {
-@@ -189,9 +190,17 @@
- } 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)) {
-Index: src/dird/dird.h
-===================================================================
---- src/dird/dird.h (révision 4588)
-+++ src/dird/dird.h (copie de travail)
-@@ -34,6 +34,7 @@
- */
-
- #include "lib/runscript.h"
-+#include "lib/breg.h"
- #include "dird_conf.h"
-
- #define DIRECTOR_DAEMON 1
-Index: src/dird/dird_conf.c
-===================================================================
---- src/dird/dird_conf.c (révision 4588)
-+++ src/dird/dird_conf.c (copie de travail)
-@@ -268,6 +268,10 @@
- {"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 @@
- 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 @@
- 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 @@
- 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) {
-Index: src/dird/ua_run.c
-===================================================================
---- src/dird/ua_run.c (révision 4588)
-+++ src/dird/ua_run.c (copie de travail)
-@@ -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 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 @@
- "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 @@
- "cloned", /* 19 cloned */
- "verifylist", /* 20 verify output list */
- "migrationjob", /* 21 migration job name */
-+ "pool", /* 22 */
- NULL};
-
- #define YES_POS 14
-@@ -188,15 +191,11 @@
- 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,8 +286,15 @@
- 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 @@
- free(jcr->where);
- }
- jcr->where = bstrdup(where);
-+ jcr->where_use_regexp = where_use_regexp;
- }
-
- if (when) {
-@@ -595,8 +602,9 @@
- } 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 @@
- 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 @@
- jcr->replace = ReplaceOptions[opt].token;
- }
- goto try_again;
-- case 10:
-+ case 11:
- /* JobId */
- jid = NULL; /* force reprompt */
- jcr->RestoreJobId = 0;
-@@ -775,6 +788,134 @@
- 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 @@
- 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 @@
- "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 @@
- 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 @@
- "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(),
-Index: src/dird/dird_conf.h
-===================================================================
---- src/dird/dird_conf.h (révision 4588)
-+++ src/dird/dird_conf.h (copie de travail)
-@@ -356,6 +356,10 @@
- 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 {
-Index: src/filed/job.c
-===================================================================
---- src/filed/job.c (révision 4588)
-+++ src/filed/job.c (copie de travail)
-@@ -115,6 +115,7 @@
- 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 @@
- *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 @@
- 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;
-Index: src/filed/filed.h
-===================================================================
---- src/filed/filed.h (révision 4588)
-+++ src/filed/filed.h (copie de travail)
-@@ -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 <zlib.h> /* compression headers */
- #else
-Index: src/jcr.h
-===================================================================
---- src/jcr.h (révision 4588)
-+++ src/jcr.h (copie de travail)
-@@ -173,6 +173,8 @@
- 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 */
-Index: src/lib/Makefile.in
-===================================================================
---- src/lib/Makefile.in (révision 4588)
-+++ src/lib/Makefile.in (copie de travail)
-@@ -32,7 +32,7 @@
- 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 @@
- 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@
-Index: src/lib/attr.c
-===================================================================
---- src/lib/attr.c (révision 4588)
-+++ src/lib/attr.c (copie de travail)
-@@ -35,8 +35,8 @@
-
- #include "bacula.h"
- #include "jcr.h"
-+#include "lib/breg.h"
-
--
- ATTR *new_attr()
- {
- ATTR *attr = (ATTR *)malloc(sizeof(ATTR));
-@@ -148,9 +148,30 @@
- * 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);
-Index: src/lib/jcr.c
-===================================================================
---- src/lib/jcr.c (révision 4588)
-+++ src/lib/jcr.c (copie de travail)
-@@ -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 @@
- 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;