+Index: src/dird/ua_restore.c
+===================================================================
+--- src/dird/ua_restore.c	(rvision 4466)
++++ src/dird/ua_restore.c	(copie de travail)
+@@ -43,8 +43,8 @@
+ 
+ #include "bacula.h"
+ #include "dird.h"
++#include "lib/breg.h"
+ 
+-
+ /* Imported functions */
+ extern void print_bsr(UAContext *ua, RBSR *bsr);
+ 
+@@ -83,6 +83,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;
++   strip_prefix = add_prefix = add_suffix = NULL;
+ 
+    memset(&rx, 0, sizeof(rx));
+    rx.path = get_pool_memory(PM_FNAME);
+@@ -94,6 +97,29 @@
+    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];
++   }
++
++   if (strip_prefix || add_suffix || add_prefix) {
++      where_use_regexp = true;
++      rx.where = bregexp_build_where(strip_prefix, add_prefix, add_suffix);
++   }
++
++   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 +221,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 +243,10 @@
+    if (escaped_where_name != NULL) {
+       bfree(escaped_where_name);
+    }
++   
++   if (where_use_regexp) {
++      free_pool_memory(rx.where);
++   }
+ 
+    if (find_arg(ua, NT_("yes")) > 0) {
+       pm_strcat(ua->cmd, " yes");    /* pass it on to the run command */
+@@ -235,6 +266,10 @@
+       bfree(escaped_where_name);
+    }
+ 
++   if (where_use_regexp) {
++      free_pool_memory(rx.where);
++   }
++
+    free_rx(&rx);
+    return 0;
+ 
+Index: src/dird/restore.c
+===================================================================
+--- src/dird/restore.c	(rvision 4466)
++++ 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 = &empty;                 /* 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_conf.c
+===================================================================
+--- src/dird/dird_conf.c	(rvision 4466)
++++ src/dird/dird_conf.c	(copie de travail)
+@@ -268,6 +268,7 @@
+    {"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},
+    /* 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 +612,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));
+       }
+Index: src/dird/ua_run.c
+===================================================================
+--- src/dird/ua_run.c	(rvision 4466)
++++ src/dird/ua_run.c	(copie de travail)
+@@ -71,6 +71,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 +88,7 @@
+       "level",                        /* 5 */
+       "storage",                      /* 6 */
+       "sd",                           /* 7 */
+-      "pool",                         /* 8 */
++      "rwhere",                       /* 8 where string as a bregexp */
+       "where",                        /* 9 */
+       "bootstrap",                    /* 10 */
+       "replace",                      /* 11 */
+@@ -101,6 +102,7 @@
+       "cloned",                       /* 19 cloned */
+       "verifylist",                   /* 20 verify output list */
+       "migrationjob",                 /* 21 migration job name */
++      "pool",                         /* 22 */
+       NULL};
+ 
+ #define YES_POS 14
+@@ -188,14 +190,8 @@
+                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:
++	       where_use_regexp = true;
+             case 9: /* where */
+                if (where) {
+                   ua->send_msg(_("Where specified twice.\n"));
+@@ -287,8 +283,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 +481,7 @@
+          free(jcr->where);
+       }
+       jcr->where = bstrdup(where);
++      jcr->where_use_regexp = where_use_regexp;
+    }
+ 
+    if (when) {
+Index: src/dird/dird_conf.h
+===================================================================
+--- src/dird/dird_conf.h	(rvision 4466)
++++ src/dird/dird_conf.h	(copie de travail)
+@@ -356,6 +356,7 @@
+    int   Priority;                    /* Job priority */
+    int   RestoreJobId;                /* What -- JobId to restore */
+    char *RestoreWhere;                /* Where on disk to restore -- directory */
++   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	(rvision 4467)
 +++ src/filed/job.c	(copie de travail)
-@@ -37,6 +37,8 @@
+@@ -36,6 +36,7 @@
+ 
  #include "bacula.h"
  #include "filed.h"
- 
 +#include "lib/breg.h"
-+
+ 
  #if defined(WIN32_VSS)
  #include "vss.h"
- 
-@@ -1601,6 +1603,7 @@
+@@ -115,6 +116,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 +1588,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 +1606,15 @@
     Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
     unbash_spaces(where);
     jcr->where = bstrdup(where);
-+   jcr->where_bregexp = get_bregexps(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;

===================================================================
--- src/jcr.h	(rvision 4466)
+++ src/jcr.h	(copie de travail)
@@ -173,6 +173,7 @@
    MSGS *jcr_msgs;                    /* Copy of message resource -- actually used */
    uint32_t ClientId;                 /* Client associated with Job */
    char *where;                       /* prefix to restore files to */
+   alist *where_bregexp;              /* BREGEXP alist for path manipulation */
    int cached_pnl;                    /* cached path length */
    POOLMEM *cached_path;              /* cached path */

       jcr->cached_path = NULL;
Index: patches/testing/breg.c
===================================================================
--- patches/testing/breg.c	(rvision 4510)
+++ patches/testing/breg.c	(copie de travail)
@@ -393,19 +393,19 @@
 
    *str_tmp = *ret = '\0';
    
-   if (*strip_prefix) {
+   if (strip_prefix) {
       len += bsnprintf(ret, str_size - len, "!%s!!",
 		       bregexp_escape_string(str_tmp, strip_prefix, sep));
    }
 
-   if (*add_suffix) {
+   if (add_suffix) {
       if (len) ret[len++] = ',';
 
       len += bsnprintf(ret + len,  str_size - len, "!([^/])$!$1%s!",
 		       bregexp_escape_string(str_tmp, add_suffix, sep));
    }
 
-   if (*add_prefix) {
+   if (add_prefix) {
       if (len) ret[len++] = ',';
 
       len += bsnprintf(ret + len, str_size - len, "!^!%s!", 
