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