LCOV - code coverage report
Current view: top level - src/server/protocol2 - backup_phase4.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 298 414 72.0 %
Date: 2016-11-07 Functions: 12 16 75.0 %

          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 : static void wait_for_champ_dindex_lock(struct sdirs *sdirs)
     621             : {
     622           0 :         while(lock_test(sdirs->champ_dindex_lock))
     623             :         {
     624           0 :                 logp("Waiting for %s\n", sdirs->champ_dindex_lock);
     625           0 :                 sleep(3);
     626             :         }
     627           0 : }
     628             : 
     629             : // Never call this outside of backup phases 2 to 4, because it cannot run
     630             : // at the same time as the champ chooser starts up - that is when the champ
     631             : // chooser attempts to delete data files. If the champ chooser attempts to
     632             : // delete data files whilst the dindex is being regenerated, data could be
     633             : // lost.
     634             : // Backup phase 2 may start a champ chooser, and the champ chooser will not
     635             : // attempt deletion if any client in the dedup_group has working/finishing
     636             : // symlinks or a dfiles.regenerating file.
     637           0 : int regenerate_client_dindex(struct sdirs *sdirs)
     638             : {
     639           0 :         int ret=-1;
     640             :         struct bu *bu;
     641           0 :         struct bu *bu_list=NULL;
     642           0 :         char *newpath=NULL;
     643           0 :         char *oldpath=NULL;
     644           0 :         char tmp[16]="";
     645           0 :         int path_built=0;
     646           0 :         uint64_t last_index=0;
     647           0 :         char *dfiles_new=NULL;
     648           0 :         char *dfiles_regenerating=NULL;
     649           0 :         struct fzp *fzp=NULL;
     650             : 
     651           0 :         if(bu_get_list_with_working(sdirs, &bu_list, NULL))
     652             :                 goto end;
     653             : 
     654           0 :         for(bu=bu_list; bu; bu=bu->next)
     655             :         {
     656           0 :                 snprintf(tmp, sizeof(tmp), "%08" PRIX64, bu->index-1);
     657           0 :                 if(!(newpath=prepend_s(sdirs->dindex, tmp))
     658           0 :                   || !(oldpath=prepend_s(bu->path, "manifest/dfiles")))
     659             :                         goto end;
     660           0 :                 if(!path_built)
     661             :                 {
     662           0 :                         if(build_path_w(newpath))
     663             :                                 goto end;
     664           0 :                         path_built++;
     665             :                 }
     666           0 :                 if(link(oldpath, newpath))
     667             :                 {
     668           0 :                         logp("%s could not hard link '%s' to '%s': %s\n",
     669           0 :                                 __func__, oldpath, newpath, strerror(errno));
     670           0 :                         goto end;
     671             :                 }
     672           0 :                 free_w(&newpath);
     673           0 :                 free_w(&oldpath);
     674           0 :                 last_index=(uint64_t)bu->index;
     675             :         }
     676             : 
     677           0 :         if(!(dfiles_new=prepend(sdirs->dfiles, ".new"))
     678           0 :           || !(dfiles_regenerating=prepend(sdirs->dfiles, ".regenerating")))
     679             :                 goto end;
     680             : 
     681             :         // dfiles.regenerating is checked in champ_chooser/dindex.c, the
     682             :         // champ chooser will not delete data files if it exists. We need
     683             :         // to make sure the champ chooser does not try to delete data files
     684             :         // whilst we have dfiles in an inconsistent state, or data will be
     685             :         // lost.
     686             :         // If we are interrupted after this point, the champ chooser deletion
     687             :         // code will not run again until this code here is re-run (or somebody
     688             :         // deletes dfiles_regenerating by hand, which they should not do).
     689           0 :         if(!(fzp=fzp_open(dfiles_regenerating, "wb"))
     690           0 :           || fzp_close(&fzp))
     691             :                 goto end;
     692             : 
     693           0 :         if(recursive_delete(dfiles_new))
     694             :                 goto end;
     695           0 :         if(merge_files_in_dir(dfiles_new, sdirs->client,
     696             :                 "dindex", last_index, merge_dindexes))
     697             :                         goto end;
     698             : 
     699             :         // If the champ chooser is deleting files, we do not want to mess with
     700             :         // our dindex/dfiles. Wait until it is finished.
     701           0 :         wait_for_champ_dindex_lock(sdirs);
     702             : 
     703           0 :         if(recursive_delete(sdirs->dindex))
     704             :                 goto end;
     705           0 :         if(do_rename(dfiles_new, sdirs->dfiles))
     706             :                 goto end;
     707           0 :         if(recursive_delete(sdirs->dindex))
     708             :                 goto end;
     709             : 
     710           0 :         if(unlink_w(dfiles_regenerating, __func__))
     711             :                 goto end;
     712             : 
     713           0 :         ret=0;
     714             : end:
     715           0 :         bu_list_free(&bu_list);
     716           0 :         free_w(&dfiles_new);
     717           0 :         free_w(&dfiles_regenerating);
     718           0 :         free_w(&newpath);
     719           0 :         free_w(&oldpath);
     720           0 :         return ret;
     721             : }
     722             : 
     723          43 : int remove_from_global_sparse(const char *global_sparse,
     724             :         const char *candidate_str)
     725             : {
     726          43 :         int ret=-1;
     727          43 :         struct lock *lock=NULL;
     728          43 :         struct sbuf *asb=NULL;
     729          43 :         uint64_t *afingerprints=NULL;
     730          43 :         size_t aflen=0;
     731          43 :         size_t clen=0;
     732          43 :         struct fzp *azp=NULL;
     733          43 :         struct fzp *dzp=NULL;
     734          43 :         struct hooks *anew=NULL;
     735          43 :         char *apath=NULL;
     736          43 :         char *tmpfile=NULL;
     737             : 
     738          43 :         logp("Removing %s from %s\n", candidate_str, global_sparse);
     739          43 :         if(!(lock=try_to_get_sparse_lock(global_sparse)))
     740             :                 goto end;
     741             : 
     742          43 :         if(!(tmpfile=get_global_sparse_tmp(global_sparse))
     743          43 :           || !(azp=fzp_gzopen(global_sparse, "rb"))
     744          43 :           || !(dzp=fzp_gzopen(tmpfile, "wb"))
     745          43 :           || !(asb=sbuf_alloc(PROTO_2)))
     746             :                 goto end;
     747             : 
     748          43 :         clen=strlen(candidate_str);
     749             : 
     750         129 :         while(azp)
     751             :         {
     752          43 :                 switch(get_next_set_of_hooks(&anew, asb, azp,
     753             :                         &apath, &afingerprints, &aflen))
     754             :                 {
     755             :                         case -1: goto end;
     756          43 :                         case 1: fzp_close(&azp); // Finished OK.
     757             :                 }
     758             : 
     759          43 :                 if(!anew) continue;
     760             : 
     761           0 :                 if(!strncmp(anew->path, candidate_str, clen)
     762           0 :                   && *(anew->path+clen)=='/')
     763           0 :                         continue;
     764             : 
     765           0 :                 if(gzprintf_hooks(dzp, anew)) goto end;
     766           0 :                 hooks_free(&anew);
     767             :         }
     768             : 
     769          43 :         if(fzp_close(&dzp))
     770             :         {
     771           0 :                 logp("Error closing %s in %s\n", tmpfile, __func__);
     772           0 :                 goto end;
     773             :         }
     774             : 
     775             :         // FIX THIS: nasty race condition needs to be recoverable.
     776          43 :         if(do_rename(tmpfile, global_sparse)) goto end;
     777             : 
     778          43 :         ret=0;
     779             : end:
     780          43 :         fzp_close(&azp);
     781          43 :         fzp_close(&dzp);
     782          43 :         lock_release(lock);
     783          43 :         lock_free(&lock);
     784          43 :         sbuf_free(&asb);
     785          43 :         hooks_free(&anew);
     786          43 :         free_v((void **)&afingerprints);
     787          43 :         free_w(&apath);
     788          43 :         free_w(&tmpfile);
     789          43 :         return ret;
     790             : }

Generated by: LCOV version 1.10