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