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

Generated by: LCOV version 1.10