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