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

Generated by: LCOV version 1.13