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 : // Should now be able to restore the original data
200 : // to the new location.
201 0 : ret=restore_sbuf(asfd, hb, bu, act, sdirs,
202 : cntr_status, cconfs, need_data, manifest, slist);
203 : // May still need to get protocol2 data.
204 0 : if(!ret && need_data->path.buf) continue;
205 : break;
206 : }
207 :
208 0 : sbuf_free_content(hb);
209 : // Break out once we have gone past the entry that we are
210 : // interested in.
211 0 : if(pcmp<0) break;
212 : }
213 : end:
214 0 : blk_free(&blk);
215 0 : sbuf_free(&hb);
216 0 : manio_close(&manio);
217 0 : return ret;
218 : }
219 :
220 42 : static int restore_sbuf(struct asfd *asfd, struct sbuf *sb, struct bu *bu,
221 : enum action act, struct sdirs *sdirs, enum cntr_status cntr_status,
222 : struct conf **cconfs, struct sbuf *need_data, const char *manifest,
223 : struct slist *slist)
224 : {
225 : //printf("%s: %s\n", act==ACTION_RESTORE?"restore":"verify", sb->path.buf);
226 42 : if(write_status(cntr_status, sb->path.buf, get_cntr(cconfs)))
227 : return -1;
228 :
229 42 : if(sb->path.cmd==CMD_HARD_LINK)
230 : {
231 1 : struct f_link *lp=NULL;
232 1 : struct f_link **bucket=NULL;
233 1 : if((lp=linkhash_search(&sb->statp, &bucket)))
234 : {
235 : // It is in the list of stuff that is in the manifest,
236 : // but was skipped on this restore.
237 : // Need to go through the manifest from the beginning,
238 : // and substitute in the data to restore to this
239 : // location.
240 0 : return hard_link_substitution(asfd, sb, lp,
241 : bu, act, sdirs,
242 : cntr_status, cconfs, manifest, slist);
243 : // FIX THIS: Would be nice to remember the new link
244 : // location so that further hard links would link to
245 : // it instead of doing the hard_link_substitution
246 : // business over again.
247 : }
248 : }
249 :
250 42 : if(get_protocol(cconfs)==PROTO_1)
251 : {
252 10 : return restore_sbuf_protocol1(asfd, sb, bu,
253 : act, sdirs, cconfs);
254 : }
255 : else
256 : {
257 32 : return restore_sbuf_protocol2(asfd, sb,
258 : act, get_cntr(cconfs), need_data);
259 : }
260 : }
261 :
262 42 : int restore_ent(struct asfd *asfd,
263 : struct sbuf **sb,
264 : struct slist *slist,
265 : struct bu *bu,
266 : enum action act,
267 : struct sdirs *sdirs,
268 : enum cntr_status cntr_status,
269 : struct conf **cconfs,
270 : struct sbuf *need_data,
271 : int *last_ent_was_dir,
272 : const char *manifest)
273 : {
274 42 : int ret=-1;
275 : struct sbuf *xb;
276 :
277 42 : if(!(*sb)->path.buf)
278 : {
279 0 : logp("Got NULL path!\n");
280 0 : return -1;
281 : }
282 :
283 : // Check if we have any directories waiting to be restored.
284 42 : while((xb=slist->head))
285 : {
286 0 : if(is_subdir(xb->path.buf, (*sb)->path.buf))
287 : {
288 : // We are still in a subdir.
289 : break;
290 : }
291 : else
292 : {
293 : // Can now restore xb because nothing else is fiddling
294 : // in a subdirectory.
295 0 : if(restore_sbuf(asfd, xb, bu,
296 : act, sdirs, cntr_status, cconfs, need_data, manifest,
297 : slist))
298 : goto end;
299 0 : slist->head=xb->next;
300 0 : sbuf_free(&xb);
301 : }
302 : }
303 :
304 : /* If it is a directory, need to remember it and restore it later, so
305 : that the permissions come out right. */
306 : /* Meta data of directories will also have the stat stuff set to be a
307 : directory, so will also come out at the end. */
308 : /* FIX THIS: for Windows, need to read and remember the blocks that
309 : go with the directories. Probably have to do the same for metadata
310 : that goes with directories. */
311 42 : if(S_ISDIR((*sb)->statp.st_mode)
312 : // Hack for metadata for now - just do it straight away.
313 0 : && !sbuf_is_metadata(*sb))
314 : {
315 : // Add to the head of the list instead of the tail.
316 0 : (*sb)->next=slist->head;
317 0 : slist->head=*sb;
318 :
319 0 : *last_ent_was_dir=1;
320 :
321 : // Allocate a new sb.
322 0 : if(!(*sb=sbuf_alloc(get_protocol(cconfs)))) goto end;
323 : }
324 : else
325 : {
326 42 : *last_ent_was_dir=0;
327 42 : if(restore_sbuf(asfd, *sb, bu,
328 : act, sdirs, cntr_status, cconfs, need_data, manifest,
329 : slist))
330 : goto end;
331 : }
332 : ret=0;
333 : end:
334 42 : return ret;
335 : }
336 :
337 5 : static int restore_remaining_dirs(struct asfd *asfd, struct bu *bu,
338 : struct slist *slist, enum action act, struct sdirs *sdirs,
339 : struct conf **cconfs)
340 : {
341 5 : int ret=-1;
342 : struct sbuf *sb;
343 5 : struct sbuf *need_data=NULL;
344 5 : if(!(need_data=sbuf_alloc(get_protocol(cconfs)))) goto end;
345 : // Restore any directories that are left in the list.
346 5 : for(sb=slist->head; sb; sb=sb->next)
347 : {
348 0 : if(get_protocol(cconfs)==PROTO_1)
349 : {
350 0 : if(restore_sbuf_protocol1(asfd, sb, bu, act,
351 : sdirs, cconfs))
352 : goto end;
353 : }
354 : else
355 : {
356 0 : if(restore_sbuf_protocol2(asfd, sb, act,
357 : get_cntr(cconfs), need_data))
358 : goto end;
359 : }
360 : }
361 : ret=0;
362 : end:
363 5 : sbuf_free(&need_data);
364 5 : return ret;
365 : }
366 :
367 5 : static int restore_stream(struct asfd *asfd, struct sdirs *sdirs,
368 : struct slist *slist, struct bu *bu, const char *manifest,
369 : regex_t *regex, int srestore, struct conf **cconfs, enum action act,
370 : enum cntr_status cntr_status)
371 : {
372 5 : int ret=-1;
373 5 : int last_ent_was_dir=0;
374 5 : struct sbuf *sb=NULL;
375 5 : struct iobuf *rbuf=asfd->rbuf;
376 5 : struct manio *manio=NULL;
377 5 : struct blk *blk=NULL;
378 5 : struct sbuf *need_data=NULL;
379 5 : enum protocol protocol=get_protocol(cconfs);
380 5 : struct cntr *cntr=get_cntr(cconfs);
381 : struct iobuf interrupt;
382 5 : iobuf_init(&interrupt);
383 :
384 5 : if(protocol==PROTO_2)
385 : {
386 : static int rs_sent=0;
387 4 : if(!(blk=blk_alloc()))
388 : goto end;
389 4 : if(!rs_sent)
390 : {
391 4 : rs_sent=1;
392 4 : if(asfd->write_str(asfd,
393 : CMD_GEN, "restore_stream")
394 4 : || asfd_read_expect(asfd,
395 : CMD_GEN, "restore_stream_ok"))
396 : goto end;
397 : }
398 : }
399 :
400 5 : if(!(manio=manio_open(manifest, "rb", protocol))
401 5 : || !(need_data=sbuf_alloc(protocol))
402 5 : || !(sb=sbuf_alloc(protocol)))
403 : goto end;
404 :
405 : while(1)
406 : {
407 421 : iobuf_free_content(rbuf);
408 421 : if(asfd->as->read_quick(asfd->as))
409 : {
410 0 : logp("read quick error\n");
411 0 : goto end;
412 : }
413 421 : if(rbuf->buf) switch(rbuf->cmd)
414 : {
415 : case CMD_MESSAGE:
416 : case CMD_WARNING:
417 : {
418 0 : log_recvd(rbuf, cntr, 0);
419 0 : continue;
420 : }
421 : case CMD_INTERRUPT:
422 5 : if(protocol==PROTO_2)
423 : {
424 5 : iobuf_free_content(&interrupt);
425 5 : iobuf_move(&interrupt, rbuf);
426 : }
427 : // PROTO_1:
428 : // Client wanted to interrupt the
429 : // sending of a file. But if we are
430 : // here, we have already moved on.
431 : // Ignore.
432 5 : continue;
433 : default:
434 0 : iobuf_log_unexpected(rbuf, __func__);
435 0 : goto end;
436 : }
437 :
438 416 : switch(manio_read_with_blk(manio,
439 416 : sb, need_data->path.buf?blk:NULL, sdirs))
440 : {
441 : case 0: break; // Keep going.
442 5 : case 1: ret=0; goto end; // Finished OK.
443 : default: goto end; // Error;
444 : }
445 :
446 411 : if(protocol==PROTO_2)
447 : {
448 401 : if(sb->endfile.buf)
449 : {
450 21 : if(act==ACTION_RESTORE
451 21 : && asfd->write(asfd, &sb->endfile))
452 : goto end;
453 21 : sbuf_free_content(sb);
454 21 : iobuf_free_content(&interrupt);
455 21 : continue;
456 : }
457 380 : if(interrupt.buf)
458 : {
459 61 : if(!need_data->path.buf)
460 : {
461 1 : iobuf_free_content(&interrupt);
462 : }
463 60 : else if(!iobuf_pathcmp(&need_data->path,
464 : &interrupt))
465 : {
466 32 : if(blk->data)
467 32 : blk->data=NULL;
468 32 : continue;
469 : }
470 : }
471 348 : if(blk->data)
472 : {
473 316 : if(protocol2_extra_restore_stream_bits(asfd,
474 : blk, slist, act, need_data,
475 : last_ent_was_dir, cntr)) goto end;
476 316 : continue;
477 : }
478 32 : sbuf_free_content(need_data);
479 : }
480 :
481 42 : if(want_to_restore(srestore, sb, regex, cconfs))
482 : {
483 42 : if(restore_ent(asfd, &sb, slist,
484 : bu, act, sdirs, cntr_status, cconfs,
485 : need_data, &last_ent_was_dir, manifest))
486 : goto end;
487 : }
488 0 : else if(sbuf_is_filedata(sb) || sbuf_is_vssdata(sb))
489 : {
490 : // Add it to the list of filedata that was not
491 : // restored.
492 0 : struct f_link **bucket=NULL;
493 0 : if(!linkhash_search(&sb->statp, &bucket)
494 0 : && linkhash_add(sb->path.buf, &sb->statp, bucket))
495 : goto end;
496 : }
497 :
498 42 : sbuf_free_content(sb);
499 : }
500 : end:
501 5 : blk_free(&blk);
502 5 : sbuf_free(&sb);
503 5 : sbuf_free(&need_data);
504 5 : iobuf_free_content(rbuf);
505 5 : iobuf_free_content(&interrupt);
506 5 : manio_close(&manio);
507 5 : return ret;
508 : }
509 :
510 5 : static int actual_restore(struct asfd *asfd, struct bu *bu,
511 : const char *manifest, regex_t *regex, int srestore, enum action act,
512 : struct sdirs *sdirs, enum cntr_status cntr_status, struct conf **cconfs)
513 : {
514 5 : int ret=-1;
515 : // For out-of-sequence directory restoring so that the
516 : // timestamps come out right:
517 5 : struct slist *slist=NULL;
518 5 : struct cntr *cntr=NULL;
519 :
520 5 : if(linkhash_init()
521 5 : || !(slist=slist_alloc()))
522 : goto end;
523 :
524 5 : if(get_protocol(cconfs)==PROTO_2
525 4 : && rblk_init())
526 : goto end;
527 :
528 5 : if(restore_stream(asfd, sdirs, slist,
529 : bu, manifest, regex,
530 : srestore, cconfs, act, cntr_status))
531 : goto end;
532 :
533 5 : if(restore_remaining_dirs(asfd, bu, slist,
534 : act, sdirs, cconfs)) goto end;
535 :
536 5 : if(cconfs) cntr=get_cntr(cconfs);
537 5 : cntr_print(cntr, act, asfd);
538 5 : cntr_stats_to_file(cntr, bu->path, act);
539 : end:
540 5 : slist_free(&slist);
541 5 : linkhash_free();
542 5 : rblk_free();
543 5 : return ret;
544 : }
545 :
546 5 : static int get_logpaths(struct bu *bu, const char *file,
547 : char **logpath, char **logpathz)
548 : {
549 5 : if(!(*logpath=prepend_s(bu->path, file))
550 5 : || !(*logpathz=prepend(*logpath, ".gz")))
551 : return -1;
552 : return 0;
553 : }
554 :
555 10 : static int restore_manifest(struct asfd *asfd, struct bu *bu,
556 : regex_t *regex, int srestore, enum action act, struct sdirs *sdirs,
557 : char **dir_for_notify, struct conf **cconfs)
558 : {
559 5 : int ret=-1;
560 5 : char *manifest=NULL;
561 5 : char *logpath=NULL;
562 5 : char *logpathz=NULL;
563 : enum protocol protocol;
564 : enum cntr_status cntr_status;
565 : static int manifest_count=0;
566 :
567 5 : protocol=get_protocol(cconfs);
568 :
569 5 : if(protocol==PROTO_2
570 4 : && blks_generate_init())
571 : goto end;
572 :
573 : // For sending status information up to the server.
574 5 : cntr_status=CNTR_STATUS_RESTORING;
575 :
576 5 : if(act==ACTION_RESTORE) cntr_status=CNTR_STATUS_RESTORING;
577 0 : else if(act==ACTION_VERIFY) cntr_status=CNTR_STATUS_VERIFYING;
578 :
579 10 : if((act==ACTION_RESTORE && get_logpaths(bu, "restorelog",
580 : &logpath, &logpathz))
581 5 : || (act==ACTION_VERIFY && get_logpaths(bu, "verifylog",
582 : &logpath, &logpathz))
583 5 : || !(manifest=prepend_s(bu->path,
584 5 : get_protocol(cconfs)==PROTO_1?
585 : "manifest.gz":"manifest")))
586 : {
587 0 : log_and_send_oom(asfd);
588 0 : goto end;
589 : }
590 :
591 5 : if(log_fzp_set(logpath, cconfs))
592 : {
593 0 : char msg[256]="";
594 0 : snprintf(msg, sizeof(msg),
595 : "could not open log file: %s", logpath);
596 0 : log_and_send(asfd, msg);
597 : goto end;
598 : }
599 :
600 5 : *dir_for_notify=strdup_w(bu->path, __func__);
601 :
602 5 : log_restore_settings(cconfs, srestore);
603 :
604 : // First, do a pass through the manifest to set up cntr.
605 : // This is the equivalent of a phase1 scan during backup.
606 :
607 5 : if(setup_cntr(asfd, manifest,
608 : regex, srestore, cconfs))
609 : goto end;
610 :
611 5 : if(!manifest_count)
612 : {
613 : // FIX THIS: Only send the counters once, otherwise the
614 : // client will break on '-b a' because it does not expect
615 : // multiple sets of counters to turn up.
616 : // This means that the client side 'expected' counter will be
617 : // confusing in that case. Live with it for now.
618 : // However, the server side log will be OK.
619 5 : if(cntr_send_bu(asfd, bu, cconfs))
620 : goto end;
621 : }
622 :
623 : // Now, do the actual restore.
624 5 : ret=actual_restore(asfd, bu, manifest,
625 : regex, srestore, act, sdirs, cntr_status, cconfs);
626 : end:
627 5 : log_fzp_set(NULL, cconfs);
628 5 : compress_file(logpath, logpathz, get_int(cconfs[OPT_COMPRESSION]));
629 5 : free_w(&manifest);
630 5 : free_w(&logpath);
631 5 : free_w(&logpathz);
632 5 : if(protocol==PROTO_2)
633 4 : blks_generate_free();
634 5 : manifest_count++;
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 1 : && !(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 5 : 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 0 : ret=restore_manifest(asfd, bu, regex, srestore,
676 : 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 5 : ret|=restore_manifest(asfd, bu, regex, srestore,
687 : act, sdirs, dir_for_notify, confs);
688 5 : if(backup && *backup=='a')
689 0 : 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 : }
|