Line data Source code
1 : #include "../../burp.h"
2 : #include "../../alloc.h"
3 : #include "../../bu.h"
4 : #include "../../cmd.h"
5 : #include "../../fsops.h"
6 : #include "../../fzp.h"
7 : #include "../../lock.h"
8 : #include "../../log.h"
9 : #include "../../prepend.h"
10 : #include "../../protocol2/blk.h"
11 : #include "../../sbuf.h"
12 : #include "../../server/bu_get.h"
13 : #include "../../server/manio.h"
14 : #include "../../server/sdirs.h"
15 : #include "champ_chooser/champ_chooser.h"
16 :
17 : struct hooks
18 : {
19 : char *path;
20 : uint64_t *fingerprints;
21 : size_t len;
22 : };
23 :
24 10 : static int hookscmp(struct hooks *a, struct hooks *b)
25 : {
26 : size_t i;
27 10 : uint64_t *af=a->fingerprints;
28 10 : uint64_t *bf=b->fingerprints;
29 13 : for(i=0; i<a->len && i<b->len; i++)
30 : {
31 12 : if(af[i]>bf[i]) return 1;
32 8 : if(af[i]<bf[i]) return -1;
33 : }
34 1 : if(a->len>b->len) return 1;
35 1 : if(a->len<b->len) return -1;
36 : return 0;
37 : }
38 :
39 62 : static int hooks_alloc(struct hooks **hnew,
40 : char **path, uint64_t **fingerprints, size_t *len)
41 : {
42 62 : if(!*path || !*fingerprints) return 0;
43 :
44 16 : if(!(*hnew=(struct hooks *)malloc_w(sizeof(struct hooks), __func__)))
45 : return -1;
46 :
47 16 : (*hnew)->path=*path;
48 16 : (*hnew)->fingerprints=*fingerprints;
49 16 : (*hnew)->len=*len;
50 16 : *path=NULL;
51 16 : *fingerprints=NULL;
52 16 : *len=0;
53 16 : return 0;
54 : }
55 :
56 : // Return 0 for OK, -1 for error, 1 for finished reading the file.
57 50 : static int get_next_set_of_hooks(struct hooks **hnew, struct sbuf *sb,
58 : struct fzp *spzp, char **path, uint64_t **fingerprints, size_t *len)
59 : {
60 : struct blk blk;
61 : while(1)
62 : {
63 98 : switch(sbuf_fill_from_file(sb, spzp, NULL, NULL))
64 : {
65 : case -1: goto error;
66 : case 1:
67 : // Reached the end.
68 46 : if(hooks_alloc(hnew, path, fingerprints, len))
69 : goto error;
70 : return 1;
71 : }
72 52 : if(sb->path.cmd==CMD_MANIFEST)
73 : {
74 16 : if(hooks_alloc(hnew, path, fingerprints, len))
75 : break;
76 16 : *path=sb->path.buf;
77 16 : sb->path.buf=NULL;
78 16 : sbuf_free_content(sb);
79 16 : if(*hnew) return 0;
80 : }
81 36 : else if(sb->path.cmd==CMD_FINGERPRINT)
82 : {
83 36 : if(!(*fingerprints=(uint64_t *)realloc_w(*fingerprints,
84 36 : ((*len)+1)*sizeof(uint64_t), __func__)))
85 : goto error;
86 36 : if(blk_set_from_iobuf_fingerprint(&blk, &sb->path))
87 : goto error;
88 36 : (*fingerprints)[(*len)++]=blk.fingerprint;
89 36 : sbuf_free_content(sb);
90 : }
91 : else
92 : {
93 0 : iobuf_log_unexpected(&sb->path, __func__);
94 0 : break;
95 : }
96 : }
97 :
98 : error:
99 0 : sbuf_free_content(sb);
100 0 : return -1;
101 : }
102 :
103 15 : static int gzprintf_hooks(struct fzp *fzp, struct hooks *hooks)
104 : {
105 : size_t i;
106 : fzp_printf(fzp, "%c%04lX%s\n", CMD_MANIFEST,
107 15 : strlen(hooks->path), hooks->path);
108 48 : for(i=0; i<hooks->len; i++)
109 33 : if(to_fzp_fingerprint(fzp, hooks->fingerprints[i]))
110 : return -1;
111 : return 0;
112 : }
113 :
114 62 : static void hooks_free(struct hooks **hooks)
115 : {
116 124 : if(!*hooks) return;
117 16 : free_w(&(*hooks)->path);
118 16 : free_v((void **)&(*hooks)->fingerprints);
119 16 : free_v((void **)hooks);
120 : }
121 :
122 : /* Merge two files of sorted sparse indexes into each other. */
123 : #ifndef UTEST
124 : static
125 : #endif
126 6 : int merge_sparse_indexes(const char *dst, const char *srca, const char *srcb)
127 : {
128 : int fcmp;
129 6 : int ret=-1;
130 6 : struct sbuf *asb=NULL;
131 6 : struct sbuf *bsb=NULL;
132 6 : uint64_t *afingerprints=NULL;
133 6 : uint64_t *bfingerprints=NULL;
134 6 : size_t aflen=0;
135 6 : size_t bflen=0;
136 6 : struct fzp *azp=NULL;
137 6 : struct fzp *bzp=NULL;
138 6 : struct fzp *dzp=NULL;
139 6 : struct hooks *anew=NULL;
140 6 : struct hooks *bnew=NULL;
141 6 : char *apath=NULL;
142 6 : char *bpath=NULL;
143 :
144 12 : if(!(asb=sbuf_alloc(PROTO_2))
145 6 : || (srcb && !(bsb=sbuf_alloc(PROTO_2))))
146 : goto end;
147 6 : if(build_path_w(dst))
148 : goto end;
149 12 : if((srca && !(azp=fzp_gzopen(srca, "rb")))
150 6 : || (srcb && !(bzp=fzp_gzopen(srcb, "rb")))
151 12 : || !(dzp=fzp_gzopen(dst, "wb")))
152 : goto end;
153 :
154 21 : while(azp || bzp || anew || bnew)
155 : {
156 15 : if(azp
157 15 : && asb
158 29 : && !anew)
159 : {
160 8 : switch(get_next_set_of_hooks(&anew, asb, azp,
161 : &apath, &afingerprints, &aflen))
162 : {
163 : case -1: goto end;
164 6 : case 1: fzp_close(&azp); // Finished OK.
165 : }
166 : }
167 :
168 15 : if(bzp
169 15 : && bsb
170 30 : && !bnew)
171 : {
172 8 : switch(get_next_set_of_hooks(&bnew, bsb, bzp,
173 : &bpath, &bfingerprints, &bflen))
174 : {
175 : case -1: goto end;
176 6 : case 1: fzp_close(&bzp); // Finished OK.
177 : }
178 : }
179 :
180 15 : if(anew && !bnew)
181 : {
182 2 : if(gzprintf_hooks(dzp, anew)) goto end;
183 2 : hooks_free(&anew);
184 : }
185 13 : else if(!anew && bnew)
186 : {
187 3 : if(gzprintf_hooks(dzp, bnew)) goto end;
188 3 : hooks_free(&bnew);
189 : }
190 10 : else if(!anew && !bnew)
191 : {
192 : continue;
193 : }
194 50 : else if(!(fcmp=hookscmp(anew, bnew)))
195 : {
196 : // They were the same - write the new one.
197 1 : if(gzprintf_hooks(dzp, bnew)) goto end;
198 1 : hooks_free(&anew);
199 1 : hooks_free(&bnew);
200 : }
201 9 : else if(fcmp<0)
202 : {
203 5 : if(gzprintf_hooks(dzp, anew)) goto end;
204 5 : hooks_free(&anew);
205 : }
206 : else
207 : {
208 4 : if(gzprintf_hooks(dzp, bnew)) goto end;
209 4 : hooks_free(&bnew);
210 : }
211 : }
212 :
213 6 : if(fzp_close(&dzp))
214 : {
215 0 : logp("Error closing %s in %s\n", tmpfile, __func__);
216 0 : goto end;
217 : }
218 :
219 : ret=0;
220 : end:
221 6 : fzp_close(&azp);
222 6 : fzp_close(&bzp);
223 6 : fzp_close(&dzp);
224 6 : sbuf_free(&asb);
225 6 : sbuf_free(&bsb);
226 6 : hooks_free(&anew);
227 6 : hooks_free(&bnew);
228 6 : free_v((void **)&afingerprints);
229 6 : free_v((void **)&bfingerprints);
230 6 : free_w(&apath);
231 6 : free_w(&bpath);
232 6 : return ret;
233 : }
234 :
235 : #ifndef UTEST
236 : static
237 : #endif
238 72 : int gzprintf_dindex(struct fzp *fzp, uint64_t *dindex)
239 : {
240 : struct blk blk;
241 : struct iobuf wbuf;
242 72 : blk.savepath=*dindex;
243 72 : blk_to_iobuf_savepath(&blk, &wbuf);
244 72 : return iobuf_send_msg_fzp(&wbuf, fzp);
245 : }
246 :
247 : // Return 0 for OK, -1 for error, 1 for finished reading the file.
248 38 : static int get_next_dindex(uint64_t **dnew, struct sbuf *sb, struct fzp *fzp)
249 : {
250 : static struct blk blk;
251 : static struct iobuf rbuf;
252 :
253 : memset(&rbuf, 0, sizeof(rbuf));
254 :
255 38 : switch(iobuf_fill_from_fzp(&rbuf, fzp))
256 : {
257 : case -1: goto error;
258 : case 1: return 1; // Reached the end.
259 : }
260 26 : if(rbuf.cmd==CMD_SAVE_PATH)
261 : {
262 26 : if(blk_set_from_iobuf_savepath(&blk, &rbuf))
263 : goto error;
264 26 : *dnew=(uint64_t *)malloc_w(sizeof(uint64_t), __func__);
265 26 : **dnew=blk.savepath;
266 26 : iobuf_free_content(&rbuf);
267 26 : return 0;
268 : }
269 : else
270 0 : iobuf_log_unexpected(&sb->path, __func__);
271 :
272 : error:
273 0 : iobuf_free_content(&rbuf);
274 0 : return -1;
275 : }
276 :
277 : /* Merge two files of sorted dindexes into each other. */
278 6 : int merge_dindexes(const char *dst, const char *srca, const char *srcb)
279 : {
280 6 : int ret=-1;
281 6 : struct sbuf *asb=NULL;
282 6 : struct sbuf *bsb=NULL;
283 6 : struct fzp *azp=NULL;
284 6 : struct fzp *bzp=NULL;
285 6 : struct fzp *dzp=NULL;
286 6 : uint64_t *anew=NULL;
287 6 : uint64_t *bnew=NULL;
288 :
289 12 : if(!(asb=sbuf_alloc(PROTO_2))
290 6 : || (srcb && !(bsb=sbuf_alloc(PROTO_2))))
291 : goto end;
292 6 : if(build_path_w(dst))
293 : goto end;
294 12 : if((srca && !(azp=fzp_gzopen(srca, "rb")))
295 6 : || (srcb && !(bzp=fzp_gzopen(srcb, "rb")))
296 12 : || !(dzp=fzp_gzopen(dst, "wb")))
297 : goto end;
298 :
299 36 : while(azp || bzp || anew || bnew)
300 : {
301 30 : if(azp
302 30 : && asb
303 27 : && !anew)
304 : {
305 19 : switch(get_next_dindex(&anew, asb, azp))
306 : {
307 : case -1: goto end;
308 6 : case 1: fzp_close(&azp); // Finished OK.
309 : }
310 : }
311 :
312 30 : if(bzp
313 30 : && bsb
314 26 : && !bnew)
315 : {
316 19 : switch(get_next_dindex(&bnew, bsb, bzp))
317 : {
318 : case -1: goto end;
319 6 : case 1: fzp_close(&bzp); // Finished OK.
320 : }
321 : }
322 :
323 30 : if(anew && !bnew)
324 : {
325 4 : if(gzprintf_dindex(dzp, anew)) goto end;
326 4 : free_v((void **)&anew);
327 : }
328 26 : else if(!anew && bnew)
329 : {
330 3 : if(gzprintf_dindex(dzp, bnew)) goto end;
331 3 : free_v((void **)&bnew);
332 : }
333 23 : else if(!anew && !bnew)
334 : {
335 : continue;
336 : }
337 17 : else if(*anew==*bnew)
338 : {
339 : // They were the same - write the new one.
340 2 : if(gzprintf_dindex(dzp, bnew)) goto end;
341 2 : free_v((void **)&anew);
342 2 : free_v((void **)&bnew);
343 : }
344 15 : else if(*anew<*bnew)
345 : {
346 7 : if(gzprintf_dindex(dzp, anew)) goto end;
347 7 : free_v((void **)&anew);
348 : }
349 : else
350 : {
351 8 : if(gzprintf_dindex(dzp, bnew)) goto end;
352 8 : free_v((void **)&bnew);
353 : }
354 : }
355 :
356 6 : if(fzp_close(&dzp))
357 : {
358 0 : logp("Error closing %s in %s\n", tmpfile, __func__);
359 0 : goto end;
360 : }
361 :
362 : ret=0;
363 : end:
364 6 : fzp_close(&azp);
365 6 : fzp_close(&bzp);
366 6 : fzp_close(&dzp);
367 6 : sbuf_free(&asb);
368 6 : sbuf_free(&bsb);
369 6 : free_v((void **)&anew);
370 6 : free_v((void **)&bnew);
371 6 : return ret;
372 : }
373 :
374 : static char *get_global_sparse_tmp(const char *global)
375 : {
376 34 : return prepend_n(global, "tmp", strlen("tmp"), ".");
377 : }
378 :
379 0 : static int merge_into_global_sparse(const char *sparse, const char *global)
380 : {
381 0 : int ret=-1;
382 0 : char *tmpfile=NULL;
383 : struct stat statp;
384 0 : struct lock *lock=NULL;
385 0 : const char *globalsrc=NULL;
386 :
387 0 : if(!(tmpfile=get_global_sparse_tmp(global)))
388 : goto end;
389 :
390 0 : if(!(lock=try_to_get_sparse_lock(global)))
391 : goto end;
392 :
393 0 : if(!lstat(global, &statp)) globalsrc=global;
394 :
395 0 : if(merge_sparse_indexes(tmpfile, globalsrc, sparse))
396 : goto end;
397 :
398 : // FIX THIS: nasty race condition needs to be recoverable.
399 0 : if(do_rename(tmpfile, global)) goto end;
400 :
401 0 : ret=0;
402 : end:
403 0 : lock_release(lock);
404 0 : lock_free(&lock);
405 0 : free_w(&tmpfile);
406 0 : return ret;
407 : }
408 :
409 7 : int merge_files_in_dir(const char *final, const char *fmanifest,
410 : const char *srcdir, uint64_t fcount,
411 : int merge(const char *dst, const char *srca, const char *srcb))
412 : {
413 7 : int ret=-1;
414 7 : uint64_t i=0;
415 7 : uint64_t pass=0;
416 7 : char *m1dir=NULL;
417 7 : char *m2dir=NULL;
418 7 : char *srca=NULL;
419 7 : char *srcb=NULL;
420 7 : char *dst=NULL;
421 7 : char compa[32]="";
422 7 : char compb[32]="";
423 7 : char compd[32]="";
424 7 : char *fullsrcdir=NULL;
425 :
426 14 : if(!(m1dir=prepend_s(fmanifest, "m1"))
427 7 : || !(m2dir=prepend_s(fmanifest, "m2"))
428 14 : || !(fullsrcdir=prepend_s(fmanifest, srcdir)))
429 : goto end;
430 14 : if(recursive_delete(m1dir)
431 7 : || recursive_delete(m2dir))
432 : goto end;
433 : while(1)
434 : {
435 13 : const char *srcdir=NULL;
436 13 : const char *dstdir=NULL;
437 13 : if(!pass)
438 : {
439 7 : srcdir=fullsrcdir;
440 7 : dstdir=m1dir;
441 : }
442 6 : else if(pass%2)
443 : {
444 4 : srcdir=m1dir;
445 4 : dstdir=m2dir;
446 : }
447 : else
448 : {
449 2 : srcdir=m2dir;
450 2 : dstdir=m1dir;
451 : }
452 13 : pass++;
453 33 : for(i=0; i<fcount; i+=2)
454 : {
455 20 : free_w(&srca);
456 20 : free_w(&srcb);
457 20 : free_w(&dst);
458 : snprintf(compa, sizeof(compa), "%08"PRIX64, i);
459 20 : snprintf(compb, sizeof(compb), "%08"PRIX64, i+1);
460 20 : snprintf(compd, sizeof(compd), "%08"PRIX64, i/2);
461 40 : if(!(srca=prepend_s(srcdir, compa))
462 20 : || !(dst=prepend_s(dstdir, compd)))
463 : goto end;
464 20 : if(i+1<fcount
465 20 : && !(srcb=prepend_s(srcdir, compb)))
466 : goto end;
467 20 : if(merge(dst, srca, srcb))
468 : goto end;
469 : }
470 13 : fcount=i/2;
471 13 : if(fcount<2) break;
472 : }
473 :
474 : // FIX THIS: nasty race condition here needs to be automatically
475 : // recoverable.
476 7 : if(dst && do_rename(dst, final))
477 : goto end;
478 14 : if(recursive_delete(m1dir)
479 7 : || recursive_delete(m2dir))
480 : goto end;
481 :
482 7 : ret=0;
483 : end:
484 7 : free_w(&m1dir);
485 7 : free_w(&m2dir);
486 7 : free_w(&srca);
487 7 : free_w(&srcb);
488 7 : free_w(&dst);
489 7 : free_w(&fullsrcdir);
490 7 : return ret;
491 : }
492 :
493 0 : int backup_phase4_server_protocol2(struct sdirs *sdirs, struct conf **confs)
494 : {
495 0 : int ret=-1;
496 0 : char *dfiles=NULL;
497 0 : char *sparse=NULL;
498 0 : struct manio *newmanio=NULL;
499 0 : char *logpath=NULL;
500 0 : char *fmanifest=NULL; // FIX THIS: should be part of sdirs.
501 :
502 0 : if(!(logpath=prepend_s(sdirs->finishing, "log")))
503 : goto end;
504 0 : if(log_fzp_set(logpath, confs))
505 : goto end;
506 :
507 0 : logp("Begin phase4 (sparse generation)\n");
508 :
509 0 : if(!(fmanifest=prepend_s(sdirs->finishing, "manifest"))
510 0 : || !(newmanio=manio_open(fmanifest, "rb", PROTO_2))
511 0 : || manio_read_fcount(newmanio)
512 0 : || !(dfiles=prepend_s(fmanifest, "dfiles"))
513 0 : || !(sparse=prepend_s(fmanifest, "sparse")))
514 : goto end;
515 :
516 0 : if(merge_files_in_dir(dfiles, fmanifest, "dindex",
517 : newmanio->offset->fcount,
518 0 : merge_dindexes))
519 : goto end;
520 0 : if(merge_files_in_dir(sparse, fmanifest, "hooks",
521 : newmanio->offset->fcount,
522 0 : merge_sparse_indexes))
523 : goto end;
524 :
525 0 : if(merge_into_global_sparse(sparse, sdirs->global_sparse))
526 : goto end;
527 :
528 0 : logp("End phase4 (sparse generation)\n");
529 :
530 0 : ret=0;
531 : end:
532 0 : manio_close(&newmanio);
533 0 : free_w(&sparse);
534 0 : free_w(&logpath);
535 0 : free_w(&fmanifest);
536 0 : return ret;
537 : }
538 :
539 0 : int regenerate_client_dindex(struct sdirs *sdirs)
540 : {
541 0 : int ret=-1;
542 : struct bu *bu;
543 0 : struct bu *bu_list=NULL;
544 0 : char *newpath=NULL;
545 0 : char *oldpath=NULL;
546 0 : char tmp[16]="";
547 0 : int path_built=0;
548 0 : uint64_t last_index=0;
549 0 : char *dfiles_new=NULL;
550 :
551 0 : if(recursive_delete(sdirs->dindex)) goto end;
552 :
553 0 : if(bu_get_list(sdirs, &bu_list)) goto end;
554 :
555 0 : for(bu=bu_list; bu; bu=bu->next)
556 : {
557 0 : snprintf(tmp, sizeof(tmp), "%08lu", bu->index-1);
558 0 : if(!(newpath=prepend_s(sdirs->dindex, tmp))
559 0 : || !(oldpath=prepend_s(bu->path, "manifest/dfiles")))
560 : goto end;
561 0 : if(!path_built)
562 : {
563 0 : if(build_path_w(newpath))
564 : goto end;
565 0 : path_built++;
566 : }
567 0 : if(link(oldpath, newpath))
568 : {
569 : logp("%s could not hard link '%s' to '%s': %s\n",
570 0 : __func__, oldpath, newpath, strerror(errno));
571 0 : goto end;
572 : }
573 0 : free_w(&newpath);
574 0 : free_w(&oldpath);
575 0 : last_index=(uint64_t)bu->index;
576 : }
577 :
578 0 : if(!(dfiles_new=prepend(sdirs->dfiles, ".new")))
579 : goto end;
580 0 : if(merge_files_in_dir(dfiles_new, sdirs->client,
581 0 : "dindex", last_index, merge_dindexes))
582 : goto end;
583 :
584 0 : if(do_rename(dfiles_new, sdirs->dfiles))
585 : goto end;
586 :
587 0 : if(recursive_delete(sdirs->dindex)) goto end;
588 :
589 0 : ret=0;
590 : end:
591 0 : bu_list_free(&bu_list);
592 0 : free_w(&newpath);
593 0 : free_w(&oldpath);
594 0 : return ret;
595 : }
596 :
597 34 : int remove_from_global_sparse(const char *global_sparse,
598 : const char *candidate_str)
599 : {
600 34 : int ret=-1;
601 34 : struct lock *lock=NULL;
602 34 : struct sbuf *asb=NULL;
603 34 : uint64_t *afingerprints=NULL;
604 34 : size_t aflen=0;
605 34 : size_t clen=0;
606 34 : struct fzp *azp=NULL;
607 34 : struct fzp *dzp=NULL;
608 34 : struct hooks *anew=NULL;
609 34 : char *apath=NULL;
610 34 : char *tmpfile=NULL;
611 :
612 34 : logp("Removing %s from %s\n", candidate_str, global_sparse);
613 34 : if(!(lock=try_to_get_sparse_lock(global_sparse)))
614 : goto end;
615 :
616 34 : if(!(tmpfile=get_global_sparse_tmp(global_sparse))
617 34 : || !(azp=fzp_gzopen(global_sparse, "rb"))
618 34 : || !(dzp=fzp_gzopen(tmpfile, "wb"))
619 68 : || !(asb=sbuf_alloc(PROTO_2)))
620 : goto end;
621 :
622 34 : clen=strlen(candidate_str);
623 :
624 102 : while(azp)
625 : {
626 34 : switch(get_next_set_of_hooks(&anew, asb, azp,
627 34 : &apath, &afingerprints, &aflen))
628 : {
629 : case -1: goto end;
630 34 : case 1: fzp_close(&azp); // Finished OK.
631 : }
632 :
633 34 : if(!anew) continue;
634 :
635 0 : if(!strncmp(anew->path, candidate_str, clen)
636 0 : && *(anew->path+clen)=='/')
637 : continue;
638 :
639 0 : if(gzprintf_hooks(dzp, anew)) goto end;
640 0 : hooks_free(&anew);
641 : }
642 :
643 34 : if(fzp_close(&dzp))
644 : {
645 0 : logp("Error closing %s in %s\n", tmpfile, __func__);
646 0 : goto end;
647 : }
648 :
649 : // FIX THIS: nasty race condition needs to be recoverable.
650 34 : if(do_rename(tmpfile, global_sparse)) goto end;
651 :
652 34 : ret=0;
653 : end:
654 34 : fzp_close(&azp);
655 34 : fzp_close(&dzp);
656 34 : lock_release(lock);
657 34 : lock_free(&lock);
658 34 : sbuf_free(&asb);
659 34 : hooks_free(&anew);
660 34 : free_v((void **)&afingerprints);
661 34 : free_w(&apath);
662 34 : free_w(&tmpfile);
663 34 : return ret;
664 : }
|