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: 169 189 89.4 %
Date: 2017-08-31 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          44 :         for(i=0; i<n; i++)
      71             :         {
      72          48 :                 free_w(&fullpath);
      73          48 :                 if(!(fullpath=prepend_s(sdirs->clients, dir[i]->d_name)))
      74             :                         goto end;
      75          48 :                 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          48 :                 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          44 :                 free_w(&dfiles);
      95          44 :                 if(!(dfiles=prepend_s(fullpath, "dfiles"))
      96          88 :                   || lstat(dfiles, &statp))
      97           0 :                         continue;
      98             : 
      99             :                 // Have a good entry. Add it to the list.
     100          44 :                 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             :         memset(&nblk, 0, sizeof(struct blk));
     154             :         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: %c\n",
     172             :                                                         __func__, nbuf.cmd);
     173           0 :                                                 goto end;
     174             :                                         }
     175          40 :                                         if(blk_set_from_iobuf_savepath(&nblk,
     176             :                                                 &nbuf)) goto end;
     177             :                                         break;
     178             :                                 default: goto end; // Error;
     179             :                         }
     180             :                 }
     181             : 
     182          88 :                 if(ozp
     183          88 :                   && !obuf.buf)
     184             :                 {
     185          87 :                         switch(iobuf_fill_from_fzp(&obuf, ozp))
     186             :                         {
     187          26 :                                 case 1: fzp_close(&ozp);
     188          26 :                                         break;
     189          61 :                                 case 0: if(obuf.cmd!=CMD_SAVE_PATH)
     190             :                                         {
     191           0 :                                                 logp("unknown cmd in %s: %c\n",
     192             :                                                         __func__, obuf.cmd);
     193           0 :                                                 goto end;
     194             :                                         }
     195          61 :                                         if(blk_set_from_iobuf_savepath(&oblk,
     196             :                                                 &obuf)) goto end;
     197             :                                         break;
     198             :                                 default: goto end; // Error;
     199             :                         }
     200             :                 }
     201             : 
     202          88 :                 if(nbuf.buf && !obuf.buf)
     203             :                 {
     204             :                         // No more from the old file. Time to stop.
     205             :                         break;
     206             :                 }
     207          83 :                 else if(!nbuf.buf && obuf.buf)
     208             :                 {
     209             :                         // No more in the new file. Delete old entry.
     210          19 :                         if(do_unlink(&oblk, datadir))
     211             :                                 goto end;
     212          19 :                         iobuf_free_content(&obuf);
     213             :                 }
     214          64 :                 else if(!nbuf.buf && !obuf.buf)
     215             :                 {
     216          21 :                         continue;
     217             :                 }
     218          43 :                 else if(nblk.savepath==oblk.savepath)
     219             :                 {
     220             :                         // Same, free both and continue;
     221          34 :                         iobuf_free_content(&nbuf);
     222          34 :                         iobuf_free_content(&obuf);
     223             :                 }
     224           9 :                 else if(nblk.savepath<oblk.savepath)
     225             :                 {
     226             :                         // Only in the new file.
     227           1 :                         iobuf_free_content(&nbuf);
     228             :                 }
     229             :                 else
     230             :                 {
     231             :                         // Only in the old file.
     232           8 :                         if(do_unlink(&oblk, datadir))
     233             :                                 goto end;
     234           8 :                         iobuf_free_content(&obuf);
     235             :                 }
     236             :         }
     237             : 
     238             : 
     239             :         ret=0;
     240             : end:
     241          26 :         iobuf_free_content(&nbuf);
     242          26 :         iobuf_free_content(&obuf);
     243          26 :         fzp_close(&nzp);
     244          26 :         fzp_close(&ozp);
     245          26 :         return ret;
     246             : }
     247             : 
     248          32 : int delete_unused_data_files(struct sdirs *sdirs, int resume)
     249             : {
     250          32 :         int ret=-1;
     251          32 :         uint64_t fcount=0;
     252             :         char hfile[32];
     253          32 :         char *hlinks=NULL;
     254          32 :         char *fullpath=NULL;
     255          32 :         char *cindex_tmp=NULL;
     256          32 :         char *cindex_new=NULL;
     257          32 :         char *dindex_tmp=NULL;
     258          32 :         char *dindex_new=NULL;
     259          32 :         char *dindex_old=NULL;
     260          32 :         struct strlist *s=NULL;
     261          32 :         struct strlist *slist=NULL;
     262             :         struct stat statp;
     263          32 :         struct lock *lock=NULL;
     264             : 
     265          32 :         if(!sdirs)
     266             :         {
     267           1 :                 logp("No sdirs passed to %s\n", __func__);
     268           1 :                 goto end;
     269             :         }
     270             : 
     271          31 :         if(resume)
     272             :         {
     273             :                 // Cannot do it on a resume, or it will delete files that are
     274             :                 // referenced in the backup we are resuming.
     275           7 :                 logp("Not attempting to clean up unused data files\n");
     276           7 :                 logp("because %s is resuming\n", sdirs->clients);
     277           7 :                 ret=0;
     278           7 :                 goto end;
     279             :         }
     280             : 
     281          24 :         if(!(lock=lock_alloc_and_init(sdirs->champ_dindex_lock)))
     282             :                 goto end;
     283          24 :         lock_get(lock);
     284          24 :         switch(lock->status)
     285             :         {
     286             :                 case GET_LOCK_GOT:
     287             :                         break;
     288             :                 default:
     289           0 :                         logp("Could not get %s\n", sdirs->champ_dindex_lock);
     290           0 :                         logp("This should not happen.\n");
     291           0 :                         goto end;
     292             :         }
     293             : 
     294          24 :         logp("Attempting to clean up unused data files %s\n", sdirs->clients);
     295             : 
     296             :         // Get all lists of files in all backups.
     297          24 :         switch(get_dfiles_to_merge(sdirs, &slist))
     298             :         {
     299             :                 case 0:
     300             :                         break; // OK.
     301             :                 case 1:
     302             :                         // Backups are in progress, cannot continue.
     303             :                         // But do not return an error.
     304           4 :                         ret=0;
     305             :                 default:
     306             :                         goto end; // Error.
     307             :         }
     308             : 
     309          20 :         if(!(dindex_tmp=prepend_s(sdirs->data, "dindex.tmp"))
     310          20 :           || !(dindex_old=prepend_s(sdirs->data, "dindex")))
     311             :                 goto end;
     312             : 
     313             :         // Get a list of the files that have been created since last time.
     314             :         // (this enables us to clean up data files that were created for
     315             :         // interrupted backups).
     316          20 :         if(!(cindex_tmp=prepend_s(sdirs->cfiles, "cindex.tmp"))
     317          20 :           || recursive_delete(cindex_tmp))
     318             :                 goto end;
     319          40 :         if(!lstat(sdirs->cfiles, &statp))
     320             :         {
     321          20 :                 if(mkdir(cindex_tmp, 0777)
     322          20 :                   || !(cindex_new=prepend_s(cindex_tmp, "cindex"))
     323          20 :                   || merge_files_in_dir_no_fcount(cindex_new,
     324          20 :                         sdirs->cfiles, merge_dindexes))
     325             :                                 goto end;
     326          40 :                 if(!lstat(cindex_new, &statp))
     327             :                 {
     328          40 :                         if(lstat(dindex_old, &statp))
     329             :                         {
     330             :                                 // The dindex file does not exist.
     331             :                                 // Just rename cindex_new.
     332          16 :                                 if(do_rename(cindex_new, dindex_old))
     333             :                                         goto end;
     334             :                         }
     335             :                         else
     336             :                         {
     337             :                                 // Merge it into the previous list of files
     338             :                                 // from all backups.
     339           4 :                                 if(merge_dindexes(dindex_tmp,
     340             :                                         dindex_old, cindex_new)
     341           4 :                                   || do_rename(dindex_tmp, dindex_old))
     342             :                                         goto end;
     343             :                         }
     344             :                 }
     345             :         }
     346             : 
     347             :         // Create a directory of hardlinks to each list of files.
     348          20 :         if(!(hlinks=prepend_s(dindex_tmp, "hlinks"))
     349          20 :           || recursive_delete(dindex_tmp)
     350          20 :           || mkdir(dindex_tmp, 0777)
     351          20 :           || mkdir(hlinks, 0777))
     352             :                 goto end;
     353          60 :         for(s=slist; s; s=s->next)
     354             :         {
     355          40 :                 snprintf(hfile, sizeof(hfile), "%08" PRIX64, fcount++);
     356          40 :                 free_w(&fullpath);
     357          40 :                 if(!(fullpath=prepend_s(hlinks, hfile)))
     358             :                         goto end;
     359          40 :                 if(link(s->path, fullpath))
     360             :                 {
     361           0 :                         logp("Could not hardlink %s to %s: %s\n",
     362           0 :                                 fullpath, s->path, strerror(errno));
     363           0 :                         goto end;
     364             :                 }
     365             :         }
     366             : 
     367             :         // Create a single list of files in all backups.
     368          20 :         if(!(dindex_new=prepend_s(dindex_tmp, "dindex")))
     369             :                 goto end;
     370          20 :         if(merge_files_in_dir(dindex_new,
     371             :                 dindex_tmp, "hlinks", fcount, merge_dindexes))
     372             :                         goto end;
     373             : 
     374          40 :         if(!lstat(dindex_new, &statp))
     375             :         {
     376          40 :                 if(!lstat(dindex_old, &statp)
     377          20 :                   && compare_dindexes_and_unlink_datafiles(dindex_old,
     378          20 :                         dindex_new, sdirs->data))
     379             :                                 goto end;
     380          20 :                 if(do_rename(dindex_new, dindex_old))
     381             :                         goto end;
     382             : 
     383             :                 // No longer need the current cfiles directory.
     384          20 :                 if(recursive_delete(sdirs->cfiles))
     385             :                         goto end;
     386             :         }
     387             : 
     388             :         ret=0;
     389             : end:
     390          32 :         strlists_free(&slist);
     391          32 :         if(cindex_tmp) recursive_delete(cindex_tmp);
     392          32 :         if(dindex_tmp) recursive_delete(dindex_tmp);
     393          32 :         lock_release(lock);
     394          32 :         lock_free(&lock);
     395          32 :         free_w(&fullpath);
     396          32 :         free_w(&hlinks);
     397          32 :         free_w(&cindex_tmp);
     398          32 :         free_w(&cindex_new);
     399          32 :         free_w(&dindex_tmp);
     400          32 :         free_w(&dindex_new);
     401          32 :         free_w(&dindex_old);
     402          32 :         return ret;
     403             : }

Generated by: LCOV version 1.10