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

Generated by: LCOV version 1.10