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