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