]> git.sur5r.net Git - bacula/bacula/blob - bacula/patches/testing/file_relocation.patch
ebl fix compilation bug
[bacula/bacula] / bacula / patches / testing / file_relocation.patch
1 Index: src/dird/ua_restore.c
2 ===================================================================
3 --- src/dird/ua_restore.c       (révision 4588)
4 +++ src/dird/ua_restore.c       (copie de travail)
5 @@ -44,7 +44,6 @@
6  #include "bacula.h"
7  #include "dird.h"
8  
9 -
10  /* Imported functions */
11  extern void print_bsr(UAContext *ua, RBSR *bsr);
12  
13 @@ -83,6 +82,9 @@
14     JCR *jcr = ua->jcr;
15     char *escaped_bsr_name = NULL;
16     char *escaped_where_name = NULL;
17 +   bool where_use_regexp = false;
18 +   char *strip_prefix, *add_prefix, *add_suffix, *regexp;
19 +   strip_prefix = add_prefix = add_suffix = regexp = NULL;
20  
21     memset(&rx, 0, sizeof(rx));
22     rx.path = get_pool_memory(PM_FNAME);
23 @@ -94,6 +96,45 @@
24     i = find_arg_with_value(ua, "where");
25     if (i >= 0) {
26        rx.where = ua->argv[i];
27 +   }
28 +
29 +   i = find_arg_with_value(ua, "strip_prefix");
30 +   if (i >= 0) {
31 +      strip_prefix = ua->argv[i];
32 +   }
33 +
34 +   i = find_arg_with_value(ua, "add_prefix");
35 +   if (i >= 0) {
36 +      add_prefix = ua->argv[i];
37 +   }
38 +
39 +   i = find_arg_with_value(ua, "add_suffix");
40 +   if (i >= 0) {
41 +      add_suffix = ua->argv[i];
42 +   }
43 +
44 +   i = find_arg(ua, "where_use_regexp");
45 +   if (i >= 0) {
46 +      where_use_regexp = true;
47 +   }
48 +
49 +   i = find_arg_with_value(ua, "rwhere");
50 +   if (i >= 0) {
51 +      where_use_regexp = true;
52 +      rx.where = ua->argv[i];
53 +   }
54 +
55 +   if (strip_prefix || add_suffix || add_prefix) {
56 +      int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
57 +      regexp = (char *) bmalloc (len * sizeof(char));
58 +
59 +      bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
60 +      where_use_regexp = true;
61 +      
62 +      rx.where = regexp;
63 +   }
64 +
65 +   if (rx.where) {
66        if (!acl_access_ok(ua, Where_ACL, rx.where)) {
67           ua->error_msg(_("\"where\" specification not authorized.\n"));
68           goto bail_out;
69 @@ -195,9 +236,10 @@
70  
71        Mmsg(ua->cmd,
72            "run job=\"%s\" client=\"%s\" storage=\"%s\" bootstrap=\"%s\""
73 -          " where=\"%s\" files=%d catalog=\"%s\"",
74 +          " %swhere=\"%s\" files=%d catalog=\"%s\"",
75            job->name(), rx.ClientName, rx.store?rx.store->name():"",
76            escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap,
77 +          where_use_regexp ? "r" : "",
78            escaped_where_name ? escaped_where_name : rx.where,
79            rx.selected_files, ua->catalog->name());
80     } else {
81 @@ -216,6 +258,10 @@
82     if (escaped_where_name != NULL) {
83        bfree(escaped_where_name);
84     }
85 +   
86 +   if (regexp) {
87 +      bfree(regexp);
88 +   }
89  
90     if (find_arg(ua, NT_("yes")) > 0) {
91        pm_strcat(ua->cmd, " yes");    /* pass it on to the run command */
92 @@ -235,6 +281,10 @@
93        bfree(escaped_where_name);
94     }
95  
96 +   if (regexp) {
97 +      bfree(regexp);
98 +   }
99 +
100     free_rx(&rx);
101     return 0;
102  
103 @@ -333,23 +383,28 @@
104  
105     const char *kw[] = {
106         /* These keywords are handled in a for loop */
107 -      "jobid",     /* 0 */
108 -      "current",   /* 1 */
109 -      "before",    /* 2 */
110 -      "file",      /* 3 */
111 -      "directory", /* 4 */
112 -      "select",    /* 5 */
113 -      "pool",      /* 6 */
114 -      "all",       /* 7 */
115 +      "jobid",       /* 0 */
116 +      "current",     /* 1 */
117 +      "before",      /* 2 */
118 +      "file",        /* 3 */
119 +      "directory",   /* 4 */
120 +      "select",      /* 5 */
121 +      "pool",        /* 6 */
122 +      "all",         /* 7 */
123  
124        /* The keyword below are handled by individual arg lookups */
125 -      "client",    /* 8 */
126 -      "storage",   /* 9 */
127 -      "fileset",   /* 10 */
128 -      "where",     /* 11 */
129 -      "yes",       /* 12 */
130 -      "bootstrap", /* 13 */
131 -      "done",      /* 14 */
132 +      "client",       /* 8 */
133 +      "storage",      /* 9 */
134 +      "fileset",      /* 10 */
135 +      "where",        /* 11 */
136 +      "yes",          /* 12 */
137 +      "bootstrap",    /* 13 */
138 +      "done",         /* 14 */
139 +      "strip_prefix", /* 15 */
140 +      "add_prefix",   /* 16 */
141 +      "add_suffix",   /* 17 */
142 +      "where_use_regexp",/* 18 */
143 +      "rwhere",       /* 19 like where + where_use_regexp */
144        NULL
145     };
146  
147 Index: src/dird/restore.c
148 ===================================================================
149 --- src/dird/restore.c  (révision 4588)
150 +++ src/dird/restore.c  (copie de travail)
151 @@ -50,8 +50,9 @@
152  #include "dird.h"
153  
154  /* Commands sent to File daemon */
155 -static char restorecmd[]   = "restore replace=%c prelinks=%d where=%s\n";
156 -static char storaddr[]     = "storage address=%s port=%d ssl=0\n";
157 +static char restorecmd[]        = "restore replace=%c prelinks=%d where=%s\n";
158 +static char restorecmdR[] = "restore replace=%c prelinks=%d rwhere=%s\n";
159 +static char storaddr[]   = "storage address=%s port=%d ssl=0\n";
160  
161  /* Responses received from File daemon */
162  static char OKrestore[]   = "2000 OK restore\n";
163 @@ -172,7 +173,7 @@
164     }
165  
166     /* Send restore command */
167 -   char replace, *where;
168 +   char replace, *where, *cmd;
169     char empty = '\0';
170  
171     if (jcr->replace != 0) {
172 @@ -189,9 +190,17 @@
173     } else {
174        where = ∅                 /* None */
175     }
176 +   
177     jcr->prefix_links = jcr->job->PrefixLinks;
178 +
179 +   if (jcr->where_use_regexp) {
180 +      cmd = restorecmdR;
181 +   } else {
182 +      cmd = restorecmd;
183 +   }
184 +
185     bash_spaces(where);
186 -   bnet_fsend(fd, restorecmd, replace, jcr->prefix_links, where);
187 +   bnet_fsend(fd, cmd, replace, jcr->prefix_links, where);
188     unbash_spaces(where);
189  
190     if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
191 Index: src/dird/dird.h
192 ===================================================================
193 --- src/dird/dird.h     (révision 4588)
194 +++ src/dird/dird.h     (copie de travail)
195 @@ -34,6 +34,7 @@
196   */
197  
198  #include "lib/runscript.h"
199 +#include "lib/breg.h"
200  #include "dird_conf.h"
201  
202  #define DIRECTOR_DAEMON 1
203 Index: src/dird/dird_conf.c
204 ===================================================================
205 --- src/dird/dird_conf.c        (révision 4588)
206 +++ src/dird/dird_conf.c        (copie de travail)
207 @@ -268,6 +268,10 @@
208     {"run",       store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
209     /* Root of where to restore files */
210     {"where",    store_dir,      ITEM(res_job.RestoreWhere), 0, 0, 0},
211 +   {"whereuseregexp", store_bool, ITEM(res_job.where_use_regexp), 0, 0, 0},
212 +   {"stripprefix",    store_str,  ITEM(res_job.strip_prefix), 0, 0, 0},
213 +   {"addprefix",    store_str,  ITEM(res_job.add_prefix), 0, 0, 0},
214 +   {"addsuffix",    store_str,  ITEM(res_job.add_suffix), 0, 0, 0},
215     /* Where to find bootstrap during restore */
216     {"bootstrap",store_dir,      ITEM(res_job.RestoreBootstrap), 0, 0, 0},
217     /* Where to write bootstrap file during backup */
218 @@ -611,6 +615,9 @@
219        if (res->res_job.RestoreWhere) {
220           sendit(sock, _("  --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
221        }
222 +      if (res->res_job.where_use_regexp) {
223 +         sendit(sock, _("  --> RWhere=%u\n"), res->res_job.where_use_regexp);
224 +      }
225        if (res->res_job.RestoreBootstrap) {
226           sendit(sock, _("  --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
227        }
228 @@ -1143,6 +1150,15 @@
229        if (res->res_job.RestoreWhere) {
230           free(res->res_job.RestoreWhere);
231        }
232 +      if (res->res_job.strip_prefix) {
233 +         free(res->res_job.strip_prefix);
234 +      }
235 +      if (res->res_job.add_prefix) {
236 +         free(res->res_job.add_prefix);
237 +      }
238 +      if (res->res_job.add_suffix) {
239 +         free(res->res_job.add_suffix);
240 +      }
241        if (res->res_job.RestoreBootstrap) {
242           free(res->res_job.RestoreBootstrap);
243        }
244 @@ -1299,6 +1315,25 @@
245           res->res_job.jobdefs    = res_all.res_job.jobdefs;
246           res->res_job.run_cmds   = res_all.res_job.run_cmds;
247           res->res_job.RunScripts = res_all.res_job.RunScripts;
248 +        if (res->res_job.strip_prefix ||
249 +            res->res_job.add_suffix   ||
250 +            res->res_job.add_prefix)
251 +        {
252 +           if (res->res_job.RestoreWhere) {
253 +              free(res->res_job.RestoreWhere);
254 +           }
255 +           int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
256 +                                                  res->res_job.add_prefix,
257 +                                                  res->res_job.add_suffix);
258 +           res->res_job.RestoreWhere = (char *) bmalloc (len * sizeof(char));
259 +           bregexp_build_where(res->res_job.RestoreWhere, len,
260 +                               res->res_job.strip_prefix,
261 +                               res->res_job.add_prefix,
262 +                               res->res_job.add_suffix);
263 +           res->res_job.where_use_regexp = true;
264 +
265 +           /* TODO: test bregexp */
266 +        }
267           break;
268        case R_COUNTER:
269           if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
270 Index: src/dird/ua_run.c
271 ===================================================================
272 --- src/dird/ua_run.c   (révision 4588)
273 +++ src/dird/ua_run.c   (copie de travail)
274 @@ -41,6 +41,7 @@
275  static void select_job_level(UAContext *ua, JCR *jcr);
276  static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, char *verify_list, 
277     char *jid, const char *replace);
278 +static void select_where_regexp(UAContext *ua, JCR *jcr);
279  
280  
281  /* Imported variables */
282 @@ -71,6 +72,7 @@
283     int Priority = 0;
284     int i, j, opt, files = 0;
285     bool kw_ok;
286 +   bool where_use_regexp = false;
287     JOB *job = NULL;
288     JOB *verify_job = NULL;
289     JOB *previous_job = NULL;
290 @@ -87,7 +89,7 @@
291        "level",                        /* 5 */
292        "storage",                      /* 6 */
293        "sd",                           /* 7 */
294 -      "pool",                         /* 8 */
295 +      "rwhere",                       /* 8 where string as a bregexp */
296        "where",                        /* 9 */
297        "bootstrap",                    /* 10 */
298        "replace",                      /* 11 */
299 @@ -101,6 +103,7 @@
300        "cloned",                       /* 19 cloned */
301        "verifylist",                   /* 20 verify output list */
302        "migrationjob",                 /* 21 migration job name */
303 +      "pool",                         /* 22 */
304        NULL};
305  
306  #define YES_POS 14
307 @@ -188,15 +191,11 @@
308                 store_name = ua->argv[i];
309                 kw_ok = true;
310                 break;
311 -            case 8: /* pool */
312 -               if (pool_name) {
313 -                  ua->send_msg(_("Pool specified twice.\n"));
314 -                  return 0;
315 -               }
316 -               pool_name = ua->argv[i];
317 -               kw_ok = true;
318 -               break;
319 +            case 8: /* rwhere */
320              case 9: /* where */
321 +               /* TODO: this is ugly ... */
322 +               where_use_regexp = (j == 9)?false:true; /* rwhere or where ? */
323 +
324                 if (where) {
325                    ua->send_msg(_("Where specified twice.\n"));
326                    return 0;
327 @@ -287,8 +286,15 @@
328                 previous_job_name = ua->argv[i];
329                 kw_ok = true;
330                 break;
331 +            case 22: /* pool */
332 +               if (pool_name) {
333 +                  ua->send_msg(_("Pool specified twice.\n"));
334 +                  return 0;
335 +               }
336 +               pool_name = ua->argv[i];
337 +               kw_ok = true;
338 +               break;
339  
340 -
341              default:
342                 break;
343              }
344 @@ -478,6 +484,7 @@
345           free(jcr->where);
346        }
347        jcr->where = bstrdup(where);
348 +      jcr->where_use_regexp = where_use_regexp;
349     }
350  
351     if (when) {
352 @@ -595,8 +602,9 @@
353        } else if (jcr->JobType == JT_RESTORE) {
354           add_prompt(ua, _("Bootstrap"));     /* 7 */
355           add_prompt(ua, _("Where"));         /* 8 */
356 -         add_prompt(ua, _("Replace"));       /* 9 */
357 -         add_prompt(ua, _("JobId"));         /* 10 */
358 +         add_prompt(ua, _("File Relocation"));/* 9 */   
359 +         add_prompt(ua, _("Replace"));       /* 10 */
360 +         add_prompt(ua, _("JobId"));         /* 11 */
361        }
362        switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
363        case 0:
364 @@ -719,8 +727,13 @@
365              ua->cmd[0] = 0;
366           }
367           jcr->where = bstrdup(ua->cmd);
368 +        jcr->where_use_regexp = false;
369           goto try_again;
370 -      case 9:
371 +      case 9: 
372 +        /* File relocation */
373 +        select_where_regexp(ua, jcr);
374 +        goto try_again;
375 +      case 10:
376           /* Replace */
377           start_prompt(ua, _("Replace:\n"));
378           for (i=0; ReplaceOptions[i].name; i++) {
379 @@ -731,7 +744,7 @@
380              jcr->replace = ReplaceOptions[opt].token;
381           }
382           goto try_again;
383 -      case 10:
384 +      case 11:
385           /* JobId */
386           jid = NULL;                  /* force reprompt */
387           jcr->RestoreJobId = 0;
388 @@ -775,6 +788,134 @@
389     return 0;                       /* do not run */
390  }
391  
392 +static void select_where_regexp(UAContext *ua, JCR *jcr)
393 +{
394 +   alist *regs;
395 +   char *strip_prefix, *add_prefix, *add_suffix, *rwhere;
396 +   strip_prefix = add_suffix = rwhere = add_prefix = NULL;
397 +
398 +try_again_reg:
399 +   ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"),
400 +               NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix));
401 +
402 +   start_prompt(ua, _("This will replace your current Where value\n"));
403 +   add_prompt(ua, _("Strip prefix"));                /* 0 */
404 +   add_prompt(ua, _("Add prefix"));                  /* 1 */
405 +   add_prompt(ua, _("Add file suffix"));             /* 2 */
406 +   add_prompt(ua, _("Enter a regexp"));              /* 3 */
407 +   add_prompt(ua, _("Test filename manipulation"));  /* 4 */
408 +   add_prompt(ua, _("Use this ?"));                  /* 5 */
409 +   
410 +   switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
411 +   case 0:
412 +      /* Strip prefix */
413 +      if (get_cmd(ua, _("Please enter path prefix to strip: "))) {
414 +        if (strip_prefix) bfree(strip_prefix);
415 +        strip_prefix = bstrdup(ua->cmd);
416 +      }
417 +      
418 +      goto try_again_reg;
419 +   case 1:
420 +      /* Add prefix */
421 +      if (get_cmd(ua, _("Please enter path prefix to add (/ for none): "))) {
422 +        if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
423 +           ua->cmd[0] = 0;
424 +        }
425 +
426 +        if (add_prefix) bfree(add_prefix);
427 +        add_prefix = bstrdup(ua->cmd);
428 +      }
429 +      goto try_again_reg;
430 +   case 2:
431 +      /* Add suffix */
432 +      if (get_cmd(ua, _("Please enter file suffix to add: "))) {
433 +        if (add_suffix) bfree(add_suffix);
434 +        add_suffix = bstrdup(ua->cmd);
435 +      }      
436 +      goto try_again_reg;
437 +   case 3:
438 +      /* Add rwhere */
439 +      if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) {
440 +        if (rwhere) bfree(rwhere);
441 +        rwhere = bstrdup(ua->cmd);
442 +      }
443 +      
444 +      goto try_again_reg;      
445 +   case 4:
446 +      /* Test regexp */ 
447 +      char *result;
448 +      char *regexp;
449 +      
450 +      if (rwhere && rwhere[0] != '\0') {
451 +        regs = get_bregexps(rwhere);
452 +        ua->send_msg(_("rwhere=%s\n"), NPRT(rwhere));
453 +      } else {
454 +        int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
455 +        regexp = (char *) bmalloc (len * sizeof(char));
456 +        bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
457 +        regs = get_bregexps(regexp);
458 +        ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"),
459 +                     NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp));
460 +        
461 +        bfree(regexp);
462 +      }
463 +
464 +      if (!regs) {
465 +        ua->send_msg(_("Cannot use your regexp\n"));
466 +        goto try_again_reg;
467 +      }
468 +
469 +      while (get_cmd(ua, _("Please enter filename to test: "))) {
470 +        apply_bregexps(ua->cmd, regs, &result);
471 +        ua->send_msg(_("%s -> %s\n"), ua->cmd, result);
472 +      }
473 +      free_bregexps(regs);
474 +      delete regs;
475 +      goto try_again_reg;
476 +
477 +   case 5:
478 +      /* OK */
479 +      break;
480 +   case -1:                        /* error or cancel */
481 +      goto bail_out_reg;
482 +   default:
483 +      goto try_again_reg;
484 +   }
485 +
486 +   /* replace the existing where */
487 +   if (jcr->where) {
488 +      bfree(jcr->where);
489 +      jcr->where = NULL;
490 +   }
491 +
492 +   if (rwhere) {
493 +      jcr->where = bstrdup(rwhere);
494 +   } else if (strip_prefix || add_prefix || add_suffix) {
495 +      int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
496 +      jcr->where = (char *) bmalloc(len*sizeof(char));
497 +      bregexp_build_where(jcr->where, len, strip_prefix, add_prefix, add_suffix);
498 +   }
499 +
500 +   regs = get_bregexps(jcr->where);
501 +   if (regs) {
502 +      free_bregexps(regs);
503 +      delete regs;
504 +      jcr->where_use_regexp = true;
505 +   } else {
506 +      if (jcr->where) {
507 +        bfree(jcr->where);
508 +        jcr->where = NULL;
509 +      }
510 +      ua->send_msg(_("Cannot use your regexp.\n"));
511 +   }
512 +
513 +bail_out_reg:
514 +   if (strip_prefix) bfree(strip_prefix);
515 +   if (add_prefix)   bfree(add_prefix);
516 +   if (add_suffix)   bfree(add_suffix);
517 +   if (rwhere)       bfree(rwhere);
518 +}
519 +
520  static void select_job_level(UAContext *ua, JCR *jcr)
521  {
522     if (jcr->JobType == JT_BACKUP) {
523 @@ -938,7 +1079,7 @@
524           ua->send_msg(_("Run Restore job\n"
525                          "JobName:    %s\n"
526                          "Bootstrap:  %s\n"
527 -                        "Where:      %s\n"
528 +                        "%s     %s\n"             /* Where or RWhere */
529                          "Replace:    %s\n"
530                          "FileSet:    %s\n"
531                          "Client:     %s\n"
532 @@ -948,6 +1089,7 @@
533                          "Priority:   %d\n"),
534                job->name(),
535                NPRT(jcr->RestoreBootstrap),
536 +              jcr->where_use_regexp?"RWhere:":"Where: ",
537                jcr->where?jcr->where:NPRT(job->RestoreWhere),
538                replace,
539                jcr->fileset->name(),
540 @@ -961,7 +1103,7 @@
541           ua->send_msg(_("Run Restore job\n"
542                         "JobName:    %s\n"
543                         "Bootstrap:  %s\n"
544 -                       "Where:      %s\n"
545 +                       "%s     %s\n"              /* Where or RWhere */
546                         "Replace:    %s\n"
547                         "Client:     %s\n"
548                         "Storage:    %s\n"
549 @@ -971,6 +1113,7 @@
550                         "Priority:   %d\n"),
551                job->name(),
552                NPRT(jcr->RestoreBootstrap),
553 +              jcr->where_use_regexp?"RWhere:":"Where: ",
554                jcr->where?jcr->where:NPRT(job->RestoreWhere),
555                replace,
556                jcr->client->name(),
557 Index: src/dird/dird_conf.h
558 ===================================================================
559 --- src/dird/dird_conf.h        (révision 4588)
560 +++ src/dird/dird_conf.h        (copie de travail)
561 @@ -356,6 +356,10 @@
562     int   Priority;                    /* Job priority */
563     int   RestoreJobId;                /* What -- JobId to restore */
564     char *RestoreWhere;                /* Where on disk to restore -- directory */
565 +   char *strip_prefix;                /* remove prefix from filename  */
566 +   char *add_prefix;                  /* add prefix to filename  */
567 +   char *add_suffix;                  /* add suffix to filename -- .old */
568 +   bool  where_use_regexp;            /* true if RestoreWhere is a BREGEXP */
569     char *RestoreBootstrap;            /* Bootstrap file */
570     alist *RunScripts;                 /* Run {client} program {after|before} Job */
571     union {
572 Index: src/filed/job.c
573 ===================================================================
574 --- src/filed/job.c     (révision 4588)
575 +++ src/filed/job.c     (copie de travail)
576 @@ -115,6 +115,7 @@
577  static char sessioncmd[]  = "session %127s %ld %ld %ld %ld %ld %ld\n";
578  static char restorecmd[]  = "restore replace=%c prelinks=%d where=%s\n";
579  static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
580 +static char restorecmdR[] = "restore replace=%c prelinks=%d rwhere=%s\n";
581  static char verifycmd[]   = "verify level=%30s";
582  static char estimatecmd[] = "estimate listing=%d";
583  static char runbefore[]   = "RunBeforeJob %s";
584 @@ -1586,12 +1587,15 @@
585     *where = 0;
586  
587     if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) {
588 -      if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
589 -         pm_strcpy(jcr->errmsg, dir->msg);
590 -         Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
591 -         return 0;
592 +      if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, where) != 3){
593 +         if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
594 +            pm_strcpy(jcr->errmsg, dir->msg);
595 +            Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
596 +            return 0;
597 +         }
598 +         *where = 0;
599        }
600 -      *where = 0;
601 +      jcr->where_use_regexp = true;
602     }
603     /* Turn / into nothing */
604     if (IsPathSeparator(where[0]) && where[1] == '\0') {
605 @@ -1601,6 +1605,15 @@
606     Dmsg2(150, "Got replace %c, where=%s\n", replace, where);
607     unbash_spaces(where);
608     jcr->where = bstrdup(where);
609 +
610 +   if (jcr->where_use_regexp) {
611 +      jcr->where_bregexp = get_bregexps(jcr->where);
612 +      if (!jcr->where_bregexp) {
613 +        Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), jcr->where);
614 +        free_pool_memory(where);
615 +        return 0;
616 +      }
617 +   }
618     free_pool_memory(where);
619     jcr->replace = replace;
620     jcr->prefix_links = prefix_links;
621 Index: src/filed/filed.h
622 ===================================================================
623 --- src/filed/filed.h   (révision 4588)
624 +++ src/filed/filed.h   (copie de travail)
625 @@ -40,6 +40,7 @@
626  #include "acl.h"
627  #include "protos.h"                   /* file daemon prototypes */
628  #include "lib/runscript.h"
629 +#include "lib/breg.h"
630  #ifdef HAVE_LIBZ
631  #include <zlib.h>                     /* compression headers */
632  #else
633 Index: src/jcr.h
634 ===================================================================
635 --- src/jcr.h   (révision 4588)
636 +++ src/jcr.h   (copie de travail)
637 @@ -173,6 +173,8 @@
638     MSGS *jcr_msgs;                    /* Copy of message resource -- actually used */
639     uint32_t ClientId;                 /* Client associated with Job */
640     char *where;                       /* prefix to restore files to */
641 +   bool where_use_regexp;             /* True if where is a bregexp */
642 +   alist *where_bregexp;              /* BREGEXP alist for path manipulation */
643     int cached_pnl;                    /* cached path length */
644     POOLMEM *cached_path;              /* cached path */
645     bool prefix_links;                 /* Prefix links with Where path */
646 Index: src/lib/Makefile.in
647 ===================================================================
648 --- src/lib/Makefile.in (révision 4588)
649 +++ src/lib/Makefile.in (copie de travail)
650 @@ -32,7 +32,7 @@
651           res.c rwlock.c scan.c serial.c sha1.c \
652           signal.c smartall.c rblist.c tls.c tree.c \
653           util.c var.c watchdog.c workq.c btimers.c \
654 -         address_conf.c pythonlib.c
655 +         address_conf.c pythonlib.c breg.c
656  
657  
658  LIBOBJS = attr.o base64.o berrno.o bsys.o bget_msg.o \
659 @@ -45,7 +45,7 @@
660           res.o rwlock.o scan.o serial.o sha1.o \
661           signal.o smartall.o rblist.o tls.o tree.o \
662           util.o var.o watchdog.o workq.o btimers.o \
663 -         address_conf.o pythonlib.o
664 +         address_conf.o pythonlib.o breg.o
665  
666  
667  EXTRAOBJS = @OBJLIST@
668 Index: src/lib/attr.c
669 ===================================================================
670 --- src/lib/attr.c      (révision 4588)
671 +++ src/lib/attr.c      (copie de travail)
672 @@ -35,8 +35,8 @@
673  
674  #include "bacula.h"
675  #include "jcr.h"
676 +#include "lib/breg.h"
677  
678 -
679  ATTR *new_attr()
680  {
681     ATTR *attr = (ATTR *)malloc(sizeof(ATTR));
682 @@ -148,9 +148,30 @@
683      *   every filename if a prefix is supplied.
684      *
685      */
686 +
687     if (jcr->where[0] == 0) {
688        pm_strcpy(attr->ofname, attr->fname);
689        pm_strcpy(attr->olname, attr->lname);
690 +
691 +   } else if (jcr->where_bregexp) { 
692 +      char *ret;
693 +      apply_bregexps(attr->fname, jcr->where_bregexp, &ret);
694 +      pm_strcpy(attr->ofname, ret);
695 +
696 +      if (attr->type == FT_LNKSAVED || attr->type == FT_LNK) {
697 +         /* Always add prefix to hard links (FT_LNKSAVED) and
698 +          *  on user request to soft links
699 +          */
700 +
701 +         if ((attr->type == FT_LNKSAVED || jcr->prefix_links)) {
702 +            apply_bregexps(attr->lname, jcr->where_bregexp, &ret);
703 +            pm_strcpy(attr->olname, ret);
704 +
705 +         } else {
706 +            pm_strcpy(attr->olname, attr->lname);
707 +         }
708 +      }
709 +      
710     } else {
711        const char *fn;
712        int wherelen = strlen(jcr->where);
713 Index: src/lib/jcr.c
714 ===================================================================
715 --- src/lib/jcr.c       (révision 4588)
716 +++ src/lib/jcr.c       (copie de travail)
717 @@ -56,6 +56,9 @@
718  /* External variables we reference */
719  extern time_t watchdog_time;
720  
721 +/* External referenced functions */
722 +void free_bregexps(alist *bregexps);
723 +
724  /* Forward referenced functions */
725  extern "C" void timeout_handler(int sig);
726  static void jcr_timeout_check(watchdog_t *self);
727 @@ -381,6 +384,11 @@
728        free(jcr->where);
729        jcr->where = NULL;
730     }
731 +   if (jcr->where_bregexp) {
732 +      free_bregexps(jcr->where_bregexp);
733 +      delete jcr->where_bregexp;
734 +      jcr->where_bregexp = NULL;
735 +   }
736     if (jcr->cached_path) {
737        free_pool_memory(jcr->cached_path);
738        jcr->cached_path = NULL;