LCOV - code coverage report
Current view: top level - src/server/protocol2/champ_chooser - dindex.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 171 191 89.5 %
Date: 2021-06-01 21:59:08 Functions: 5 5 100.0 %

          Line data    Source code
       1             : #include "../../../burp.h"
       2             : #include "../../../alloc.h"
       3             : #include "../../../fsops.h"
       4             : #include "../../../hexmap.h"
       5             : #include "../../../lock.h"
       6             : #include "../../../log.h"
       7             : #include "../../../prepend.h"
       8             : #include "../../../protocol2/blk.h"
       9             : #include "../../../sbuf.h"
      10             : #include "../../../strlist.h"
      11             : #include "../../sdirs.h"
      12             : #include "../backup_phase4.h"
      13             : #include "dindex.h"
      14             : 
      15          24 : static int backup_in_progress(const char *fullpath)
      16             : {
      17          24 :         int ret=-1;
      18             :         struct stat statp;
      19          24 :         char *working=NULL;
      20          24 :         char *finishing=NULL;
      21          24 :         char *dfiles_regenerating=NULL;
      22             : 
      23          24 :         if(!(working=prepend_s(fullpath, "working"))
      24          24 :           || !(finishing=prepend_s(fullpath, "finishing"))
      25          24 :           || !(dfiles_regenerating=prepend_s(fullpath, "dfiles.regenerating")))
      26             :                 goto end;
      27             : 
      28          48 :         if(!lstat(working, &statp)
      29          44 :           || !lstat(finishing, &statp))
      30             :         {
      31           4 :                 logp("%s looks like it has a backup in progress.\n",
      32             :                         fullpath);
      33           4 :                 ret=1;
      34           4 :                 goto end;
      35             :         }
      36          40 :         if(!lstat(dfiles_regenerating, &statp))
      37             :         {
      38           0 :                 logp("%s looks like it was interrupted whilst "
      39             :                         "regenerating its dfiles.\n", fullpath);
      40           0 :                 ret=1;
      41           0 :                 goto end;
      42             :         }
      43             :         ret=0;
      44             : end:
      45          24 :         if(ret==1)
      46           4 :                 logp("Give up clean up attempt.\n");
      47          24 :         free_w(&working);
      48          24 :         free_w(&finishing);
      49          24 :         free_w(&dfiles_regenerating);
      50          24 :         return ret;
      51             : }
      52             : 
      53             : // Returns 0 on OK, -1 on error, 1 if there were backups already in progress.
      54          24 : static int get_dfiles_to_merge(struct sdirs *sdirs, struct strlist **s)
      55             : {
      56          24 :         int i=0;
      57          24 :         int n=0;
      58          24 :         int ret=-1;
      59             :         struct stat statp;
      60          24 :         char *fullpath=NULL;
      61          24 :         char *dfiles=NULL;
      62          24 :         struct dirent **dir=NULL;
      63             : 
      64          24 :         if((n=scandir(sdirs->clients, &dir, filter_dot, NULL))<0)
      65             :         {
      66           0 :                 logp("scandir failed for %s in %s: %s\n",
      67           0 :                         sdirs->clients, __func__, strerror(errno));
      68             :                 goto end;
      69             :         }
      70          40 :         for(i=0; i<n; i++)
      71             :         {
      72          44 :                 free_w(&fullpath);
      73          44 :                 if(!(fullpath=prepend_s(sdirs->clients, dir[i]->d_name)))
      74             :                         goto end;
      75          44 :                 switch(is_dir(fullpath, dir[i]))
      76             :                 {
      77           0 :                         case 0: continue;
      78             :                         case 1: break;
      79           0 :                         default: logp("is_dir(%s): %s\n",
      80           0 :                                         fullpath, strerror(errno));
      81             :                                 goto end;
      82             :                 }
      83             : 
      84          44 :                 if(strcmp(sdirs->client, fullpath))
      85             :                 {
      86          24 :                         switch(backup_in_progress(fullpath))
      87             :                         {
      88             :                                 case 0: break;
      89           4 :                                 case 1: ret=1;
      90             :                                 default: goto end;
      91             :                         }
      92             :                 }
      93             : 
      94          40 :                 free_w(&dfiles);
      95          40 :                 if(!(dfiles=prepend_s(fullpath, "dfiles"))
      96          80 :                   || lstat(dfiles, &statp))
      97           0 :                         continue;
      98             : 
      99             :                 // Have a good entry. Add it to the list.
     100          40 :                 if(strlist_add(s, dfiles, 0))
     101             :                         goto end;
     102             :         }
     103             : 
     104             :         ret=0;
     105             : end:
     106          24 :         free_w(&fullpath);
     107          24 :         free_w(&dfiles);
     108          24 :         if(dir)
     109             :         {
     110          48 :                 for(i=0; i<n; i++)
     111          48 :                         free(dir[i]);
     112          24 :                 free(dir);
     113             :         }
     114          24 :         return ret;
     115             : }
     116             : 
     117          27 : static int do_unlink(struct blk *oblk, const char *datadir)
     118             : {
     119          27 :         int ret=-1;
     120          27 :         char *fullpath=NULL;
     121          27 :         char *savepath=uint64_to_savepathstr(oblk->savepath);
     122          27 :         if(!(fullpath=prepend_s(datadir, savepath)))
     123             :                 goto end;
     124          27 :         errno=0;
     125          27 :         if(unlink(fullpath) && errno!=ENOENT)
     126             :         {
     127           0 :                 logp("Could not unlink %s: %s\n", fullpath, strerror(errno));
     128             :                 goto end;
     129             :         }
     130          27 :         logp("Deleted %s\n", savepath);
     131          27 :         ret=0;
     132             : end:
     133          27 :         free_w(&fullpath);
     134          27 :         return ret;
     135             : }
     136             : 
     137             : #ifndef UTEST
     138             : static
     139             : #endif
     140          26 : int compare_dindexes_and_unlink_datafiles(const char *dindex_old,
     141             :         const char *dindex_new, const char *datadir)
     142             : {
     143          26 :         int ret=-1;
     144          26 :         struct fzp *nzp=NULL;
     145          26 :         struct fzp *ozp=NULL;
     146             :         struct iobuf nbuf;
     147             :         struct iobuf obuf;
     148             :         struct blk nblk;
     149             :         struct blk oblk;
     150             : 
     151          26 :         iobuf_init(&nbuf);
     152          26 :         iobuf_init(&obuf);
     153          26 :         memset(&nblk, 0, sizeof(struct blk));
     154          26 :         memset(&oblk, 0, sizeof(struct blk));
     155             :         
     156          26 :         if(!(nzp=fzp_gzopen(dindex_new, "rb"))
     157          26 :           || !(ozp=fzp_gzopen(dindex_old, "rb")))
     158             :                 goto end;
     159             : 
     160         109 :         while(nzp || ozp)
     161             :         {
     162          88 :                 if(nzp
     163          69 :                   && !nbuf.buf)
     164             :                 {
     165          61 :                         switch(iobuf_fill_from_fzp(&nbuf, nzp))
     166             :                         {
     167          21 :                                 case 1: fzp_close(&nzp);
     168          21 :                                         break;
     169          40 :                                 case 0: if(nbuf.cmd!=CMD_SAVE_PATH)
     170             :                                         {
     171           0 :                                                 logp("unknown cmd in %s: %s\n",
     172             :                                                         __func__,
     173             :                                                         iobuf_to_printable(&nbuf));
     174           0 :                                                 goto end;
     175             :                                         }
     176          40 :                                         if(blk_set_from_iobuf_savepath(&nblk,
     177             :                                                 &nbuf)) goto end;
     178             :                                         break;
     179             :                                 default: goto end; // Error;
     180             :                         }
     181             :                 }
     182             : 
     183          88 :                 if(ozp
     184          88 :                   && !obuf.buf)
     185             :                 {
     186          87 :                         switch(iobuf_fill_from_fzp(&obuf, ozp))
     187             :                         {
     188          26 :                                 case 1: fzp_close(&ozp);
     189          26 :                                         break;
     190          61 :                                 case 0: if(obuf.cmd!=CMD_SAVE_PATH)
     191             :                                         {
     192           0 :                                                 logp("unknown cmd in %s: %c\n",
     193             :                                                         __func__, obuf.cmd);
     194           0 :                                                 goto end;
     195             :                                         }
     196          61 :                                         if(blk_set_from_iobuf_savepath(&oblk,
     197             :                                                 &obuf)) goto end;
     198             :                                         break;
     199             :                                 default: goto end; // Error;
     200             :                         }
     201             :                 }
     202             : 
     203          88 :                 if(nbuf.buf && !obuf.buf)
     204             :                 {
     205             :                         // No more from the old file. Time to stop.
     206             :                         break;
     207             :                 }
     208          83 :                 else if(!nbuf.buf && obuf.buf)
     209             :                 {
     210             :                         // No more in the new file. Delete old entry.
     211          19 :                         if(do_unlink(&oblk, datadir))
     212             :                                 goto end;
     213          19 :                         iobuf_free_content(&obuf);
     214             :                 }
     215          64 :                 else if(!nbuf.buf && !obuf.buf)
     216             :                 {
     217          21 :                         continue;
     218             :                 }
     219          43 :                 else if(nblk.savepath==oblk.savepath)
     220             :                 {
     221             :                         // Same, free both and continue;
     222          34 :                         iobuf_free_content(&nbuf);
     223          34 :                         iobuf_free_content(&obuf);
     224             :                 }
     225           9 :                 else if(nblk.savepath<oblk.savepath)
     226             :                 {
     227             :                         // Only in the new file.
     228           1 :                         iobuf_free_content(&nbuf);
     229             :                 }
     230             :                 else
     231             :                 {
     232             :                         // Only in the old file.
     233           8 :                         if(do_unlink(&oblk, datadir))
     234             :                                 goto end;
     235           8 :                         iobuf_free_content(&obuf);
     236             :                 }
     237             :         }
     238             : 
     239             : 
     240             :         ret=0;
     241             : end:
     242          26 :         iobuf_free_content(&nbuf);
     243          26 :         iobuf_free_content(&obuf);
     244          26 :         fzp_close(&nzp);
     245          26 :         fzp_close(&ozp);
     246          26 :         return ret;
     247             : }
     248             : 
     249          32 : int delete_unused_data_files(struct sdirs *sdirs, int resume)
     250             : {
     251          32 :         int ret=-1;
     252          32 :         uint64_t fcount=0;
     253             :         char hfile[32];
     254          32 :         char *hlinks=NULL;
     255          32 :         char *fullpath=NULL;
     256          32 :         char *cindex_tmp=NULL;
     257          32 :         char *cindex_new=NULL;
     258          32 :         char *dindex_tmp=NULL;
     259          32 :         char *dindex_new=NULL;
     260          32 :         char *dindex_old=NULL;
     261          32 :         struct strlist *s=NULL;
     262          32 :         struct strlist *slist=NULL;
     263             :         struct stat statp;
     264          32 :         struct lock *lock=NULL;
     265             : 
     266          32 :         if(!sdirs)
     267             :         {
     268           1 :                 logp("No sdirs passed to %s\n", __func__);
     269           1 :                 goto end;
     270             :         }
     271             : 
     272          31 :         if(resume)
     273             :         {
     274             :                 // Cannot do it on a resume, or it will delete files that are
     275             :                 // referenced in the backup we are resuming.
     276           7 :                 logp("Not attempting to clean up unused data files\n");
     277           7 :                 logp("because %s is resuming\n", sdirs->clients);
     278           7 :                 ret=0;
     279           7 :                 goto end;
     280             :         }
     281             : 
     282          24 :         if(!(lock=lock_alloc_and_init(sdirs->champ_dindex_lock)))
     283             :                 goto end;
     284          24 :         lock_get(lock);
     285          24 :         switch(lock->status)
     286             :         {
     287             :                 case GET_LOCK_GOT:
     288             :                         break;
     289             :                 default:
     290           0 :                         logp("Could not get %s\n", sdirs->champ_dindex_lock);
     291           0 :                         logp("This should not happen.\n");
     292           0 :                         goto end;
     293             :         }
     294             : 
     295          24 :         logp("Attempting to clean up unused data files %s\n", sdirs->clients);
     296             : 
     297             :         // Get all lists of files in all backups.
     298          24 :         switch(get_dfiles_to_merge(sdirs, &slist))
     299             :         {
     300             :                 case 0:
     301             :                         break; // OK.
     302             :                 case 1:
     303             :                         // Backups are in progress, cannot continue.
     304             :                         // But do not return an error.
     305           4 :                         ret=0;
     306             :                 default:
     307             :                         goto end; // Error.
     308             :         }
     309             : 
     310          20 :         if(!(dindex_tmp=prepend_s(sdirs->data, "dindex.tmp"))
     311          20 :           || !(dindex_old=prepend_s(sdirs->data, "dindex")))
     312             :                 goto end;
     313             : 
     314             :         // Get a list of the files that have been created since last time.
     315             :         // (this enables us to clean up data files that were created for
     316             :         // interrupted backups).
     317          20 :         if(!(cindex_tmp=prepend_s(sdirs->cfiles, "cindex.tmp"))
     318          20 :           || recursive_delete(cindex_tmp))
     319             :                 goto end;
     320          40 :         if(!lstat(sdirs->cfiles, &statp))
     321             :         {
     322          20 :                 if(mkdir(cindex_tmp, 0777)
     323          20 :                   || !(cindex_new=prepend_s(cindex_tmp, "cindex"))
     324          20 :                   || merge_files_in_dir_no_fcount(cindex_new,
     325          20 :                         sdirs->cfiles, merge_dindexes))
     326             :                                 goto end;
     327          40 :                 if(!lstat(cindex_new, &statp))
     328             :                 {
     329          40 :                         if(lstat(dindex_old, &statp))
     330             :                         {
     331             :                                 // The dindex file does not exist.
     332             :                                 // Just rename cindex_new.
     333          16 :                                 if(do_rename(cindex_new, dindex_old))
     334             :                                         goto end;
     335             :                         }
     336             :                         else
     337             :                         {
     338             :                                 // Merge it into the previous list of files
     339             :                                 // from all backups.
     340           4 :                                 if(merge_dindexes(dindex_tmp,
     341             :                                         dindex_old, cindex_new)
     342           4 :                                   || do_rename(dindex_tmp, dindex_old))
     343             :                                         goto end;
     344             :                         }
     345             :                 }
     346             :         }
     347             : 
     348             :         // Create a directory of hardlinks to each list of files.
     349          20 :         if(!(hlinks=prepend_s(dindex_tmp, "hlinks"))
     350          20 :           || recursive_delete(dindex_tmp)
     351          20 :           || mkdir(dindex_tmp, 0777)
     352          20 :           || mkdir(hlinks, 0777))
     353             :                 goto end;
     354          60 :         for(s=slist; s; s=s->next)
     355             :         {
     356          40 :                 snprintf(hfile, sizeof(hfile), "%08" PRIX64, fcount++);
     357          40 :                 free_w(&fullpath);
     358          40 :                 if(!(fullpath=prepend_s(hlinks, hfile)))
     359             :                         goto end;
     360          40 :                 if(link(s->path, fullpath))
     361             :                 {
     362           0 :                         logp("Could not hardlink %s to %s: %s\n",
     363           0 :                                 fullpath, s->path, strerror(errno));
     364           0 :                         goto end;
     365             :                 }
     366             :         }
     367             : 
     368             :         // Create a single list of files in all backups.
     369          20 :         if(!(dindex_new=prepend_s(dindex_tmp, "dindex")))
     370             :                 goto end;
     371          20 :         if(merge_files_in_dir(dindex_new,
     372             :                 dindex_tmp, "hlinks", fcount, merge_dindexes))
     373             :                         goto end;
     374             : 
     375          40 :         if(!lstat(dindex_new, &statp))
     376             :         {
     377          40 :                 if(!lstat(dindex_old, &statp)
     378          20 :                   && compare_dindexes_and_unlink_datafiles(dindex_old,
     379          20 :                         dindex_new, sdirs->data))
     380             :                                 goto end;
     381          20 :                 if(do_rename(dindex_new, dindex_old))
     382             :                         goto end;
     383             : 
     384             :                 // No longer need the current cfiles directory.
     385          20 :                 if(recursive_delete(sdirs->cfiles))
     386             :                         goto end;
     387             :         }
     388             : 
     389             :         ret=0;
     390             : end:
     391          32 :         strlists_free(&slist);
     392          32 :         if(cindex_tmp) recursive_delete(cindex_tmp);
     393          32 :         if(dindex_tmp) recursive_delete(dindex_tmp);
     394          32 :         lock_release(lock);
     395          32 :         lock_free(&lock);
     396          32 :         free_w(&fullpath);
     397          32 :         free_w(&hlinks);
     398          32 :         free_w(&cindex_tmp);
     399          32 :         free_w(&cindex_new);
     400          32 :         free_w(&dindex_tmp);
     401          32 :         free_w(&dindex_new);
     402          32 :         free_w(&dindex_old);
     403          32 :         return ret;
     404             : }

Generated by: LCOV version 1.13