Line data Source code
1 : #include "../burp.h"
2 : #include "../cmd.h"
3 : #include "../cntr.h"
4 : #include "../iobuf.h"
5 : #include "../log.h"
6 : #include "../pathcmp.h"
7 : #include "../sbuf.h"
8 : #include "dpth.h"
9 : #include "resume.h"
10 : #include "backup_phase1.h"
11 : #include "protocol1/dpth.h"
12 :
13 : // Used on resume, this just reads the phase1 file and sets up cntr.
14 0 : static int read_phase1(struct manio *p1manio, struct conf **cconfs)
15 : {
16 0 : int ret=-1;
17 : struct sbuf *p1b;
18 0 : struct cntr *cntr=get_cntr(cconfs);
19 0 : if(!(p1b=sbuf_alloc())) return -1;
20 : while(1)
21 : {
22 0 : sbuf_free_content(p1b);
23 0 : switch(manio_read(p1manio, p1b))
24 : {
25 : case 0: break;
26 0 : case 1: ret=0;
27 : default: goto end;
28 : }
29 0 : cntr_add_phase1(cntr, p1b->path.cmd, 0);
30 :
31 0 : if(sbuf_is_estimatable(p1b))
32 0 : cntr_add_val(cntr, CMD_BYTES_ESTIMATED,
33 0 : (uint64_t)p1b->statp.st_size);
34 : }
35 : end:
36 0 : sbuf_free(&p1b);
37 0 : return ret;
38 : }
39 :
40 0 : static int set_higher_datapth(struct sbuf *sb, struct dpth *dpth)
41 : {
42 : // Make sure we end up with the highest datapth we can possibly
43 : // find - dpth_protocol1_set_from_string() will only set it if
44 : // it is higher.
45 0 : if(sb->protocol1 && sb->protocol1->datapth.buf
46 0 : && dpth_protocol1_set_from_string(dpth,
47 : sb->protocol1->datapth.buf))
48 : {
49 0 : logp("unable to set datapath: %s\n",
50 0 : iobuf_to_printable(&sb->protocol1->datapth));
51 : return -1;
52 : }
53 : return 0;
54 : }
55 :
56 : #ifndef UTEST
57 : static
58 : #endif
59 24 : int forward_past_entry(struct manio *manio, struct iobuf *target,
60 : man_off_t **pos)
61 : {
62 24 : struct sbuf *sb=NULL;
63 :
64 24 : if(!(sb=sbuf_alloc()))
65 : goto error;
66 :
67 24 : man_off_t_free(pos);
68 24 : if(!(*pos=manio_tell(manio)))
69 : {
70 0 : logp("Could not manio_tell first pos in %s(): %s\n",
71 0 : __func__, strerror(errno));
72 0 : goto error;
73 : }
74 :
75 : while(1)
76 : {
77 872 : sbuf_free_content(sb);
78 872 : man_off_t_free(pos);
79 872 : if(!(*pos=manio_tell(manio)))
80 : {
81 0 : logp("Could not manio_tell top pos in %s(): %s\n",
82 0 : __func__, strerror(errno));
83 0 : goto error;
84 : }
85 :
86 872 : switch(manio_read(manio, sb))
87 : {
88 : case 0:
89 : break;
90 : case 1:
91 0 : if(!(*pos)->offset)
92 : {
93 : // This is OK. I've seen it happen
94 : // when the current manifest is an
95 : // empty backup.
96 0 : logp("Empty file in %s()\n", __func__);
97 0 : sbuf_free(&sb);
98 0 : return 0;
99 : }
100 0 : logp("End of file in %s()\n", __func__);
101 0 : goto error;
102 : default:
103 0 : logp("Error in %s()\n", __func__);
104 0 : goto error;
105 : }
106 :
107 872 : switch(iobuf_pathcmp(target, &sb->path))
108 : {
109 : case 0:
110 : // Exact match, we want to be past here.
111 24 : man_off_t_free(pos);
112 24 : if(!(*pos=manio_tell(manio)))
113 : {
114 0 : logp("Could not manio_tell pos in %s(): "
115 0 : "%s\n", __func__, strerror(errno));
116 0 : goto error;
117 : }
118 24 : sbuf_free(&sb);
119 24 : return 0;
120 : case -1:
121 : // Gone past the match, we want to return to
122 : // the previous tell.
123 0 : sbuf_free(&sb);
124 0 : return 0;
125 : default:
126 : // Not gone far enough yet, continue.
127 : break;
128 : }
129 : }
130 :
131 : error:
132 0 : sbuf_free(&sb);
133 0 : man_off_t_free(pos);
134 0 : return -1;
135 : }
136 :
137 : #ifndef UTEST
138 : static
139 : #endif
140 44 : int forward_before_entry(struct manio *manio, struct iobuf *target,
141 : struct cntr *cntr, struct dpth *dpth, man_off_t **pos)
142 : {
143 44 : int ars=0;
144 44 : struct sbuf *sb=NULL;
145 :
146 44 : if(!(sb=sbuf_alloc()))
147 : goto error;
148 :
149 44 : man_off_t_free(pos);
150 44 : if(!(*pos=manio_tell(manio)))
151 : {
152 0 : logp("Could not manio_tell first pos in %s(): %s\n",
153 0 : __func__, strerror(errno));
154 0 : goto error;
155 : }
156 :
157 : while(1)
158 : {
159 2146 : if(sb->endfile.buf
160 60 : || (sb->path.buf && !sbuf_is_filedata(sb)))
161 : {
162 2102 : man_off_t_free(pos);
163 2102 : if(!(*pos=manio_tell(manio)))
164 : {
165 0 : logp("Could not manio_tell pos in %s(): "
166 0 : "%s\n", __func__, strerror(errno));
167 0 : goto error;
168 : }
169 : }
170 :
171 2146 : sbuf_free_content(sb);
172 2146 : ars=manio_read(manio, sb);
173 2146 : if(dpth && set_higher_datapth(sb, dpth)) goto error;
174 :
175 2146 : switch(ars)
176 : {
177 : case 0: break;
178 : case 1:
179 2 : sbuf_free(&sb);
180 2 : return 0;
181 : default:
182 8 : logp("Error in %s(), but continuing\n",
183 : __func__);
184 : // Treat error in unchanged manio as
185 : // OK - could have been a short write.
186 8 : sbuf_free(&sb);
187 8 : return 0;
188 : }
189 :
190 2136 : if(iobuf_pathcmp(target, &sb->path)<=0)
191 : {
192 34 : sbuf_free(&sb);
193 34 : return 0;
194 : }
195 :
196 2102 : if(cntr)
197 : {
198 0 : if(sb->endfile.buf)
199 : {
200 0 : uint64_t e=strtoull(sb->endfile.buf, NULL, 10);
201 0 : cntr_add_bytes(cntr, e);
202 : }
203 : }
204 : }
205 :
206 : error:
207 0 : sbuf_free(&sb);
208 0 : man_off_t_free(pos);
209 0 : return -1;
210 : }
211 :
212 : #ifndef UTEST
213 : static
214 : #endif
215 104 : int get_last_good_entry(struct manio *manio, struct iobuf *result,
216 : struct cntr *cntr, struct dpth *dpth, man_off_t **pos)
217 : {
218 104 : int ars=0;
219 104 : int got_vss_start=0;
220 104 : struct sbuf *sb=NULL;
221 : struct iobuf lastpath;
222 :
223 104 : if(!(sb=sbuf_alloc()))
224 : goto error;
225 :
226 104 : iobuf_init(&lastpath);
227 :
228 104 : man_off_t_free(pos);
229 104 : if(!(*pos=manio_tell(manio)))
230 : {
231 0 : logp("Could not manio_tell first pos in %s(): %s\n",
232 0 : __func__, strerror(errno));
233 0 : goto error;
234 : }
235 :
236 : while(1)
237 : {
238 4276 : if(sb->path.buf && !got_vss_start)
239 : {
240 4128 : iobuf_free_content(&lastpath);
241 4128 : iobuf_move(&lastpath, &sb->path);
242 4128 : if(!sbuf_is_filedata(sb)
243 56 : && !sbuf_is_vssdata(sb))
244 : {
245 52 : iobuf_free_content(result);
246 52 : iobuf_move(result, &lastpath);
247 :
248 52 : man_off_t_free(pos);
249 52 : if(!(*pos=manio_tell(manio)))
250 : {
251 0 : logp("Could not manio_tell pos in %s(): %s\n",
252 0 : __func__, strerror(errno));
253 0 : goto error;
254 : }
255 : }
256 : }
257 4276 : if(sb->endfile.buf && !got_vss_start)
258 : {
259 4076 : iobuf_free_content(result);
260 4076 : iobuf_move(result, &lastpath);
261 :
262 4076 : man_off_t_free(pos);
263 4076 : if(!(*pos=manio_tell(manio)))
264 : {
265 0 : logp("Could not manio_tell pos in %s(): %s\n",
266 0 : __func__, strerror(errno));
267 0 : goto error;
268 : }
269 : }
270 :
271 4276 : sbuf_free_content(sb);
272 4276 : ars=manio_read(manio, sb);
273 4276 : if(dpth && set_higher_datapth(sb, dpth)) goto error;
274 :
275 4276 : switch(ars)
276 : {
277 : case 0: break;
278 80 : case 1: iobuf_free_content(&lastpath);
279 80 : sbuf_free(&sb);
280 80 : return 0;
281 : default:
282 24 : if(result->buf)
283 20 : logp("Error after %s in %s()\n",
284 : iobuf_to_printable(result),
285 : __func__);
286 : // Treat error in changed manio as
287 : // OK - could have been a short write.
288 24 : iobuf_free_content(&lastpath);
289 24 : sbuf_free(&sb);
290 24 : return 0;
291 : }
292 :
293 : // Some hacks for split_vss.
294 4172 : switch(sb->path.cmd)
295 : {
296 : case CMD_VSS:
297 : case CMD_ENC_VSS:
298 : got_vss_start=1;
299 : break;
300 : case CMD_VSS_T:
301 : case CMD_ENC_VSS_T:
302 : got_vss_start=0;
303 : break;
304 : case CMD_FILE:
305 : case CMD_ENC_FILE:
306 4072 : if(S_ISDIR(sb->statp.st_mode))
307 24 : got_vss_start=0;
308 : break;
309 : default:
310 : break;
311 : }
312 :
313 4172 : if(cntr)
314 : {
315 0 : if(sb->endfile.buf)
316 : {
317 0 : uint64_t e=strtoull(sb->endfile.buf, NULL, 10);
318 0 : cntr_add_bytes(cntr, e);
319 : }
320 : }
321 : }
322 :
323 : error:
324 0 : iobuf_free_content(&lastpath);
325 0 : sbuf_free(&sb);
326 0 : man_off_t_free(pos);
327 0 : return -1;
328 : }
329 :
330 0 : static int add_to_cntr(
331 : struct cntr *cntr,
332 : enum cmd cmd,
333 : enum cntr_manio cntr_manio
334 : ) {
335 0 : switch(cntr_manio)
336 : {
337 : case CNTR_MANIO_NEW:
338 0 : cntr_add(cntr, cmd, 0);
339 0 : break;
340 : case CNTR_MANIO_CHANGED:
341 0 : cntr_add_changed(cntr, cmd);
342 0 : break;
343 : case CNTR_MANIO_SAME:
344 0 : cntr_add_same(cntr, cmd);
345 0 : break;
346 : case CNTR_MANIO_DELETED:
347 0 : cntr_add_deleted(cntr, cmd);
348 0 : break;
349 : default:
350 0 : logp("Unknown counter in %s(): %c\n",
351 : __func__, cntr_manio);
352 0 : return -1;
353 : }
354 : return 0;
355 : }
356 :
357 0 : static int forward_past_entry_counter(
358 : struct manio *manio,
359 : struct iobuf *target,
360 : struct cntr *cntr,
361 : man_off_t **pos
362 : ) {
363 : char what[1];
364 : struct iobuf rbuf;
365 :
366 0 : iobuf_init(&rbuf);
367 :
368 : while(1)
369 : {
370 0 : iobuf_free_content(&rbuf);
371 0 : man_off_t_free(pos);
372 0 : if(!(*pos=manio_tell(manio)))
373 : {
374 0 : logp("Could not manio_tell top pos in %s(): %s\n",
375 0 : __func__, strerror(errno));
376 0 : goto error;
377 : }
378 :
379 0 : switch(fzp_read_ensure(manio->fzp, what, sizeof(what), __func__))
380 : {
381 : case 0: break;
382 : case 1: return 0;
383 : default:
384 0 : logp("Error read in %s(), but continuing\n",
385 : __func__);
386 : // Treat error in unchanged manio as
387 : // OK - could have been a short write.
388 0 : iobuf_free_content(&rbuf);
389 0 : return 0;
390 : }
391 :
392 0 : switch(iobuf_fill_from_fzp(&rbuf, manio->fzp))
393 : {
394 : case 0: break;
395 : case 1:
396 0 : iobuf_free_content(&rbuf);
397 0 : return 0;
398 : default:
399 0 : logp("Error in %s(), but continuing\n",
400 : __func__);
401 : // Treat error in unchanged manio as
402 : // OK - could have been a short write.
403 0 : iobuf_free_content(&rbuf);
404 0 : return 0;
405 : }
406 :
407 0 : switch(iobuf_pathcmp(target, &rbuf))
408 : {
409 : case 0:
410 0 : add_to_cntr(cntr, rbuf.cmd, what[0]);
411 : // Exact match, we want to be past here.
412 0 : man_off_t_free(pos);
413 0 : if(!(*pos=manio_tell(manio)))
414 : {
415 0 : logp("Could not manio_tell pos in %s(): "
416 0 : "%s\n", __func__, strerror(errno));
417 0 : goto error;
418 : }
419 0 : iobuf_free_content(&rbuf);
420 0 : return 0;
421 : case -1:
422 : // Gone past the match, we want to return to
423 : // the previous tell. Do not add_to_cntr,
424 : // or we will have one too many.
425 0 : iobuf_free_content(&rbuf);
426 0 : return 0;
427 : default:
428 : // Not gone far enough yet, continue.
429 0 : add_to_cntr(cntr, rbuf.cmd, what[0]);
430 : break;
431 : }
432 : }
433 :
434 : error:
435 0 : iobuf_free_content(&rbuf);
436 0 : man_off_t_free(pos);
437 0 : return -1;
438 : }
439 :
440 0 : static int tell_and_truncate(struct manio **manio, int compression)
441 : {
442 0 : int ret=-1;
443 0 : man_off_t *pos=NULL;
444 0 : if(!(pos=manio_tell(*manio))) {
445 0 : logp("Could not get pos in %s\n", __func__);
446 0 : goto end;
447 : }
448 0 : if(manio_close_and_truncate(manio, pos, compression))
449 : goto end;
450 0 : ret=0;
451 : end:
452 0 : man_off_t_free(&pos);
453 0 : return ret;
454 : }
455 :
456 : // Return p1manio position.
457 0 : static int do_resume_work(
458 : man_off_t **pos_phase1,
459 : man_off_t **pos_current,
460 : struct sdirs *sdirs,
461 : struct dpth *dpth, struct conf **cconfs
462 : ) {
463 0 : int ret=-1;
464 0 : man_off_t *pos=NULL;
465 0 : struct iobuf *chb=NULL;
466 0 : struct manio *cmanio=NULL;
467 0 : struct manio *chmanio=NULL;
468 0 : struct manio *unmanio=NULL;
469 0 : struct manio *p1manio=NULL;
470 0 : struct manio *counters_d=NULL;
471 0 : struct manio *counters_n=NULL;
472 0 : struct cntr *cntr=get_cntr(cconfs);
473 0 : int compression=get_int(cconfs[OPT_COMPRESSION]);
474 :
475 0 : if(!(cmanio=manio_open(sdirs->cmanifest, MANIO_MODE_READ))
476 0 : || !(p1manio=manio_open_phase1(sdirs->phase1data, MANIO_MODE_READ))
477 0 : || !(chmanio=manio_open_phase2(sdirs->changed, MANIO_MODE_READ))
478 0 : || !(unmanio=manio_open_phase2(sdirs->unchanged, MANIO_MODE_READ))
479 0 : || !(counters_d=manio_open_phase2(sdirs->counters_d, MANIO_MODE_READ))
480 0 : || !(counters_n=manio_open_phase2(sdirs->counters_n, MANIO_MODE_READ)))
481 : goto end;
482 :
483 0 : if(!(chb=iobuf_alloc()))
484 : goto error;
485 :
486 0 : logp("Setting up resume positions...\n");
487 :
488 0 : if(get_last_good_entry(chmanio, chb, cntr, dpth, &pos)
489 0 : || manio_close_and_truncate(&chmanio, pos, compression))
490 : goto error;
491 :
492 0 : man_off_t_free(&pos);
493 :
494 0 : if(chb->buf)
495 : {
496 0 : logp(" last good entry: %s\n",
497 : iobuf_to_printable(chb));
498 : // Now need to go to the appropriate places in p1manio, cmanio
499 : // and unmanio.
500 :
501 0 : logp(" setting pos_phase1\n");
502 0 : if(forward_past_entry(p1manio, chb, pos_phase1))
503 : goto error;
504 :
505 : // This sets pos_current. This manifest may not exist.
506 0 : if(cmanio->fzp)
507 : {
508 0 : logp(" setting pos_current\n");
509 0 : if (forward_past_entry(cmanio,
510 : chb, pos_current))
511 : goto error;
512 : }
513 :
514 : // The unchanged manio needs to be positioned just before the
515 : // found entry, otherwise it ends up having a duplicated entry.
516 0 : if(forward_before_entry(unmanio,
517 : chb, cntr, dpth, &pos))
518 : goto error;
519 0 : if(manio_close_and_truncate(&unmanio, pos, compression))
520 : goto error;
521 0 : man_off_t_free(&pos);
522 :
523 0 : logp(" setting entry counter_d\n");
524 0 : if(forward_past_entry_counter(counters_d, chb, cntr, &pos))
525 : goto error;
526 0 : if(manio_close_and_truncate(&counters_d, pos, 0))
527 : goto error;
528 0 : man_off_t_free(&pos);
529 :
530 0 : logp(" setting entry counter_n\n");
531 0 : if(forward_past_entry_counter(counters_n, chb, cntr, &pos))
532 : goto error;
533 0 : if(manio_close_and_truncate(&counters_n, pos, 0))
534 : goto error;
535 0 : man_off_t_free(&pos);
536 : }
537 : else
538 : {
539 0 : logp(" nothing previously transferred\n");
540 0 : if(!(*pos_phase1=manio_tell(p1manio))) {
541 0 : logp("Could not get pos_phase1 in %s\n", __func__);
542 0 : goto error;
543 : }
544 0 : if(tell_and_truncate(&unmanio, compression)
545 0 : || tell_and_truncate(&counters_d, 0)
546 0 : || tell_and_truncate(&counters_n, 0))
547 : goto error;
548 : }
549 :
550 : // Now should have all manios truncated correctly, with pos_phase1 and
551 : // pos_current set correctly in order to resume.
552 : ret=0;
553 : goto end;
554 : error:
555 0 : man_off_t_free(pos_phase1);
556 0 : man_off_t_free(pos_current);
557 : end:
558 0 : iobuf_free(&chb);
559 0 : man_off_t_free(&pos);
560 0 : manio_close(&p1manio);
561 0 : manio_close(&cmanio);
562 0 : manio_close(&chmanio);
563 0 : manio_close(&unmanio);
564 0 : manio_close(&counters_d);
565 0 : manio_close(&counters_n);
566 0 : return ret;
567 : }
568 :
569 0 : int do_resume(
570 : man_off_t **pos_phase1,
571 : man_off_t **pos_current,
572 : struct sdirs *sdirs,
573 : struct dpth *dpth,
574 : struct conf **cconfs
575 : ) {
576 0 : int ret=-1;
577 0 : struct manio *chmanio=NULL;
578 0 : struct manio *unmanio=NULL;
579 0 : struct manio *p1manio=NULL;
580 0 : struct manio *counters_d=NULL;
581 0 : struct manio *counters_n=NULL;
582 :
583 0 : logp("Begin phase1 (read previous file system scan)\n");
584 0 : if(!(p1manio=manio_open_phase1(sdirs->phase1data, "rb"))
585 0 : || read_phase1(p1manio, cconfs))
586 : goto end;
587 0 : manio_close(&p1manio);
588 :
589 : // First, open them in append mode, so that they will be created if
590 : // they do not exist.
591 0 : if(!(chmanio=manio_open_phase2(sdirs->changed, "ab"))
592 0 : || !(unmanio=manio_open_phase2(sdirs->unchanged, "ab"))
593 0 : || !(counters_d=manio_open_phase2(sdirs->counters_d, "ab"))
594 0 : || !(counters_n=manio_open_phase2(sdirs->counters_n, "ab")))
595 : goto end;
596 0 : manio_close(&chmanio);
597 0 : manio_close(&unmanio);
598 0 : manio_close(&counters_d);
599 0 : manio_close(&counters_n);
600 :
601 0 : if(do_resume_work(pos_phase1, pos_current, sdirs, dpth, cconfs))
602 : goto end;
603 :
604 0 : if(dpth_incr(dpth)) goto end;
605 :
606 0 : logp("End phase1 (read previous file system scan)\n");
607 0 : ret=0;
608 : end:
609 0 : manio_close(&p1manio);
610 0 : manio_close(&chmanio);
611 0 : manio_close(&unmanio);
612 0 : manio_close(&counters_d);
613 0 : manio_close(&counters_n);
614 0 : return ret;
615 : }
|