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