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