Line data Source code
1 : #include "../../burp.h"
2 : #include "../../alloc.h"
3 : #include "../../bu.h"
4 : #include "../../cmd.h"
5 : #include "../../cstat.h"
6 : #include "../../fsops.h"
7 : #include "../../fzp.h"
8 : #include "../../lock.h"
9 : #include "../../log.h"
10 : #include "../../prepend.h"
11 : #include "../../protocol2/blk.h"
12 : #include "../../sbuf.h"
13 : #include "../../strlist.h"
14 : #include "../../server/bu_get.h"
15 : #include "../../server/manio.h"
16 : #include "../../server/sdirs.h"
17 : #include "champ_chooser/champ_chooser.h"
18 : #include "backup_phase4.h"
19 : #include "clist.h"
20 : #include "sparse_min.h"
21 :
22 : static int hookscmp(struct hooks *a, struct hooks *b)
23 : {
24 : size_t i;
25 43 : uint64_t *af=a->fingerprints;
26 43 : uint64_t *bf=b->fingerprints;
27 47 : for(i=0; i<a->len && i<b->len; i++)
28 : {
29 46 : if(af[i]>bf[i]) return 1;
30 37 : if(af[i]<bf[i]) return -1;
31 : }
32 1 : if(a->len>b->len) return 1;
33 1 : if(a->len<b->len) return -1;
34 : return 0;
35 : }
36 :
37 144 : static int hooks_alloc(struct hooks **hnew,
38 : char **path, uint64_t **fingerprints, size_t *len)
39 : {
40 144 : if(!*path || !*fingerprints) return 0;
41 :
42 70 : if(!(*hnew=(struct hooks *)malloc_w(sizeof(struct hooks), __func__)))
43 : return -1;
44 :
45 70 : (*hnew)->path=*path;
46 70 : (*hnew)->fingerprints=*fingerprints;
47 70 : (*hnew)->len=*len;
48 70 : *path=NULL;
49 70 : *fingerprints=NULL;
50 70 : *len=0;
51 70 : return 0;
52 : }
53 :
54 : // Return 0 for OK, -1 for error, 1 for finished reading the file.
55 : #ifndef UTEST
56 : static
57 : #endif
58 114 : int get_next_set_of_hooks(struct hooks **hnew, struct sbuf *sb,
59 : struct fzp *spzp, char **path, uint64_t **fingerprints, size_t *len)
60 : {
61 : struct blk blk;
62 : while(1)
63 : {
64 342 : switch(sbuf_fill_from_file(sb, spzp, NULL))
65 : {
66 : case -1: goto error;
67 : case 1:
68 : // Reached the end.
69 74 : if(hooks_alloc(hnew, path, fingerprints, len))
70 : goto error;
71 : return 1;
72 : }
73 268 : if(sb->path.cmd==CMD_MANIFEST)
74 : {
75 70 : if(hooks_alloc(hnew, path, fingerprints, len))
76 : break;
77 70 : *path=sb->path.buf;
78 70 : sb->path.buf=NULL;
79 70 : sbuf_free_content(sb);
80 70 : if(*hnew) return 0;
81 : }
82 198 : else if(sb->path.cmd==CMD_FINGERPRINT)
83 : {
84 198 : if(!(*fingerprints=(uint64_t *)realloc_w(*fingerprints,
85 198 : ((*len)+1)*sizeof(uint64_t), __func__)))
86 : goto error;
87 198 : if(blk_set_from_iobuf_fingerprint(&blk, &sb->path))
88 : goto error;
89 198 : (*fingerprints)[(*len)++]=blk.fingerprint;
90 198 : sbuf_free_content(sb);
91 : }
92 : else
93 : {
94 0 : iobuf_log_unexpected(&sb->path, __func__);
95 0 : break;
96 : }
97 : }
98 :
99 : error:
100 0 : sbuf_free_content(sb);
101 0 : return -1;
102 : }
103 :
104 : #ifndef UTEST
105 : static
106 : #endif
107 69 : int hooks_gzprintf(struct fzp *fzp, struct hooks *hooks)
108 : {
109 : size_t i;
110 69 : fzp_printf(fzp, "%c%04lX%s\n", CMD_MANIFEST,
111 : strlen(hooks->path), hooks->path);
112 264 : for(i=0; i<hooks->len; i++)
113 195 : if(to_fzp_fingerprint(fzp, hooks->fingerprints[i]))
114 : return -1;
115 : return 0;
116 : }
117 :
118 : #ifndef UTEST
119 : static
120 : #endif
121 143 : void hooks_free(struct hooks **hooks)
122 : {
123 143 : if(!*hooks) return;
124 70 : free_w(&(*hooks)->path);
125 70 : free_v((void **)&(*hooks)->fingerprints);
126 70 : free_v((void **)hooks);
127 : }
128 :
129 : /* Merge two files of sorted sparse indexes into each other. */
130 : #ifndef UTEST
131 : static
132 : #endif
133 15 : int merge_sparse_indexes(const char *dst, const char *srca, const char *srcb)
134 : {
135 : int fcmp;
136 15 : int ret=-1;
137 15 : struct sbuf *asb=NULL;
138 15 : struct sbuf *bsb=NULL;
139 15 : uint64_t *afingerprints=NULL;
140 15 : uint64_t *bfingerprints=NULL;
141 15 : size_t aflen=0;
142 15 : size_t bflen=0;
143 15 : struct fzp *azp=NULL;
144 15 : struct fzp *bzp=NULL;
145 15 : struct fzp *dzp=NULL;
146 15 : struct hooks *anew=NULL;
147 15 : struct hooks *bnew=NULL;
148 15 : char *apath=NULL;
149 15 : char *bpath=NULL;
150 :
151 15 : if(!(asb=sbuf_alloc(PROTO_2))
152 15 : || (srcb && !(bsb=sbuf_alloc(PROTO_2))))
153 : goto end;
154 15 : if(build_path_w(dst))
155 : goto end;
156 15 : if((srca && !(azp=fzp_gzopen(srca, "rb")))
157 15 : || (srcb && !(bzp=fzp_gzopen(srcb, "rb")))
158 15 : || !(dzp=fzp_gzopen(dst, "wb")))
159 : goto end;
160 :
161 75 : while(azp || bzp || anew || bnew)
162 : {
163 60 : if(azp
164 60 : && asb
165 48 : && !anew)
166 : {
167 45 : switch(get_next_set_of_hooks(&anew, asb, azp,
168 : &apath, &afingerprints, &aflen))
169 : {
170 : case -1: goto end;
171 15 : case 1: fzp_close(&azp); // Finished OK.
172 : }
173 : }
174 :
175 120 : if(bzp
176 60 : && bsb
177 19 : && !bnew)
178 : {
179 17 : switch(get_next_set_of_hooks(&bnew, bsb, bzp,
180 : &bpath, &bfingerprints, &bflen))
181 : {
182 : case -1: goto end;
183 15 : case 1: fzp_close(&bzp); // Finished OK.
184 : }
185 : }
186 :
187 60 : if(anew && !bnew)
188 : {
189 10 : if(hooks_gzprintf(dzp, anew)) goto end;
190 10 : hooks_free(&anew);
191 : }
192 50 : else if(!anew && bnew)
193 : {
194 7 : if(hooks_gzprintf(dzp, bnew)) goto end;
195 7 : hooks_free(&bnew);
196 : }
197 43 : else if(!anew && !bnew)
198 : {
199 0 : continue;
200 : }
201 86 : else if(!(fcmp=hookscmp(anew, bnew)))
202 : {
203 : // They were the same - write the new one.
204 1 : if(hooks_gzprintf(dzp, bnew)) goto end;
205 1 : hooks_free(&anew);
206 1 : hooks_free(&bnew);
207 : }
208 42 : else if(fcmp<0)
209 : {
210 33 : if(hooks_gzprintf(dzp, anew)) goto end;
211 33 : hooks_free(&anew);
212 : }
213 : else
214 : {
215 9 : if(hooks_gzprintf(dzp, bnew)) goto end;
216 9 : hooks_free(&bnew);
217 : }
218 : }
219 :
220 15 : if(fzp_close(&dzp))
221 : {
222 0 : logp("Error closing %s in %s\n", dst, __func__);
223 0 : goto end;
224 : }
225 :
226 : ret=0;
227 : end:
228 15 : fzp_close(&azp);
229 15 : fzp_close(&bzp);
230 15 : fzp_close(&dzp);
231 15 : sbuf_free(&asb);
232 15 : sbuf_free(&bsb);
233 15 : hooks_free(&anew);
234 15 : hooks_free(&bnew);
235 15 : free_v((void **)&afingerprints);
236 15 : free_v((void **)&bfingerprints);
237 15 : free_w(&apath);
238 15 : free_w(&bpath);
239 15 : return ret;
240 : }
241 :
242 : #ifndef UTEST
243 : static
244 : #endif
245 410 : int dindex_gzprintf(struct fzp *fzp, uint64_t *dindex)
246 : {
247 : struct blk blk;
248 : struct iobuf wbuf;
249 410 : blk.savepath=*dindex;
250 410 : blk_to_iobuf_savepath(&blk, &wbuf);
251 410 : return iobuf_send_msg_fzp(&wbuf, fzp);
252 : }
253 :
254 : // Return 0 for OK, -1 for error, 1 for finished reading the file.
255 438 : static int get_next_dindex(uint64_t **dnew, struct sbuf *sb, struct fzp *fzp)
256 : {
257 : static struct blk blk;
258 : static struct iobuf rbuf;
259 :
260 438 : memset(&rbuf, 0, sizeof(rbuf));
261 :
262 438 : switch(iobuf_fill_from_fzp(&rbuf, fzp))
263 : {
264 : case -1: goto error;
265 : case 1: return 1; // Reached the end.
266 : }
267 278 : if(rbuf.cmd==CMD_SAVE_PATH)
268 : {
269 278 : if(blk_set_from_iobuf_savepath(&blk, &rbuf))
270 : goto error;
271 278 : *dnew=(uint64_t *)malloc_w(sizeof(uint64_t), __func__);
272 278 : **dnew=blk.savepath;
273 278 : iobuf_free_content(&rbuf);
274 278 : return 0;
275 : }
276 : else
277 0 : iobuf_log_unexpected(&sb->path, __func__);
278 :
279 : error:
280 0 : iobuf_free_content(&rbuf);
281 0 : return -1;
282 : }
283 :
284 : /* Merge two files of sorted dindexes into each other. */
285 90 : int merge_dindexes(const char *dst, const char *srca, const char *srcb)
286 : {
287 90 : int ret=-1;
288 90 : struct sbuf *asb=NULL;
289 90 : struct sbuf *bsb=NULL;
290 90 : struct fzp *azp=NULL;
291 90 : struct fzp *bzp=NULL;
292 90 : struct fzp *dzp=NULL;
293 90 : uint64_t *anew=NULL;
294 90 : uint64_t *bnew=NULL;
295 :
296 90 : if(!(asb=sbuf_alloc(PROTO_2))
297 90 : || (srcb && !(bsb=sbuf_alloc(PROTO_2))))
298 : goto end;
299 90 : if(build_path_w(dst))
300 : goto end;
301 90 : if((srca && !(azp=fzp_gzopen(srca, "rb")))
302 90 : || (srcb && !(bzp=fzp_gzopen(srcb, "rb")))
303 90 : || !(dzp=fzp_gzopen(dst, "wb")))
304 : goto end;
305 :
306 392 : while(azp || bzp || anew || bnew)
307 : {
308 302 : if(azp
309 302 : && asb
310 252 : && !anew)
311 : {
312 244 : switch(get_next_dindex(&anew, asb, azp))
313 : {
314 : case -1: goto end;
315 90 : case 1: fzp_close(&azp); // Finished OK.
316 : }
317 : }
318 :
319 604 : if(bzp
320 302 : && bsb
321 201 : && !bnew)
322 : {
323 194 : switch(get_next_dindex(&bnew, bsb, bzp))
324 : {
325 : case -1: goto end;
326 70 : case 1: fzp_close(&bzp); // Finished OK.
327 : }
328 : }
329 :
330 302 : if(anew && !bnew)
331 : {
332 81 : if(dindex_gzprintf(dzp, anew)) goto end;
333 81 : free_v((void **)&anew);
334 : }
335 221 : else if(!anew && bnew)
336 : {
337 50 : if(dindex_gzprintf(dzp, bnew)) goto end;
338 50 : free_v((void **)&bnew);
339 : }
340 171 : else if(!anew && !bnew)
341 : {
342 90 : continue;
343 : }
344 81 : else if(*anew==*bnew)
345 : {
346 : // They were the same - write the new one.
347 66 : if(dindex_gzprintf(dzp, bnew)) goto end;
348 66 : free_v((void **)&anew);
349 66 : free_v((void **)&bnew);
350 : }
351 15 : else if(*anew<*bnew)
352 : {
353 7 : if(dindex_gzprintf(dzp, anew)) goto end;
354 7 : free_v((void **)&anew);
355 : }
356 : else
357 : {
358 8 : if(dindex_gzprintf(dzp, bnew)) goto end;
359 8 : free_v((void **)&bnew);
360 : }
361 : }
362 :
363 90 : if(fzp_close(&dzp))
364 : {
365 0 : logp("Error closing %s in %s\n", dst, __func__);
366 0 : goto end;
367 : }
368 :
369 : ret=0;
370 : end:
371 90 : fzp_close(&azp);
372 90 : fzp_close(&bzp);
373 90 : fzp_close(&dzp);
374 90 : sbuf_free(&asb);
375 90 : sbuf_free(&bsb);
376 90 : free_v((void **)&anew);
377 90 : free_v((void **)&bnew);
378 90 : return ret;
379 : }
380 :
381 : static char *get_global_sparse_tmp(const char *global)
382 : {
383 52 : return prepend_n(global, "tmp", strlen("tmp"), ".");
384 : }
385 :
386 9 : int merge_into_global_sparse(
387 : const char *sparse,
388 : const char *global_sparse,
389 : struct lock *lock
390 : ) {
391 9 : int ret=-1;
392 : struct stat statp;
393 9 : char *tmpfile=NULL;
394 9 : const char *globalsrc=NULL;
395 :
396 9 : if(lock->status!=GET_LOCK_GOT)
397 : {
398 0 : logp("Attempt to merge into sparse index without a lock!\n");
399 0 : goto end;
400 : }
401 :
402 9 : if(!(tmpfile=get_global_sparse_tmp(global_sparse)))
403 : goto end;
404 :
405 9 : if(!lstat(global_sparse, &statp)) globalsrc=global_sparse;
406 :
407 9 : if(merge_sparse_indexes(tmpfile, globalsrc, sparse))
408 : goto end;
409 :
410 : // FIX THIS: nasty race condition needs to be recoverable.
411 9 : if(do_rename(tmpfile, global_sparse))
412 : goto end;
413 :
414 9 : ret=0;
415 : end:
416 9 : free_w(&tmpfile);
417 9 : return ret;
418 : }
419 :
420 0 : static int lock_and_merge_into_global_sparse(
421 : const char *sparse,
422 : const char *global_sparse,
423 : struct conf **conf,
424 : struct sdirs *sdirs
425 : ) {
426 0 : int ret=-1;
427 0 : struct lock *lock=NULL;
428 0 : struct cstat *clist=NULL;
429 :
430 0 : if(!(lock=try_to_get_sparse_lock(global_sparse)))
431 : goto end;
432 :
433 0 : if(merge_into_global_sparse(sparse, global_sparse, lock))
434 : goto end;
435 :
436 0 : if(get_client_list(&clist, sdirs->clients, conf))
437 : goto end;
438 :
439 0 : if(sparse_minimise(conf, sdirs->global_sparse, lock, clist))
440 : goto end;
441 :
442 0 : ret=0;
443 : end:
444 0 : lock_release(lock);
445 0 : lock_free(&lock);
446 0 : clist_free(&clist);
447 0 : return ret;
448 : }
449 :
450 47 : int merge_files_in_dir(const char *final, const char *fmanifest,
451 : const char *srcdir, uint64_t fcount,
452 : int merge(const char *dst, const char *srca, const char *srcb))
453 : {
454 47 : int ret=-1;
455 47 : uint64_t i=0;
456 47 : uint64_t pass=0;
457 47 : char *m1dir=NULL;
458 47 : char *m2dir=NULL;
459 47 : char *srca=NULL;
460 47 : char *srcb=NULL;
461 47 : char *dst=NULL;
462 47 : char compa[32]="";
463 47 : char compb[32]="";
464 47 : char compd[32]="";
465 47 : char *fullsrcdir=NULL;
466 :
467 47 : if(!(m1dir=prepend_s(fmanifest, "m1"))
468 47 : || !(m2dir=prepend_s(fmanifest, "m2"))
469 47 : || !(fullsrcdir=prepend_s(fmanifest, srcdir)))
470 : goto end;
471 47 : if(recursive_delete(m1dir)
472 47 : || recursive_delete(m2dir))
473 : goto end;
474 : while(1)
475 : {
476 53 : const char *srcdir=NULL;
477 53 : const char *dstdir=NULL;
478 53 : if(!pass)
479 : {
480 47 : srcdir=fullsrcdir;
481 47 : dstdir=m1dir;
482 : }
483 6 : else if(pass%2)
484 : {
485 4 : srcdir=m1dir;
486 4 : dstdir=m2dir;
487 : }
488 : else
489 : {
490 2 : srcdir=m2dir;
491 2 : dstdir=m1dir;
492 : }
493 53 : pass++;
494 113 : for(i=0; i<fcount; i+=2)
495 : {
496 60 : free_w(&srca);
497 60 : free_w(&srcb);
498 60 : free_w(&dst);
499 60 : snprintf(compa, sizeof(compa), "%08" PRIX64, i);
500 60 : snprintf(compb, sizeof(compb), "%08" PRIX64, i+1);
501 60 : snprintf(compd, sizeof(compd), "%08" PRIX64, i/2);
502 60 : if(!(srca=prepend_s(srcdir, compa))
503 60 : || !(dst=prepend_s(dstdir, compd)))
504 : goto end;
505 60 : if(i+1<fcount
506 55 : && !(srcb=prepend_s(srcdir, compb)))
507 : goto end;
508 60 : if(merge(dst, srca, srcb))
509 : goto end;
510 : }
511 53 : fcount=i/2;
512 53 : if(fcount<2) break;
513 : }
514 :
515 : // FIX THIS: nasty race condition here needs to be automatically
516 : // recoverable.
517 47 : if(dst && do_rename(dst, final))
518 : goto end;
519 47 : if(recursive_delete(m1dir)
520 47 : || recursive_delete(m2dir))
521 : goto end;
522 :
523 47 : ret=0;
524 : end:
525 47 : free_w(&m1dir);
526 47 : free_w(&m2dir);
527 47 : free_w(&srca);
528 47 : free_w(&srcb);
529 47 : free_w(&dst);
530 47 : free_w(&fullsrcdir);
531 47 : return ret;
532 : }
533 :
534 20 : int merge_files_in_dir_no_fcount(const char *final, const char *fmanifest,
535 : int merge(const char *dst, const char *srca, const char *srcb))
536 : {
537 20 : int ret=-1;
538 20 : int n=0;
539 20 : int i=0;
540 20 : char *dst=NULL;
541 20 : char *dstdir=NULL;
542 20 : char compd[32]="";
543 20 : char *fullpath=NULL;
544 20 : uint64_t fcount=0;
545 20 : struct dirent **dir=NULL;
546 20 : struct strlist *s=NULL;
547 20 : struct strlist *slist=NULL;
548 :
549 20 : if(!(dstdir=prepend_s(fmanifest, "n1")))
550 : goto end;
551 20 : if(recursive_delete(dstdir))
552 : goto end;
553 :
554 : // Files are unsorted, and not named sequentially.
555 20 : if((n=scandir(fmanifest, &dir, filter_dot, NULL))<0)
556 : {
557 0 : logp("scandir failed for %s in %s: %s\n",
558 0 : fmanifest, __func__, strerror(errno));
559 0 : goto end;
560 : }
561 60 : for(i=0; i<n; i++)
562 : {
563 60 : free_w(&fullpath);
564 60 : if(!(fullpath=prepend_s(fmanifest, dir[i]->d_name)))
565 : goto end;
566 60 : switch(is_dir(fullpath, dir[i]))
567 : {
568 : case 0: break;
569 20 : case 1: continue;
570 0 : default: logp("is_dir(%s): %s\n",
571 0 : fullpath, strerror(errno));
572 0 : goto end;
573 : }
574 :
575 : // Have a good entry. Add it to the list.
576 40 : if(strlist_add(&slist, fullpath, 0))
577 : goto end;
578 40 : fcount++;
579 : }
580 :
581 : // Merge them all into a directory, name the files sequentially.
582 20 : i=0;
583 60 : for(s=slist; s; s=s->next)
584 : {
585 40 : free_w(&dst);
586 40 : snprintf(compd, sizeof(compd), "%08" PRIX64, (uint64_t)i++);
587 40 : if(!(dst=prepend_s(dstdir, compd)))
588 : goto end;
589 40 : if(merge(dst, s->path, s->next?s->next->path:NULL))
590 : goto end;
591 : }
592 :
593 : // Now do a normal merge.
594 20 : if(merge_files_in_dir(final, fmanifest, "n1", fcount, merge))
595 : goto end;
596 :
597 20 : ret=0;
598 : end:
599 20 : recursive_delete(dstdir);
600 20 : strlists_free(&slist);
601 20 : free_w(&dstdir);
602 20 : free_w(&dst);
603 20 : free_w(&fullpath);
604 20 : if(dir)
605 : {
606 60 : for(i=0; i<n; i++)
607 60 : free(dir[i]);
608 20 : free(dir);
609 : }
610 20 : return ret;
611 : }
612 :
613 0 : int backup_phase4_server_protocol2(struct sdirs *sdirs, struct conf **confs)
614 : {
615 0 : int ret=-1;
616 0 : char *dfiles=NULL;
617 0 : char *sparse=NULL;
618 0 : struct manio *newmanio=NULL;
619 0 : char *logpath=NULL;
620 0 : char *fmanifest=NULL; // FIX THIS: should be part of sdirs.
621 :
622 0 : if(!(logpath=prepend_s(sdirs->finishing, "log")))
623 : goto end;
624 0 : if(log_fzp_set(logpath, confs))
625 : goto end;
626 :
627 0 : logp("Begin phase4 (sparse generation)\n");
628 :
629 0 : if(!(fmanifest=prepend_s(sdirs->finishing, "manifest"))
630 0 : || !(newmanio=manio_open(fmanifest, "rb", PROTO_2))
631 0 : || manio_read_fcount(newmanio)
632 0 : || !(dfiles=prepend_s(fmanifest, "dfiles"))
633 0 : || !(sparse=prepend_s(fmanifest, "sparse")))
634 : goto end;
635 :
636 0 : if(merge_files_in_dir(dfiles, fmanifest, "dindex",
637 0 : newmanio->offset->fcount,
638 : merge_dindexes))
639 : goto end;
640 0 : if(merge_files_in_dir(sparse, fmanifest, "hooks",
641 0 : newmanio->offset->fcount,
642 : merge_sparse_indexes))
643 : goto end;
644 :
645 0 : if(lock_and_merge_into_global_sparse(sparse,
646 0 : sdirs->global_sparse, confs, sdirs))
647 : goto end;
648 :
649 0 : logp("End phase4 (sparse generation)\n");
650 :
651 0 : ret=0;
652 : end:
653 0 : manio_close(&newmanio);
654 0 : free_w(&sparse);
655 0 : free_w(&logpath);
656 0 : free_w(&fmanifest);
657 0 : return ret;
658 : }
659 :
660 0 : static void wait_for_champ_dindex_lock(struct sdirs *sdirs)
661 : {
662 0 : while(lock_test(sdirs->champ_dindex_lock))
663 : {
664 0 : logp("Waiting for %s\n", sdirs->champ_dindex_lock);
665 0 : sleep(3);
666 : }
667 0 : }
668 :
669 : // Never call this outside of backup phases 2 to 4, because it cannot run
670 : // at the same time as the champ chooser starts up - that is when the champ
671 : // chooser attempts to delete data files. If the champ chooser attempts to
672 : // delete data files whilst the dindex is being regenerated, data could be
673 : // lost.
674 : // Backup phase 2 may start a champ chooser, and the champ chooser will not
675 : // attempt deletion if any client in the dedup_group has working/finishing
676 : // symlinks or a dfiles.regenerating file.
677 0 : int regenerate_client_dindex(struct sdirs *sdirs)
678 : {
679 0 : int ret=-1;
680 : struct bu *bu;
681 0 : struct bu *bu_list=NULL;
682 0 : char *newpath=NULL;
683 0 : char *oldpath=NULL;
684 0 : char tmp[16]="";
685 0 : int path_built=0;
686 0 : uint64_t last_index=0;
687 0 : char *dfiles_new=NULL;
688 0 : char *dfiles_regenerating=NULL;
689 0 : struct fzp *fzp=NULL;
690 :
691 0 : if(bu_get_list_with_working(sdirs, &bu_list))
692 : goto end;
693 :
694 0 : for(bu=bu_list; bu; bu=bu->next)
695 : {
696 0 : snprintf(tmp, sizeof(tmp), "%08" PRIX64, bu->index-1);
697 0 : if(!(newpath=prepend_s(sdirs->dindex, tmp))
698 0 : || !(oldpath=prepend_s(bu->path, "manifest/dfiles")))
699 : goto end;
700 0 : if(!path_built)
701 : {
702 0 : if(build_path_w(newpath))
703 : goto end;
704 0 : path_built++;
705 : }
706 0 : if(link(oldpath, newpath))
707 : {
708 0 : logp("%s could not hard link '%s' to '%s': %s\n",
709 0 : __func__, oldpath, newpath, strerror(errno));
710 0 : goto end;
711 : }
712 0 : free_w(&newpath);
713 0 : free_w(&oldpath);
714 0 : last_index=(uint64_t)bu->index;
715 : }
716 :
717 0 : if(!(dfiles_new=prepend(sdirs->dfiles, ".new"))
718 0 : || !(dfiles_regenerating=prepend(sdirs->dfiles, ".regenerating")))
719 : goto end;
720 :
721 : // dfiles.regenerating is checked in champ_chooser/dindex.c, the
722 : // champ chooser will not delete data files if it exists. We need
723 : // to make sure the champ chooser does not try to delete data files
724 : // whilst we have dfiles in an inconsistent state, or data will be
725 : // lost.
726 : // If we are interrupted after this point, the champ chooser deletion
727 : // code will not run again until this code here is re-run (or somebody
728 : // deletes dfiles_regenerating by hand, which they should not do).
729 0 : if(!(fzp=fzp_open(dfiles_regenerating, "wb"))
730 0 : || fzp_close(&fzp))
731 : goto end;
732 :
733 0 : if(recursive_delete(dfiles_new))
734 : goto end;
735 0 : if(merge_files_in_dir(dfiles_new, sdirs->client,
736 : "dindex", last_index, merge_dindexes))
737 : goto end;
738 :
739 : // If the champ chooser is deleting files, we do not want to mess with
740 : // our dindex/dfiles. Wait until it is finished.
741 0 : wait_for_champ_dindex_lock(sdirs);
742 :
743 0 : if(recursive_delete(sdirs->dindex))
744 : goto end;
745 0 : if(do_rename(dfiles_new, sdirs->dfiles))
746 : goto end;
747 0 : if(recursive_delete(sdirs->dindex))
748 : goto end;
749 :
750 0 : if(unlink_w(dfiles_regenerating, __func__))
751 : goto end;
752 :
753 0 : ret=0;
754 : end:
755 0 : bu_list_free(&bu_list);
756 0 : free_w(&dfiles_new);
757 0 : free_w(&dfiles_regenerating);
758 0 : free_w(&newpath);
759 0 : free_w(&oldpath);
760 0 : return ret;
761 : }
762 :
763 43 : int remove_backup_from_global_sparse(const char *global_sparse,
764 : const char *candidate_str)
765 : {
766 43 : int ret=-1;
767 43 : struct lock *lock=NULL;
768 43 : struct sbuf *asb=NULL;
769 43 : uint64_t *afingerprints=NULL;
770 43 : size_t aflen=0;
771 43 : size_t clen=0;
772 43 : struct fzp *azp=NULL;
773 43 : struct fzp *dzp=NULL;
774 43 : struct hooks *anew=NULL;
775 43 : char *apath=NULL;
776 43 : char *tmpfile=NULL;
777 :
778 43 : logp("Removing %s from %s\n", candidate_str, global_sparse);
779 43 : if(!(lock=try_to_get_sparse_lock(global_sparse)))
780 : goto end;
781 :
782 43 : if(!(tmpfile=get_global_sparse_tmp(global_sparse))
783 43 : || !(azp=fzp_gzopen(global_sparse, "rb"))
784 43 : || !(dzp=fzp_gzopen(tmpfile, "wb"))
785 43 : || !(asb=sbuf_alloc(PROTO_2)))
786 : goto end;
787 :
788 43 : clen=strlen(candidate_str);
789 :
790 129 : while(azp)
791 : {
792 43 : switch(get_next_set_of_hooks(&anew, asb, azp,
793 : &apath, &afingerprints, &aflen))
794 : {
795 : case -1: goto end;
796 43 : case 1: fzp_close(&azp); // Finished OK.
797 : }
798 :
799 43 : if(!anew) continue;
800 :
801 0 : if(!strncmp(anew->path, candidate_str, clen)
802 0 : && *(anew->path+clen)=='/')
803 0 : continue;
804 :
805 0 : if(hooks_gzprintf(dzp, anew)) goto end;
806 0 : hooks_free(&anew);
807 : }
808 :
809 43 : if(fzp_close(&dzp))
810 : {
811 0 : logp("Error closing %s in %s\n", tmpfile, __func__);
812 0 : goto end;
813 : }
814 :
815 : // FIX THIS: nasty race condition needs to be recoverable.
816 43 : if(do_rename(tmpfile, global_sparse))
817 : goto end;
818 :
819 43 : ret=0;
820 : end:
821 43 : fzp_close(&azp);
822 43 : fzp_close(&dzp);
823 43 : lock_release(lock);
824 43 : lock_free(&lock);
825 43 : sbuf_free(&asb);
826 43 : hooks_free(&anew);
827 43 : free_v((void **)&afingerprints);
828 43 : free_w(&apath);
829 43 : free_w(&tmpfile);
830 43 : return ret;
831 : }
|