]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/breg.c
8034c2c321aeedbf6120f0667220dbfeeb565fd8
[bacula/bacula] / bacula / src / lib / breg.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2016 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  * Manipulation routines for BREGEXP list
21  *
22  *  Eric Bollengier, March 2007
23  *
24  */
25
26
27 #include "bacula.h"
28
29 #include "breg.h"
30 #include "mem_pool.h"
31
32 BREGEXP *new_bregexp(const char *motif)
33 {
34    Dmsg0(500, "bregexp: creating new bregexp object\n");
35    BREGEXP *self = (BREGEXP *)bmalloc(sizeof(BREGEXP));
36    memset(self, 0, sizeof(BREGEXP));
37
38    if (!self->extract_regexp(motif)) {
39       Dmsg0(100, "bregexp: extract_regexp error\n");
40       free_bregexp(self);
41       return NULL;
42    }
43
44    self->result = get_pool_memory(PM_FNAME);
45    self->result[0] = '\0';
46
47    return self;
48 }
49
50 void free_bregexp(BREGEXP *self)
51 {
52    Dmsg0(500, "bregexp: freeing BREGEXP object\n");
53
54    if (!self) {
55       return;
56    }
57
58    if (self->expr) {
59       bfree(self->expr);
60    }
61    if (self->result) {
62       free_pool_memory(self->result);
63    }
64    regfree(&self->preg);
65    bfree(self);
66 }
67
68 /* Free a bregexps alist
69  */
70 void free_bregexps(alist *bregexps)
71 {
72    Dmsg0(500, "bregexp: freeing all BREGEXP object\n");
73
74    BREGEXP *elt;
75    foreach_alist(elt, bregexps) {
76       free_bregexp(elt);
77    }
78 }
79
80 /* Apply all regexps to fname
81  */
82 bool apply_bregexps(const char *fname, alist *bregexps, char **result)
83 {
84    BREGEXP *elt;
85    bool ok=false;
86
87    char *ret = (char *) fname;
88    foreach_alist(elt, bregexps) {
89       ret = elt->replace(ret);
90       ok = ok || elt->success;
91    }
92    Dmsg2(500, "bregexp: fname=%s ret=%s\n", fname, ret);
93
94    *result = ret;
95    return ok;
96 }
97
98 /* return an alist of BREGEXP or return NULL if it's not a
99  * where=!tmp!opt!ig,!temp!opt!i
100  */
101 alist *get_bregexps(const char *where)
102 {
103    char *p = (char *)where;
104    alist *list = New(alist(10, not_owned_by_alist));
105    BREGEXP *reg;
106
107    reg = new_bregexp(p);
108
109    while(reg) {
110       p = reg->eor;
111       list->append(reg);
112       reg = new_bregexp(p);
113    }
114
115    if (list->size()) {
116       return list;
117    } else {
118       delete list;
119       return NULL;
120    }
121 }
122
123 bool BREGEXP::extract_regexp(const char *motif)
124 {
125    if ( !motif ) {
126       return false;
127    }
128
129    char sep = motif[0];
130
131    if (!(sep == '!' ||
132          sep == ':' ||
133          sep == ';' ||
134          sep == '|' ||
135          sep == ',' ||
136          sep == '&' ||
137          sep == '%' ||
138          sep == '=' ||
139          sep == '~' ||
140          sep == '/' ||
141          sep == '<' ||
142          sep == '#'   ))
143    {
144       return false;
145    }
146
147    char *search = (char *) motif + 1;
148    int options = REG_EXTENDED | REG_NEWLINE;
149    bool ok = false;
150
151    /* extract 1st part */
152    char *dest = expr = bstrdup(motif);
153
154    while (*search && !ok) {
155       if (search[0] == '\\' && search[1] == sep) {
156          *dest++ = *++search;       /* we skip separator */
157
158       } else if (search[0] == '\\' && search[1] == '\\') {
159          *dest++ = *++search;       /* we skip the second \ */
160
161       } else if (*search == sep) {  /* we found end of expression */
162          *dest++ = '\0';
163
164          if (subst) {           /* already have found motif */
165             ok = true;
166
167          } else {
168             *dest++ = *++search; /* we skip separator */
169             subst = dest;        /* get replaced string */
170          }
171
172       } else {
173          *dest++ = *search++;
174       }
175    }
176    *dest = '\0';                /* in case of */
177
178    if (!ok || !subst) {
179       /* bad regexp */
180       return false;
181    }
182
183    ok = false;
184    /* find options */
185    while (*search && !ok) {
186       if (*search == 'i') {
187          options |= REG_ICASE;
188
189       } else if (*search == 'g') {
190               /* recherche multiple*/
191
192       } else if (*search == sep) {
193          /* skip separator */
194
195       } else {                  /* end of options */
196          ok = true;
197       }
198       search++;
199    }
200
201    int rc = regcomp(&preg, expr, options);
202    if (rc != 0) {
203       char prbuf[500];
204       regerror(rc, &preg, prbuf, sizeof(prbuf));
205       Dmsg1(100, "bregexp: compile error: %s\n", prbuf);
206       return false;
207    }
208
209    eor = search;                /* useful to find the next regexp in where */
210
211    return true;
212 }
213
214 /* return regexp->result */
215 char *BREGEXP::replace(const char *fname)
216 {
217    success = false;             /* use this.success to known if it's ok */
218    int flen = strlen(fname);
219    int rc = regexec(&preg, fname, BREG_NREGS, regs, 0);
220
221    if (rc == REG_NOMATCH) {
222       Dmsg0(500, "bregexp: regex mismatch\n");
223       return return_fname(fname, flen);
224    }
225
226    int len = compute_dest_len(fname, regs);
227
228    if (len) {
229       result = check_pool_memory_size(result, len);
230       edit_subst(fname, regs);
231       success = true;
232       Dmsg2(500, "bregexp: len = %i, result_len = %i\n", len, strlen(result));
233
234    } else {                     /* error in substitution */
235       Dmsg0(100, "bregexp: error in substitution\n");
236       return return_fname(fname, flen);
237    }
238
239    return result;
240 }
241
242 char *BREGEXP::return_fname(const char *fname, int len)
243 {
244    result = check_pool_memory_size(result, len+1);
245    strcpy(result,fname);
246    return result;
247 }
248
249 int BREGEXP::compute_dest_len(const char *fname, regmatch_t breg[])
250 {
251    int len=0;
252    char *p;
253    char *psubst = subst;
254    int no;
255
256    if (!fname || !breg) {
257       return 0;
258    }
259
260    /* match failed ? */
261    if (breg[0].rm_so < 0) {
262       return 0;
263    }
264
265    for (p = psubst++; *p ; p = psubst++) {
266       /* match $1 \1 back references */
267       if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
268          no = *psubst++ - '0';
269
270          /* we check if the back reference exists */
271          /* references can not match if we are using (..)? */
272
273          if (breg[no].rm_so >= 0 && breg[no].rm_eo >= 0) {
274             len += breg[no].rm_eo - breg[no].rm_so;
275          }
276
277       } else {
278          len++;
279       }
280    }
281
282    /* $0 is replaced by subst */
283    len -= breg[0].rm_eo - breg[0].rm_so;
284    len += strlen(fname) + 1;
285
286    return len;
287 }
288
289 char *BREGEXP::edit_subst(const char *fname, regmatch_t breg[])
290 {
291    int i;
292    char *p;
293    char *psubst = subst;
294    int no;
295    int len;
296
297    /* il faut recopier fname dans dest
298     *  on recopie le debut fname -> breg->start[0]
299     */
300
301    for (i = 0; i < breg[0].rm_so ; i++) {
302       result[i] = fname[i];
303    }
304
305    /* on recopie le motif de remplacement (avec tous les $x) */
306
307    for (p = psubst++; *p ; p = psubst++) {
308       /* match $1 \1 back references */
309       if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
310          no = *psubst++ - '0';
311
312          /* have a back reference ? */
313          if (breg[no].rm_so >= 0 && breg[no].rm_eo >= 0) {
314             len = breg[no].rm_eo - breg[no].rm_so;
315             bstrncpy(result + i, fname + breg[no].rm_so, len + 1);
316             i += len ;
317          }
318
319       } else {
320          result[i++] = *p;
321       }
322    }
323
324    /* we copy what is out of the match */
325    strcpy(result + i, fname + breg[0].rm_eo);
326
327    return result;
328 }
329
330 /* escape sep char and \
331  * dest must be long enough (src*2+1)
332  * return end of the string */
333 char *bregexp_escape_string(char *dest, const char *src, const char sep)
334 {
335    char *ret = dest;
336    while (*src)
337    {
338       if (*src == sep) {
339          *dest++ = '\\';
340       } else if (*src == '\\') {
341          *dest++ = '\\';
342       }
343       *dest++ = *src++;
344    }
345    *dest = '\0';
346
347    return ret;
348 }
349
350 static const char regexp_sep = '!';
351 static const char *str_strip_prefix = "!%s!!i";
352 static const char *str_add_prefix   = "!^!%s!";
353 static const char *str_add_suffix   = "!([^/])$!$1%s!";
354
355 int bregexp_get_build_where_size(char *strip_prefix,
356                                  char *add_prefix,
357                                  char *add_suffix)
358 {
359    int str_size = ((strip_prefix?strlen(strip_prefix)+strlen(str_strip_prefix):0) +
360                    (add_prefix?strlen(add_prefix)+strlen(str_add_prefix)      :0) +
361                    (add_suffix?strlen(add_suffix)+strlen(str_add_suffix)      :0) )
362          /* escape + 3*, + \0 */
363             * 2    + 3   + 1;
364
365    Dmsg1(200, "bregexp_get_build_where_size = %i\n", str_size);
366    return str_size;
367 }
368
369 /* build a regexp string with user arguments
370  * Usage :
371  *
372  * int len = bregexp_get_build_where_size(a,b,c) ;
373  * char *dest = (char *) bmalloc (len * sizeof(char));
374  * bregexp_build_where(dest, len, a, b, c);
375  * bfree(dest);
376  *
377  */
378 char *bregexp_build_where(char *dest, int str_size,
379                           char *strip_prefix,
380                           char *add_prefix,
381                           char *add_suffix)
382 {
383    int len=0;
384
385    POOLMEM *str_tmp = get_memory(str_size);
386
387    *str_tmp = *dest = '\0';
388
389    if (strip_prefix) {
390       len += bsnprintf(dest, str_size - len, str_strip_prefix,
391                        bregexp_escape_string(str_tmp, strip_prefix, regexp_sep));
392    }
393
394    if (add_suffix) {
395       if (len) dest[len++] = ',';
396
397       len += bsnprintf(dest + len,  str_size - len, str_add_suffix,
398                        bregexp_escape_string(str_tmp, add_suffix, regexp_sep));
399    }
400
401    if (add_prefix) {
402       if (len) dest[len++] = ',';
403
404       len += bsnprintf(dest + len, str_size - len, str_add_prefix,
405                        bregexp_escape_string(str_tmp, add_prefix, regexp_sep));
406    }
407
408    free_pool_memory(str_tmp);
409
410    return dest;
411 }
412
413
414 void BREGEXP::debug()
415 {
416    printf("expr=[%s]\n", expr);
417    printf("subst=[%s]\n", subst);
418    printf("result=%s\n", NPRT(result));
419 }