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/restore_spool.h"
26 : #include "../protocol2/rabin/rabin.h"
27 : #include "sdirs.h"
28 :
29 5 : static enum asl_ret restore_end_func(struct asfd *asfd,
30 : struct conf **confs, 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 0 : 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,
81 : enum action act, char status, struct conf **cconfs)
82 : {
83 5 : int ars=0;
84 5 : int ret=-1;
85 5 : struct fzp *fzp=NULL;
86 5 : struct sbuf *sb=NULL;
87 5 : struct cntr *cntr=NULL;
88 :
89 5 : cntr=get_cntr(cconfs);
90 5 : if(!cntr) return 0;
91 :
92 : // FIX THIS: this is only trying to work for protocol1.
93 0 : if(get_protocol(cconfs)!=PROTO_1) return 0;
94 :
95 0 : if(!(sb=sbuf_alloc(PROTO_1))) goto end;
96 0 : if(!(fzp=fzp_gzopen(manifest, "rb")))
97 : {
98 0 : log_and_send(asfd, "could not open manifest");
99 : goto end;
100 : }
101 : while(1)
102 : {
103 0 : if((ars=sbuf_fill_from_file(sb, fzp, NULL, NULL)))
104 : {
105 0 : if(ars<0) goto end;
106 : // ars==1 means end ok
107 : break;
108 : }
109 : else
110 : {
111 0 : if(want_to_restore(srestore, sb, regex, cconfs))
112 : {
113 0 : cntr_add_phase1(cntr, sb->path.cmd, 0);
114 0 : if(sb->endfile.buf)
115 : cntr_add_val(cntr,
116 : CMD_BYTES_ESTIMATED,
117 : strtoull(sb->endfile.buf,
118 0 : NULL, 10), 0);
119 : }
120 : }
121 0 : sbuf_free_content(sb);
122 : }
123 0 : ret=0;
124 : end:
125 0 : sbuf_free(&sb);
126 0 : fzp_close(&fzp);
127 : return ret;
128 : }
129 :
130 : static int restore_sbuf(struct asfd *asfd, struct sbuf *sb, struct bu *bu,
131 : enum action act, struct sdirs *sdirs, enum cntr_status cntr_status,
132 : struct conf **cconfs, struct sbuf *need_data, const char *manifest,
133 : struct slist *slist);
134 :
135 : // Used when restoring a hard link that we have not restored the destination
136 : // for. Read through the manifest from the beginning and substitute the path
137 : // and data to the new location.
138 0 : static int hard_link_substitution(struct asfd *asfd,
139 : struct sbuf *sb, struct f_link *lp,
140 : struct bu *bu, enum action act, struct sdirs *sdirs,
141 : enum cntr_status cntr_status, struct conf **cconfs,
142 : const char *manifest, struct slist *slist)
143 : {
144 0 : int ret=-1;
145 0 : struct sbuf *need_data=NULL;
146 0 : int last_ent_was_dir=0;
147 0 : struct sbuf *hb=NULL;
148 0 : struct manio *manio=NULL;
149 0 : struct blk *blk=NULL;
150 : int pcmp;
151 0 : enum protocol protocol=get_protocol(cconfs);
152 0 : struct cntr *cntr=get_cntr(cconfs);
153 :
154 0 : if(!(manio=manio_open(manifest, "rb", protocol))
155 0 : || !(need_data=sbuf_alloc(protocol))
156 0 : || !(hb=sbuf_alloc(protocol)))
157 : goto end;
158 :
159 0 : if(protocol==PROTO_2)
160 : {
161 0 : if(!(blk=blk_alloc()))
162 : goto end;
163 : }
164 :
165 : while(1)
166 : {
167 0 : switch(manio_read_with_blk(manio,
168 0 : hb, need_data->path.buf?blk:NULL, sdirs))
169 : {
170 : case 0: break; // Keep going.
171 0 : case 1: ret=0; goto end; // Finished OK.
172 : default: goto end; // Error;
173 : }
174 :
175 0 : if(protocol==PROTO_2)
176 : {
177 0 : if(hb->endfile.buf)
178 : {
179 0 : sbuf_free_content(hb);
180 : continue;
181 : }
182 0 : if(blk->data)
183 : {
184 0 : if(protocol2_extra_restore_stream_bits(asfd,
185 : blk, slist, act, need_data,
186 0 : last_ent_was_dir, cntr)) goto end;
187 : continue;
188 : }
189 0 : sbuf_free_content(need_data);
190 : }
191 :
192 0 : pcmp=pathcmp(lp->name, hb->path.buf);
193 :
194 0 : if(!pcmp && (sbuf_is_filedata(hb) || sbuf_is_vssdata(hb)))
195 : {
196 : // Copy the path from sb to hb.
197 0 : free_w(&hb->path.buf);
198 0 : if(!(hb->path.buf=strdup_w(sb->path.buf, __func__)))
199 : goto end;
200 : // Should now be able to restore the original data
201 : // to the new location.
202 : ret=restore_sbuf(asfd, hb, bu, act, sdirs,
203 0 : 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 : return hard_link_substitution(asfd, sb, lp,
242 : bu, act, sdirs,
243 0 : 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 : return restore_sbuf_protocol1(asfd, sb, bu,
254 10 : act, sdirs, cntr_status, cconfs);
255 : }
256 : else
257 : {
258 : return restore_sbuf_protocol2(asfd, sb,
259 32 : act, cntr_status, 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 0 : 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 84 : if(S_ISDIR((*sb)->statp.st_mode)
313 : // Hack for metadata for now - just do it straight away.
314 42 : && !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 42 : 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 : enum cntr_status cntr_status, 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 0 : sdirs, cntr_status, cconfs))
353 : goto end;
354 : }
355 : else
356 : {
357 0 : if(restore_sbuf_protocol2(asfd, sb, act,
358 0 : cntr_status, 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 4 : CMD_GEN, "restore_stream")
395 8 : || asfd_read_expect(asfd,
396 4 : CMD_GEN, "restore_stream_ok"))
397 : goto end;
398 : }
399 : }
400 :
401 10 : if(!(manio=manio_open(manifest, "rb", protocol))
402 5 : || !(need_data=sbuf_alloc(protocol))
403 10 : || !(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 : 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 60 : &interrupt))
466 : {
467 32 : if(blk->data)
468 32 : blk->data=NULL;
469 : 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 316 : last_ent_was_dir, cntr)) goto end;
477 : 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 42 : 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 5 : int do_restore_stream=1;
517 : // For out-of-sequence directory restoring so that the
518 : // timestamps come out right:
519 5 : struct slist *slist=NULL;
520 5 : struct cntr *cntr=NULL;
521 :
522 10 : if(linkhash_init()
523 5 : || !(slist=slist_alloc()))
524 : goto end;
525 :
526 5 : if(get_protocol(cconfs)==PROTO_2)
527 : {
528 4 : if(rblk_init())
529 : goto end;
530 4 : switch(maybe_restore_spool(asfd, manifest, sdirs, bu,
531 4 : srestore, regex, cconfs, slist, act, cntr_status))
532 : {
533 : case 1: do_restore_stream=0; break;
534 4 : case 0: do_restore_stream=1; break;
535 : default: goto end; // Error;
536 : }
537 : }
538 10 : if(do_restore_stream && restore_stream(asfd, sdirs, slist,
539 : bu, manifest, regex,
540 5 : srestore, cconfs, act, cntr_status))
541 : goto end;
542 :
543 5 : if(restore_remaining_dirs(asfd, bu, slist,
544 5 : act, sdirs, cntr_status, cconfs)) goto end;
545 :
546 5 : if(cconfs) cntr=get_cntr(cconfs);
547 5 : cntr_print(cntr, act);
548 5 : cntr_stats_to_file(cntr, bu->path, act, cconfs);
549 : end:
550 5 : slist_free(&slist);
551 5 : linkhash_free();
552 5 : rblk_free();
553 5 : return ret;
554 : }
555 :
556 5 : static int get_logpaths(struct bu *bu, const char *file,
557 : char **logpath, char **logpathz)
558 : {
559 10 : if(!(*logpath=prepend_s(bu->path, file))
560 5 : || !(*logpathz=prepend(*logpath, ".gz")))
561 : return -1;
562 : return 0;
563 : }
564 :
565 10 : static int restore_manifest(struct asfd *asfd, struct bu *bu,
566 : regex_t *regex, int srestore, enum action act, struct sdirs *sdirs,
567 : char **dir_for_notify, struct conf **cconfs)
568 : {
569 5 : int ret=-1;
570 5 : char *manifest=NULL;
571 5 : char *logpath=NULL;
572 5 : char *logpathz=NULL;
573 : enum protocol protocol;
574 : enum cntr_status cntr_status;
575 :
576 5 : protocol=get_protocol(cconfs);
577 :
578 5 : if(protocol==PROTO_2
579 5 : && blks_generate_init())
580 : goto end;
581 :
582 : // For sending status information up to the server.
583 5 : cntr_status=CNTR_STATUS_RESTORING;
584 :
585 5 : if(act==ACTION_RESTORE) cntr_status=CNTR_STATUS_RESTORING;
586 0 : else if(act==ACTION_VERIFY) cntr_status=CNTR_STATUS_VERIFYING;
587 :
588 10 : if((act==ACTION_RESTORE && get_logpaths(bu, "restorelog",
589 5 : &logpath, &logpathz))
590 5 : || (act==ACTION_VERIFY && get_logpaths(bu, "verifylog",
591 0 : &logpath, &logpathz))
592 10 : || !(manifest=prepend_s(bu->path,
593 5 : get_protocol(cconfs)==PROTO_1?
594 5 : "manifest.gz":"manifest")))
595 : {
596 0 : log_and_send_oom(asfd, __func__);
597 0 : goto end;
598 : }
599 :
600 5 : if(log_fzp_set(logpath, cconfs))
601 : {
602 0 : char msg[256]="";
603 : snprintf(msg, sizeof(msg),
604 0 : "could not open log file: %s", logpath);
605 0 : log_and_send(asfd, msg);
606 : goto end;
607 : }
608 :
609 5 : *dir_for_notify=strdup_w(bu->path, __func__);
610 :
611 5 : log_restore_settings(cconfs, srestore);
612 :
613 : // First, do a pass through the manifest to set up cntr.
614 : // This is the equivalent of a phase1 scan during backup.
615 :
616 5 : if(setup_cntr(asfd, manifest,
617 5 : regex, srestore, act, cntr_status, cconfs))
618 : goto end;
619 :
620 10 : if(get_int(cconfs[OPT_SEND_CLIENT_CNTR])
621 5 : && cntr_send(get_cntr(cconfs)))
622 : goto end;
623 :
624 : // Now, do the actual restore.
625 : ret=actual_restore(asfd, bu, manifest,
626 5 : 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 : return ret;
636 : }
637 :
638 6 : int do_restore_server(struct asfd *asfd, struct sdirs *sdirs,
639 : enum action act, int srestore,
640 : char **dir_for_notify, struct conf **confs)
641 : {
642 6 : int ret=-1;
643 6 : uint8_t found=0;
644 6 : struct bu *bu=NULL;
645 6 : struct bu *bu_list=NULL;
646 6 : unsigned long bno=0;
647 6 : regex_t *regex=NULL;
648 6 : const char *regexstr=get_string(confs[OPT_REGEX]);
649 6 : const char *backup=get_string(confs[OPT_BACKUP]);
650 :
651 6 : logp("in do_restore\n");
652 :
653 6 : if(regexstr
654 1 : && *regexstr
655 7 : && !(regex=regex_compile(regexstr)))
656 : {
657 1 : char msg[256]="";
658 : snprintf(msg, sizeof(msg), "unable to compile regex: %s\n",
659 : regexstr);
660 1 : log_and_send(asfd, msg);
661 : goto end;
662 : }
663 :
664 5 : if(bu_get_list(sdirs, &bu_list))
665 : goto end;
666 :
667 10 : if(bu_list &&
668 : (!backup
669 5 : || !*backup
670 5 : || (!(bno=strtoul(backup, NULL, 10)) && *backup!='a')))
671 : {
672 0 : found=1;
673 : // No backup specified, do the most recent.
674 0 : for(bu=bu_list; bu && bu->next; bu=bu->next) { }
675 : ret=restore_manifest(asfd, bu, regex, srestore,
676 0 : act, sdirs, dir_for_notify, confs);
677 : }
678 :
679 5 : if(!found) for(bu=bu_list; bu; bu=bu->next)
680 : {
681 5 : if(!strcmp(bu->timestamp, backup)
682 5 : || bu->bno==bno || (backup && *backup=='a'))
683 : {
684 5 : found=1;
685 : //logp("got: %s\n", bu->path);
686 : ret|=restore_manifest(asfd, bu, regex, srestore,
687 5 : act, sdirs, dir_for_notify, confs);
688 5 : if(backup && *backup=='a')
689 : continue;
690 : break;
691 : }
692 : }
693 :
694 5 : bu_list_free(&bu_list);
695 :
696 :
697 5 : if(found)
698 : {
699 : // Restore has nearly completed OK.
700 5 : ret=restore_end(asfd, confs);
701 : }
702 : else
703 : {
704 0 : logp("backup not found\n");
705 0 : asfd->write_str(asfd, CMD_ERROR, "backup not found");
706 0 : ret=-1;
707 : }
708 : end:
709 6 : regex_free(®ex);
710 6 : return ret;
711 : }
|