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: 310 422 73.5 %
Date: 2017-05-30 Functions: 13 17 76.5 %

          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             : }

Generated by: LCOV version 1.10