Line data Source code
1 : #include "../burp.h"
2 : #include "../alloc.h"
3 : #include "../asfd.h"
4 : #include "../async.h"
5 : #include "../bu.h"
6 : #include "../cmd.h"
7 : #include "../cntr.h"
8 : #include "../cstat.h"
9 : #include "../handy.h"
10 : #include "../hexmap.h"
11 : #include "../linkhash.h"
12 : #include "../lock.h"
13 : #include "../log.h"
14 : #include "../pathcmp.h"
15 : #include "../prepend.h"
16 : #include "../regexp.h"
17 : #include "../slist.h"
18 : #include "../strlist.h"
19 : #include "bu_get.h"
20 : #include "child.h"
21 : #include "compress.h"
22 : #include "manio.h"
23 : #include "restore_sbuf.h"
24 : #include "rubble.h"
25 : #include "sdirs.h"
26 :
27 1 : static enum asl_ret restore_end_func(struct asfd *asfd,
28 : __attribute__ ((unused)) struct conf **confs,
29 : __attribute__ ((unused)) void *param)
30 : {
31 1 : if(!strcmp(asfd->rbuf->buf, "restoreend ok"))
32 : return ASL_END_OK;
33 : // Old v2 clients send something slightly different.
34 0 : if(!strcmp(asfd->rbuf->buf, "restoreend_ok"))
35 : return ASL_END_OK;
36 0 : iobuf_log_unexpected(asfd->rbuf, __func__);
37 0 : return ASL_END_ERROR;
38 : }
39 :
40 1 : static int restore_end(struct asfd *asfd, struct conf **confs)
41 : {
42 1 : if(asfd->write_str(asfd, CMD_GEN, "restoreend")) return -1;
43 1 : return asfd->simple_loop(asfd, confs, NULL, __func__, restore_end_func);
44 : }
45 :
46 : static int srestore_matches(struct strlist *s, const char *path)
47 : {
48 0 : int r=0;
49 0 : if(!s->flag) return 0; // Do not know how to do excludes yet.
50 0 : if((r=strncmp_w(path, s->path))) return 0; // no match
51 : if(!r) return 1; // exact match
52 : if(*(path+strlen(s->path)+1)=='/')
53 : return 1; // matched directory contents
54 : return 0; // no match
55 : }
56 :
57 : // Used when restore is initiated from the server.
58 0 : static int srestore_check(struct conf **confs, const char *path)
59 : {
60 0 : struct strlist *l=get_strlist(confs[OPT_INCEXCDIR]);
61 :
62 : // If no includes specified, restore everything.
63 0 : if(!l) return 1;
64 :
65 0 : for(; l; l=l->next)
66 0 : if(srestore_matches(l, path))
67 : return 1;
68 : return 0;
69 : }
70 :
71 0 : static int restore_list_check(
72 : struct asfd *asfd,
73 : struct cntr *cntr,
74 : struct fzp *rl_fzp,
75 : struct iobuf *rl_iobuf,
76 : const char *path
77 : )
78 : {
79 0 : char *last=NULL;
80 :
81 : do {
82 0 : if(!rl_iobuf->buf)
83 : {
84 0 : switch(iobuf_fill_from_fzp(rl_iobuf, rl_fzp))
85 : {
86 : case 0: break; // OK, read something.
87 : case 1: return 0; // Finished, no match.
88 0 : default: return -1; // Error.
89 : }
90 : }
91 :
92 0 : if(last && pathcmp(rl_iobuf->buf, last)!=1)
93 : {
94 0 : logw(asfd, cntr,
95 : "Input file ordering problem: '%s' '%s'",
96 : last, rl_iobuf->buf);
97 : }
98 :
99 0 : switch(pathcmp(rl_iobuf->buf, path))
100 : {
101 : case 0: return 1; // Successful match.
102 0 : case 1: return 0; // Ahead in input, no match.
103 : default:
104 : // Behind, need to read more from input.
105 0 : free_w(&last);
106 0 : last=rl_iobuf->buf;
107 0 : rl_iobuf->buf=NULL;
108 : }
109 : } while (1);
110 :
111 : return 0;
112 : }
113 :
114 10 : static int want_to_restore(
115 : struct asfd *asfd,
116 : int srestore,
117 : struct fzp *input_fzp,
118 : struct iobuf *input_iobuf,
119 : struct sbuf *sb,
120 : regex_t *regex,
121 : enum action act,
122 : struct conf **cconfs
123 : ) {
124 10 : if(act==ACTION_RESTORE)
125 : {
126 : // Do not send VSS data to non-windows, or to windows client
127 : // that asked us not to send it.
128 10 : if(!get_int(cconfs[OPT_CLIENT_IS_WINDOWS])
129 0 : || get_int(cconfs[OPT_VSS_RESTORE])!=VSS_RESTORE_ON)
130 : {
131 10 : if(sbuf_is_vssdata(sb))
132 : return 0;
133 : // Do not send VSS directory data to non-windows.
134 10 : if(S_ISDIR(sb->statp.st_mode)
135 0 : && sbuf_is_filedata(sb)
136 0 : && !sbuf_is_metadata(sb))
137 : return 0;
138 : }
139 : }
140 : return
141 : (!input_fzp
142 0 : || restore_list_check(asfd, get_cntr(cconfs),
143 0 : input_fzp, input_iobuf, sb->path.buf))
144 10 : && (!srestore
145 0 : || srestore_check(cconfs, sb->path.buf))
146 20 : && (!regex
147 0 : || regex_check(regex, sb->path.buf));
148 : }
149 :
150 1 : static int maybe_open_restore_list(
151 : struct conf **cconfs,
152 : struct fzp **rl_fzp,
153 : struct iobuf **rl_iobuf,
154 : struct sdirs *sdirs
155 : ) {
156 1 : if(!get_string(cconfs[OPT_RESTORE_LIST]))
157 : return 0;
158 :
159 0 : if(!(*rl_fzp=fzp_open(sdirs->restore_list, "rb"))
160 0 : || !(*rl_iobuf=iobuf_alloc()))
161 : return -1;
162 :
163 : return 0;
164 : }
165 :
166 1 : static int setup_cntr(struct asfd *asfd, const char *manifest,
167 : regex_t *regex, int srestore, struct conf **cconfs, enum action act,
168 : struct bu *bu, struct sdirs *sdirs)
169 : {
170 1 : int ars=0;
171 1 : int ret=-1;
172 1 : struct fzp *fzp=NULL;
173 1 : struct sbuf *sb=NULL;
174 1 : struct cntr *cntr=NULL;
175 1 : struct fzp *rl_fzp=NULL;
176 1 : struct iobuf *rl_iobuf=NULL;
177 :
178 1 : cntr=get_cntr(cconfs);
179 1 : if(!cntr) return 0;
180 0 : cntr->bno=(int)bu->bno;
181 :
182 0 : if(maybe_open_restore_list(cconfs, &rl_fzp, &rl_iobuf, sdirs))
183 : goto end;
184 :
185 0 : if(!(sb=sbuf_alloc())) goto end;
186 0 : if(!(fzp=fzp_gzopen(manifest, "rb")))
187 : {
188 0 : log_and_send(asfd, "could not open manifest");
189 : goto end;
190 : }
191 : while(1)
192 : {
193 0 : if((ars=sbuf_fill_from_file(sb, fzp)))
194 : {
195 0 : if(ars<0) goto end;
196 : // ars==1 means end ok
197 : break;
198 : }
199 : else
200 : {
201 0 : if(want_to_restore(asfd, srestore,
202 : rl_fzp, rl_iobuf,
203 : sb, regex, act, cconfs))
204 : {
205 0 : cntr_add_phase1(cntr, sb->path.cmd, 0);
206 0 : if(sb->endfile.buf)
207 0 : cntr_add_val(cntr,
208 : CMD_BYTES_ESTIMATED,
209 0 : strtoull(sb->endfile.buf,
210 : NULL, 10));
211 : }
212 : }
213 0 : sbuf_free_content(sb);
214 : }
215 0 : ret=0;
216 : end:
217 0 : iobuf_free(&rl_iobuf);
218 0 : fzp_close(&rl_fzp);
219 0 : sbuf_free(&sb);
220 0 : fzp_close(&fzp);
221 : return ret;
222 : }
223 :
224 : static int restore_sbuf(struct asfd *asfd, struct sbuf *sb, struct bu *bu,
225 : enum action act, struct sdirs *sdirs, enum cntr_status cntr_status,
226 : struct conf **cconfs, const char *manifest,
227 : struct slist *slist);
228 :
229 : // Used when restoring a hard link that we have not restored the destination
230 : // for. Read through the manifest from the beginning and substitute the path
231 : // and data to the new location.
232 0 : static int hard_link_substitution(struct asfd *asfd,
233 : struct sbuf *sb, struct f_link *lp,
234 : struct bu *bu, enum action act, struct sdirs *sdirs,
235 : enum cntr_status cntr_status, struct conf **cconfs,
236 : const char *manifest, struct slist *slist)
237 : {
238 0 : int ret=-1;
239 0 : struct sbuf *hb=NULL;
240 0 : struct manio *manio=NULL;
241 : int pcmp;
242 :
243 0 : if(!(manio=manio_open(manifest, "rb"))
244 0 : || !(hb=sbuf_alloc()))
245 : goto end;
246 :
247 : while(1)
248 : {
249 0 : switch(manio_read(manio, hb))
250 : {
251 : case 0: break; // Keep going.
252 0 : case 1: ret=0; goto end; // Finished OK.
253 : default: goto end; // Error;
254 : }
255 :
256 0 : pcmp=pathcmp(lp->name, hb->path.buf);
257 :
258 0 : if(!pcmp && (sbuf_is_filedata(hb) || sbuf_is_vssdata(hb)))
259 : {
260 : // Copy the path from sb to hb.
261 0 : free_w(&hb->path.buf);
262 0 : if(!(hb->path.buf=strdup_w(sb->path.buf, __func__)))
263 : goto end;
264 0 : hb->path.len = sb->path.len;
265 : // Should now be able to restore the original data
266 : // to the new location.
267 0 : ret=restore_sbuf(asfd, hb, bu, act, sdirs,
268 : cntr_status, cconfs, manifest, slist);
269 : break;
270 : }
271 :
272 0 : sbuf_free_content(hb);
273 : // Break out once we have gone past the entry that we are
274 : // interested in.
275 0 : if(pcmp<0) break;
276 : }
277 : end:
278 0 : sbuf_free(&hb);
279 0 : manio_close(&manio);
280 0 : return ret;
281 : }
282 :
283 10 : static int restore_sbuf(struct asfd *asfd, struct sbuf *sb, struct bu *bu,
284 : enum action act, struct sdirs *sdirs, enum cntr_status cntr_status,
285 : struct conf **cconfs, const char *manifest,
286 : struct slist *slist)
287 : {
288 : //printf("%s: %s\n", act==ACTION_RESTORE?"restore":"verify",
289 : // iobuf_to_printable(&sb->path));
290 10 : if(timed_operation_status_only(cntr_status, sb->path.buf, cconfs))
291 : return -1;
292 :
293 10 : if(sb->path.cmd==CMD_HARD_LINK)
294 : {
295 1 : struct f_link *lp=NULL;
296 1 : struct f_link **bucket=NULL;
297 1 : if((lp=linkhash_search(&sb->statp, &bucket)))
298 : {
299 : // It is in the list of stuff that is in the manifest,
300 : // but was skipped on this restore.
301 : // Need to go through the manifest from the beginning,
302 : // and substitute in the data to restore to this
303 : // location.
304 0 : return hard_link_substitution(asfd, sb, lp,
305 : bu, act, sdirs,
306 : cntr_status, cconfs, manifest, slist);
307 : // FIX THIS: Would be nice to remember the new link
308 : // location so that further hard links would link to
309 : // it instead of doing the hard_link_substitution
310 : // business over again.
311 : }
312 : }
313 :
314 10 : return restore_sbuf_all(asfd, sb, bu, act, sdirs, cconfs);
315 : }
316 :
317 10 : static int restore_ent(struct asfd *asfd,
318 : struct sbuf **sb,
319 : struct slist *slist,
320 : struct bu *bu,
321 : enum action act,
322 : struct sdirs *sdirs,
323 : enum cntr_status cntr_status,
324 : struct conf **cconfs,
325 : int *last_ent_was_dir,
326 : const char *manifest)
327 : {
328 10 : int ret=-1;
329 : struct sbuf *xb;
330 :
331 10 : if(!(*sb)->path.buf)
332 : {
333 0 : logp("Got NULL path!\n");
334 0 : return -1;
335 : }
336 :
337 : // Check if we have any directories waiting to be restored.
338 10 : while((xb=slist->head))
339 : {
340 0 : if(is_subdir(xb->path.buf, (*sb)->path.buf))
341 : {
342 : // We are still in a subdir.
343 : break;
344 : }
345 : else
346 : {
347 : // Can now restore xb because nothing else is fiddling
348 : // in a subdirectory.
349 0 : if(restore_sbuf(asfd, xb, bu,
350 : act, sdirs, cntr_status, cconfs, manifest,
351 : slist))
352 : goto end;
353 0 : slist->head=xb->next;
354 0 : sbuf_free(&xb);
355 : }
356 : }
357 :
358 : /* If it is a directory, need to remember it and restore it later, so
359 : that the permissions come out right. */
360 : /* Meta data of directories will also have the stat stuff set to be a
361 : directory, so will also come out at the end. */
362 : /* FIX THIS: for Windows, need to read and remember the blocks that
363 : go with the directories. Probably have to do the same for metadata
364 : that goes with directories. */
365 10 : if(S_ISDIR((*sb)->statp.st_mode)
366 : // Hack for metadata for now - just do it straight away.
367 0 : && !sbuf_is_metadata(*sb))
368 : {
369 : // Add to the head of the list instead of the tail.
370 0 : (*sb)->next=slist->head;
371 0 : slist->head=*sb;
372 :
373 0 : *last_ent_was_dir=1;
374 :
375 : // Allocate a new sb.
376 0 : if(!(*sb=sbuf_alloc())) goto end;
377 : }
378 : else
379 : {
380 10 : *last_ent_was_dir=0;
381 10 : if(restore_sbuf(asfd, *sb, bu,
382 : act, sdirs, cntr_status, cconfs, manifest,
383 : slist))
384 : goto end;
385 : }
386 : ret=0;
387 : end:
388 : return ret;
389 : }
390 :
391 : static int restore_remaining_dirs(struct asfd *asfd, struct bu *bu,
392 : struct slist *slist, enum action act, struct sdirs *sdirs,
393 : struct conf **cconfs)
394 : {
395 1 : int ret=-1;
396 : struct sbuf *sb;
397 : // Restore any directories that are left in the list.
398 1 : for(sb=slist->head; sb; sb=sb->next)
399 : {
400 0 : if(restore_sbuf_all(asfd, sb, bu, act, sdirs, cconfs))
401 : goto end;
402 : }
403 : ret=0;
404 : end:
405 : return ret;
406 : }
407 :
408 1 : static int restore_stream(struct asfd *asfd, struct sdirs *sdirs,
409 : struct slist *slist, struct bu *bu, const char *manifest,
410 : regex_t *regex, int srestore, struct conf **cconfs, enum action act,
411 : enum cntr_status cntr_status)
412 : {
413 1 : int ret=-1;
414 1 : int last_ent_was_dir=0;
415 1 : struct sbuf *sb=NULL;
416 1 : struct iobuf *rbuf=asfd->rbuf;
417 1 : struct manio *manio=NULL;
418 1 : struct cntr *cntr=get_cntr(cconfs);
419 : struct iobuf interrupt;
420 1 : struct fzp *rl_fzp=NULL;
421 1 : struct iobuf *rl_iobuf=NULL;
422 :
423 1 : iobuf_init(&interrupt);
424 :
425 1 : if(maybe_open_restore_list(cconfs, &rl_fzp, &rl_iobuf, sdirs))
426 : goto end;
427 :
428 1 : if(!(manio=manio_open(manifest, "rb"))
429 1 : || !(sb=sbuf_alloc()))
430 : goto end;
431 :
432 : while(1)
433 : {
434 11 : iobuf_free_content(rbuf);
435 11 : if(asfd->as->read_quick(asfd->as))
436 : {
437 0 : logp("read quick error\n");
438 0 : goto end;
439 : }
440 11 : if(rbuf->buf) switch(rbuf->cmd)
441 : {
442 : case CMD_MESSAGE:
443 : case CMD_WARNING:
444 : {
445 0 : log_recvd(rbuf, cntr, 0);
446 0 : continue;
447 : }
448 : case CMD_INTERRUPT:
449 : // Client wanted to interrupt the
450 : // sending of a file. But if we are
451 : // here, we have already moved on.
452 : // Ignore.
453 0 : continue;
454 : default:
455 0 : iobuf_log_unexpected(rbuf, __func__);
456 0 : goto end;
457 : }
458 :
459 11 : switch(manio_read(manio, sb))
460 : {
461 : case 0: break; // Keep going.
462 1 : case 1: ret=0; goto end; // Finished OK.
463 : default: goto end; // Error;
464 : }
465 :
466 10 : if(want_to_restore(asfd, srestore, rl_fzp, rl_iobuf,
467 : sb, regex, act, cconfs))
468 : {
469 10 : if(restore_ent(asfd, &sb, slist,
470 : bu, act, sdirs, cntr_status, cconfs,
471 : &last_ent_was_dir, manifest))
472 : goto end;
473 : }
474 : else
475 : {
476 0 : if(sbuf_is_filedata(sb) || sbuf_is_vssdata(sb))
477 : {
478 : // Add it to the list of filedata that was not
479 : // restored.
480 0 : struct f_link **bucket=NULL;
481 0 : if(!linkhash_search(&sb->statp, &bucket)
482 0 : && linkhash_add(sb->path.buf, &sb->statp, bucket))
483 : goto end;
484 : }
485 : }
486 :
487 10 : sbuf_free_content(sb);
488 : }
489 : end:
490 1 : iobuf_free(&rl_iobuf);
491 1 : fzp_close(&rl_fzp);
492 1 : sbuf_free(&sb);
493 1 : iobuf_free_content(rbuf);
494 1 : iobuf_free_content(&interrupt);
495 1 : manio_close(&manio);
496 1 : return ret;
497 : }
498 :
499 1 : static int actual_restore(struct asfd *asfd, struct bu *bu,
500 : const char *manifest, regex_t *regex, int srestore, enum action act,
501 : struct sdirs *sdirs, enum cntr_status cntr_status, struct conf **cconfs)
502 : {
503 1 : int ret=-1;
504 : // For out-of-sequence directory restoring so that the
505 : // timestamps come out right:
506 1 : struct slist *slist=NULL;
507 1 : struct cntr *cntr=NULL;
508 :
509 1 : if(linkhash_init()
510 1 : || !(slist=slist_alloc()))
511 : goto end;
512 :
513 1 : if(restore_stream(asfd, sdirs, slist,
514 : bu, manifest, regex,
515 : srestore, cconfs, act, cntr_status))
516 : goto end;
517 :
518 2 : if(restore_remaining_dirs(asfd, bu, slist,
519 : act, sdirs, cconfs)) goto end;
520 :
521 1 : if(cconfs) cntr=get_cntr(cconfs);
522 1 : cntr_set_bytes(cntr, asfd);
523 1 : cntr_print(cntr, act);
524 1 : if(cntr_stats_to_file(cntr, bu->path, act))
525 : goto end;
526 1 : ret=0;
527 : end:
528 1 : slist_free(&slist);
529 1 : linkhash_free();
530 1 : return ret;
531 : }
532 :
533 1 : static int get_logpaths(struct bu *bu, const char *file,
534 : char **logpath, char **logpathz)
535 : {
536 1 : if(!(*logpath=prepend_s(bu->path, file))
537 1 : || !(*logpathz=prepend(*logpath, ".gz")))
538 : return -1;
539 : return 0;
540 : }
541 :
542 1 : static void parallelism_warnings(struct asfd *asfd, struct conf **cconfs,
543 : struct sdirs *sdirs, struct bu *bu)
544 : {
545 : struct bu *b;
546 :
547 1 : if(lock_test(sdirs->lock_storage_for_write->path))
548 : {
549 0 : logm(asfd, cconfs, "Another process is currently backing up or deleting for this client.\n");
550 0 : return;
551 : }
552 :
553 1 : if(!check_for_rubble(sdirs))
554 : return;
555 :
556 0 : for(b=bu; b && b->next; b=b->next)
557 : {
558 0 : if(b->flags & BU_CURRENT)
559 : break; // Warning.
560 0 : if(b->flags & BU_HARDLINKED)
561 : return; // No warning.
562 : }
563 :
564 0 : logw(asfd, get_cntr(cconfs),
565 : "The latest backup needs recovery, but continuing anyway.\n");
566 : }
567 :
568 1 : static int restore_manifest(struct asfd *asfd, struct bu *bu,
569 : regex_t *regex, int srestore, enum action act, struct sdirs *sdirs,
570 : char **dir_for_notify, struct conf **cconfs)
571 : {
572 1 : int ret=-1;
573 1 : char *manifest=NULL;
574 1 : char *logpath=NULL;
575 1 : char *logpathz=NULL;
576 : enum cntr_status cntr_status;
577 1 : struct lock *lock=NULL;
578 1 : char *lockfile=NULL;
579 : static int manifest_count=0;
580 :
581 1 : if(!(lockfile=prepend_s(bu->path, "lockfile.read"))
582 1 : || !(lock=lock_alloc_and_init(lockfile)))
583 : goto end;
584 1 : lock_get(lock);
585 1 : if(lock->status!=GET_LOCK_GOT)
586 : {
587 0 : char msg[256]="";
588 0 : snprintf(msg, sizeof(msg), "Another process is restoring or verifying backup %s.\n", bu->timestamp);
589 0 : log_and_send(asfd, msg);
590 : goto end;
591 : }
592 :
593 : // For sending status information up to the server.
594 1 : cntr_status=CNTR_STATUS_RESTORING;
595 :
596 1 : if(act==ACTION_RESTORE) cntr_status=CNTR_STATUS_RESTORING;
597 0 : else if(act==ACTION_VERIFY) cntr_status=CNTR_STATUS_VERIFYING;
598 :
599 1 : if((act==ACTION_RESTORE && get_logpaths(bu, "restorelog",
600 : &logpath, &logpathz))
601 1 : || (act==ACTION_VERIFY && get_logpaths(bu, "verifylog",
602 : &logpath, &logpathz))
603 1 : || !(manifest=prepend_s(bu->path, "manifest.gz")))
604 : {
605 0 : log_and_send_oom(asfd);
606 0 : goto end;
607 : }
608 :
609 1 : if(log_fzp_set(logpath, cconfs))
610 : {
611 0 : char msg[256]="";
612 0 : snprintf(msg, sizeof(msg),
613 : "could not open log file: %s", logpath);
614 0 : log_and_send(asfd, msg);
615 : goto end;
616 : }
617 :
618 1 : *dir_for_notify=strdup_w(bu->path, __func__);
619 :
620 1 : log_restore_settings(cconfs, srestore);
621 :
622 : // First, do a pass through the manifest to set up cntr.
623 : // This is the equivalent of a phase1 scan during backup.
624 :
625 1 : if(setup_cntr(asfd, manifest,
626 : regex, srestore, cconfs, act, bu, sdirs))
627 : goto end;
628 :
629 1 : if(!manifest_count)
630 : {
631 : // FIX THIS: Only send the counters once, otherwise the
632 : // client will break on '-b a' because it does not expect
633 : // multiple sets of counters to turn up.
634 : // This means that the client side 'expected' counter will be
635 : // confusing in that case. Live with it for now.
636 : // However, the server side log will be OK.
637 1 : if(cntr_send_bu(asfd, bu, cconfs, cntr_status))
638 : goto end;
639 : }
640 :
641 1 : parallelism_warnings(asfd, cconfs, sdirs, bu);
642 :
643 : // Now, do the actual restore.
644 1 : ret=actual_restore(asfd, bu, manifest,
645 : regex, srestore, act, sdirs, cntr_status, cconfs);
646 : end:
647 1 : log_fzp_set(NULL, cconfs);
648 1 : if(logpath && logpathz)
649 1 : compress_file(logpath, logpathz,
650 : get_int(cconfs[OPT_COMPRESSION]));
651 1 : free_w(&manifest);
652 1 : free_w(&logpath);
653 1 : free_w(&logpathz);
654 1 : free_w(&lockfile);
655 1 : lock_release(lock);
656 1 : lock_free(&lock);
657 1 : manifest_count++;
658 1 : return ret;
659 : }
660 :
661 4 : int do_restore_server(struct asfd *asfd, struct sdirs *sdirs,
662 : enum action act, int srestore,
663 : char **dir_for_notify, struct conf **confs)
664 : {
665 4 : int ret=-1;
666 4 : uint8_t found=0;
667 4 : struct bu *bu=NULL;
668 4 : struct bu *bu_list=NULL;
669 4 : unsigned long bno=0;
670 4 : regex_t *regex=NULL;
671 4 : const char *regexstr=get_string(confs[OPT_REGEX]);
672 4 : const char *backup=get_string(confs[OPT_BACKUP]);
673 4 : int regex_case_insensitive=get_int(confs[OPT_REGEX_CASE_INSENSITIVE]);
674 :
675 4 : logp("in do_restore\n");
676 :
677 4 : if(regexstr
678 1 : && *regexstr
679 1 : && !(regex=regex_compile_restore(regexstr, regex_case_insensitive)))
680 : {
681 1 : char msg[256]="";
682 1 : snprintf(msg, sizeof(msg), "unable to compile regex: %s\n",
683 : regexstr);
684 1 : log_and_send(asfd, msg);
685 : goto end;
686 : }
687 :
688 3 : if(bu_get_list(sdirs, &bu_list))
689 : goto end;
690 :
691 3 : if(bu_list &&
692 : (!backup
693 1 : || !*backup
694 1 : || (!(bno=strtoul(backup, NULL, 10)) && *backup!='a')))
695 : {
696 0 : found=1;
697 : // No backup specified, do the most recent.
698 0 : for(bu=bu_list; bu && bu->next; bu=bu->next) { }
699 0 : ret=restore_manifest(asfd, bu, regex, srestore,
700 : act, sdirs, dir_for_notify, confs);
701 : }
702 :
703 3 : if(!found) for(bu=bu_list; bu; bu=bu->next)
704 : {
705 1 : if(!strcmp(bu->timestamp, backup)
706 1 : || bu->bno==bno || (backup && *backup=='a'))
707 : {
708 1 : found=1;
709 : //logp("got: %s\n", bu->path);
710 1 : ret|=restore_manifest(asfd, bu, regex, srestore,
711 : act, sdirs, dir_for_notify, confs);
712 1 : if(backup && *backup=='a')
713 0 : continue;
714 : break;
715 : }
716 : }
717 :
718 3 : bu_list_free(&bu_list);
719 :
720 :
721 3 : if(found)
722 : {
723 : // Restore has nearly completed OK.
724 1 : ret=restore_end(asfd, confs);
725 : }
726 : else
727 : {
728 2 : logp("backup not found\n");
729 2 : asfd->write_str(asfd, CMD_ERROR, "backup not found");
730 2 : ret=-1;
731 : }
732 : end:
733 4 : regex_free(®ex);
734 4 : return ret;
735 : }
|