LCOV - code coverage report
Current view: top level - src/server - restore_sbuf.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 118 173 68.2 %
Date: 2022-12-03 01:09:05 Functions: 5 7 71.4 %

          Line data    Source code
       1             : #include "../burp.h"
       2             : #include "../alloc.h"
       3             : #include "../asfd.h"
       4             : #include "../async.h"
       5             : #include "../bu.h"
       6             : #include "../cmd.h"
       7             : #include "../cntr.h"
       8             : #include "../handy.h"
       9             : #include "../handy_extra.h"
      10             : #include "../hexmap.h"
      11             : #include "../log.h"
      12             : #include "../md5.h"
      13             : #include "../prepend.h"
      14             : #include "../server/backup_phase4.h"
      15             : #include "../server/link.h"
      16             : #include "../server/zlibio.h"
      17             : #include "../sbuf.h"
      18             : #include "../slist.h"
      19             : #include "dpth.h"
      20             : #include "sdirs.h"
      21             : #include "restore_sbuf.h"
      22             : 
      23             : #include <librsync.h>
      24             : 
      25           0 : static int create_zero_length_file(const char *path)
      26             : {
      27           0 :         int ret=0;
      28             :         struct fzp *dest;
      29           0 :         if(!(dest=fzp_open(path, "wb")))
      30           0 :                 ret=-1;
      31           0 :         ret|=fzp_close(&dest);
      32           0 :         return ret;
      33             : }
      34             : 
      35           0 : static int inflate_or_link_oldfile(struct asfd *asfd, const char *oldpath,
      36             :         const char *infpath, struct conf **cconfs, int compression)
      37             : {
      38           0 :         int ret=0;
      39             :         struct stat statp;
      40             : 
      41           0 :         if(lstat(oldpath, &statp))
      42             :         {
      43           0 :                 logp("could not lstat %s\n", oldpath);
      44           0 :                 return -1;
      45             :         }
      46             : 
      47           0 :         if(dpth_is_compressed(compression, oldpath))
      48             :         {
      49             :                 //logp("inflating...\n");
      50             : 
      51           0 :                 if(!statp.st_size)
      52             :                 {
      53             :                         // Empty file - cannot inflate.
      54           0 :                         logp("asked to inflate zero length file: %s\n",
      55             :                                 oldpath);
      56           0 :                         return create_zero_length_file(infpath);
      57             :                 }
      58             : 
      59           0 :                 if((ret=zlib_inflate(asfd, oldpath, infpath, get_cntr(cconfs))))
      60           0 :                         logp("zlib_inflate returned: %d\n", ret);
      61             :         }
      62             :         else
      63             :         {
      64             :                 // Not compressed - just hard link it.
      65           0 :                 if(do_link(oldpath, infpath, &statp, cconfs,
      66             :                         1 /* allow overwrite of infpath */))
      67             :                                 return -1;
      68             :         }
      69             :         return ret;
      70             : }
      71             : 
      72           4 : static int do_send_file(struct asfd *asfd, struct sbuf *sb,
      73             :         int patches, const char *best, struct cntr *cntr)
      74             : {
      75           4 :         enum send_e ret=SEND_FATAL;
      76             :         struct BFILE bfd;
      77           4 :         uint64_t bytes=0; // Unused.
      78             : 
      79           4 :         bfile_init(&bfd, 0, 0, cntr);
      80          12 :         if(bfd.open_for_send(&bfd, asfd, best,
      81           8 :                 sb->use_winapi, sb->winattr,
      82             :                 1 /* no O_NOATIME */, cntr))
      83             :                         return SEND_FATAL;
      84           4 :         if(asfd->write(asfd, &sb->path))
      85             :                 ret=SEND_FATAL;
      86           4 :         else if(patches)
      87             :         {
      88             :                 // If we did some patches, the resulting file
      89             :                 // is not gzipped. Gzip it during the send.
      90           0 :                 ret=send_whole_file_gzl(
      91             :                         asfd,
      92           0 :                         sb->datapth.buf,
      93             :                         /*quick_read*/1,
      94             :                         &bytes,
      95             :                         /*encpassword*/NULL,
      96             :                         cntr,
      97             :                         /*compression*/9,
      98             :                         &bfd,
      99             :                         /*extrameta*/NULL,
     100             :                         /*elen*/0,
     101             :                         /*key_deriv*/ENCRYPTION_UNSET,
     102             :                         /*salt*/0
     103             :                 );
     104             :         }
     105             :         else
     106             :         {
     107             :                 // If it was encrypted, it may or may not have been compressed
     108             :                 // before encryption. Send it as it as, and let the client
     109             :                 // sort it out.
     110           4 :                 if(sbuf_is_encrypted(sb))
     111             :                 {
     112           2 :                         ret=send_whole_filel(asfd,
     113             : #ifdef HAVE_WIN32
     114             :                                 sb->path.cmd
     115             : #endif
     116           2 :                                 sb->datapth.buf,
     117             :                                 1, &bytes, cntr, &bfd, NULL, 0);
     118             :                 }
     119             :                 // It might have been stored uncompressed. Gzip it during
     120             :                 // the send. If the client knew what kind of file it would be
     121             :                 // receiving, this step could disappear.
     122           2 :                 else if(!dpth_is_compressed(sb->compression,
     123           2 :                         sb->datapth.buf))
     124             :                 {
     125           2 :                         ret=send_whole_file_gzl(
     126             :                                 asfd,
     127           2 :                                 sb->datapth.buf,
     128             :                                 /*quick_read*/1,
     129             :                                 &bytes,
     130             :                                 /*encpassword*/NULL,
     131             :                                 cntr,
     132             :                                 /*compression*/9,
     133             :                                 &bfd,
     134             :                                 /*extrameta*/NULL,
     135             :                                 /*elen*/0,
     136             :                                 /*key_deriv*/ENCRYPTION_UNSET,
     137             :                                 /*salt*/0
     138             :                         );
     139             :                 }
     140             :                 else
     141             :                 {
     142             :                         // If we did not do some patches, the resulting
     143             :                         // file might already be gzipped. Send it as it is.
     144           0 :                         ret=send_whole_filel(asfd,
     145             : #ifdef HAVE_WIN32
     146             :                                 sb->path.cmd
     147             : #endif
     148           0 :                                 sb->datapth.buf,
     149             :                                 1, &bytes, cntr, &bfd, NULL, 0);
     150             :                 }
     151             :         }
     152           4 :         bfd.close(&bfd, asfd);
     153             : 
     154           4 :         switch(ret)
     155             :         {
     156             :                 case SEND_OK:
     157             :                 case SEND_ERROR: // Carry on.
     158             :                         return 0;
     159             :                 case SEND_FATAL:
     160             :                 default:
     161           0 :                         return -1;
     162             :         }
     163             : }
     164             : 
     165             : #ifndef UTEST
     166             : static
     167             : #endif
     168           5 : int verify_file(struct asfd *asfd, struct sbuf *sb,
     169             :         int patches, const char *best, struct cntr *cntr)
     170             : {
     171           5 :         struct md5 *md5=NULL;
     172           5 :         int b=0;
     173           5 :         const char *cp=NULL;
     174           5 :         const char *newsum=NULL;
     175             :         uint8_t in[ZCHUNK];
     176             :         uint8_t checksum[MD5_DIGEST_LENGTH];
     177           5 :         uint64_t cbytes=0;
     178           5 :         struct fzp *fzp=NULL;
     179             : 
     180           5 :         if(!sb->endfile.buf
     181           5 :           || !(cp=strrchr(sb->endfile.buf, ':')))
     182             :         {
     183           1 :                 logw(asfd, cntr,
     184             :                         "%s has no md5sum!\n",
     185             :                         iobuf_to_printable(&sb->datapth));
     186           1 :                 return 0;
     187             :         }
     188           4 :         cp++;
     189           4 :         if(!(md5=md5_alloc(__func__)))
     190             :                 return -1;
     191           4 :         if(!md5_init(md5))
     192             :         {
     193           0 :                 logp("md5_init() failed\n");
     194           0 :                 md5_free(&md5);
     195           0 :                 return -1;
     196             :         }
     197           4 :         if(patches
     198           4 :           || sb->path.cmd==CMD_ENC_FILE
     199           4 :           || sb->path.cmd==CMD_ENC_METADATA
     200           4 :           || sb->path.cmd==CMD_EFS_FILE
     201           4 :           || sb->path.cmd==CMD_ENC_VSS
     202           4 :           || sb->path.cmd==CMD_ENC_VSS_T
     203           4 :           || (!patches && !dpth_is_compressed(sb->compression, best)))
     204           2 :                 fzp=fzp_open(best, "rb");
     205             :         else
     206           2 :                 fzp=fzp_gzopen(best, "rb");
     207             : 
     208           4 :         if(!fzp)
     209             :         {
     210           1 :                 logw(asfd, cntr, "could not open %s\n", best);
     211           1 :                 md5_free(&md5);
     212           1 :                 return 0;
     213             :         }
     214           5 :         while((b=fzp_read(fzp, in, ZCHUNK))>0)
     215             :         {
     216           2 :                 cbytes+=b;
     217           2 :                 if(!md5_update(md5, in, b))
     218             :                 {
     219           0 :                         logp("md5_update() failed\n");
     220           0 :                         fzp_close(&fzp);
     221           0 :                         md5_free(&md5);
     222           0 :                         return -1;
     223             :                 }
     224             :         }
     225           3 :         if(!fzp_eof(fzp))
     226             :         {
     227           1 :                 logw(asfd, cntr, "error while reading %s\n", best);
     228           1 :                 fzp_close(&fzp);
     229           1 :                 md5_free(&md5);
     230           1 :                 return 0;
     231             :         }
     232           2 :         fzp_close(&fzp);
     233           2 :         if(!md5_final(md5, checksum))
     234             :         {
     235           0 :                 logp("md5_final() failed\n");
     236           0 :                 md5_free(&md5);
     237           0 :                 return -1;
     238             :         }
     239           2 :         newsum=bytes_to_md5str(checksum);
     240           2 :         md5_free(&md5);
     241             : 
     242           2 :         if(strcmp(newsum, cp))
     243             :         {
     244           1 :                 logp("%s %s\n", newsum, cp);
     245           1 :                 logw(asfd, cntr, "md5sum for '%s (%s)' did not match!\n",
     246             :                         iobuf_to_printable(&sb->path),
     247             :                         iobuf_to_printable(&sb->datapth));
     248           1 :                 logp("md5sum for '%s (%s)' did not match!\n",
     249             :                         iobuf_to_printable(&sb->path),
     250             :                         iobuf_to_printable(&sb->datapth));
     251           1 :                 return 0;
     252             :         }
     253             : 
     254             :         // Just send the file name to the client, so that it can show cntr.
     255           1 :         if(asfd->write(asfd, &sb->path)) return -1;
     256           1 :         return 0;
     257             : }
     258             : 
     259           4 : static int process_data_dir_file(struct asfd *asfd,
     260             :         struct bu *bu, struct bu *b, const char *path,
     261             :         struct sbuf *sb, enum action act, struct sdirs *sdirs,
     262             :         struct conf **cconfs)
     263             : {
     264           4 :         int ret=-1;
     265           4 :         int patches=0;
     266           4 :         char *dpath=NULL;
     267             :         struct stat dstatp;
     268           4 :         const char *tmp=NULL;
     269           4 :         const char *best=NULL;
     270             :         static char *tmppath1=NULL;
     271             :         static char *tmppath2=NULL;
     272           4 :         struct cntr *cntr=NULL;
     273           4 :         if(cconfs) cntr=get_cntr(cconfs);
     274             : 
     275           4 :         if((!tmppath1 && !(tmppath1=prepend_s(bu->path, "tmp1")))
     276           4 :           || (!tmppath2 && !(tmppath2=prepend_s(bu->path, "tmp2"))))
     277             :                 goto end;
     278             : 
     279           4 :         best=path;
     280           4 :         tmp=tmppath1;
     281             :         // Now go down the list, applying any deltas.
     282           4 :         for(b=b->prev; b && b->next!=bu; b=b->prev)
     283             :         {
     284           0 :                 free_w(&dpath);
     285           0 :                 if(!(dpath=prepend_s(b->delta, sb->datapth.buf)))
     286             :                         goto end;
     287             : 
     288           0 :                 if(lstat(dpath, &dstatp) || !S_ISREG(dstatp.st_mode))
     289           0 :                         continue;
     290             : 
     291           0 :                 if(!patches)
     292             :                 {
     293             :                         // Need to gunzip the first one.
     294           0 :                         if(inflate_or_link_oldfile(asfd, best, tmp,
     295             :                                 cconfs, sb->compression))
     296             :                         {
     297           0 :                                 logw(asfd, cntr,
     298             :                                   "problem when inflating %s\n", best);
     299           0 :                                 ret=0;
     300             :                                 goto end;
     301             :                         }
     302           0 :                         best=tmp;
     303           0 :                         if(tmp==tmppath1) tmp=tmppath2;
     304             :                         else tmp=tmppath1;
     305             :                 }
     306             : 
     307           0 :                 if(do_patch(best, dpath, tmp,
     308             :                         0 /* do not gzip the result */,
     309             :                         sb->compression /* from the manifest */))
     310             :                 {
     311           0 :                         logw(asfd, cntr, "problem when patching %s with %s\n", path, b->timestamp);
     312           0 :                         ret=0;
     313             :                         goto end;
     314             :                 }
     315             : 
     316           0 :                 best=tmp;
     317           0 :                 if(tmp==tmppath1) tmp=tmppath2;
     318             :                 else tmp=tmppath1;
     319           0 :                 unlink(tmp);
     320           0 :                 patches++;
     321             :         }
     322             : 
     323           4 :         switch(act)
     324             :         {
     325             :                 case ACTION_RESTORE:
     326           4 :                         if(do_send_file(asfd, sb, patches, best, cntr))
     327             :                                 goto end;
     328             :                         break;
     329             :                 case ACTION_VERIFY:
     330           0 :                         if(verify_file(asfd, sb, patches, best, cntr))
     331             :                                 goto end;
     332             :                         break;
     333             :                 default:
     334           0 :                         logp("Unknown action: %d\n", act);
     335             :                         goto end;
     336             :         }
     337           4 :         cntr_add(cntr, sb->path.cmd, 0);
     338           4 :         cntr_add_bytes(cntr, strtoull(sb->endfile.buf, NULL, 10));
     339             : 
     340           4 :         ret=0;
     341             : end:
     342           4 :         free_w(&dpath);
     343           4 :         if(tmppath1) unlink(tmppath1);
     344           4 :         if(tmppath2) unlink(tmppath2);
     345           4 :         free_w(&tmppath1);
     346           4 :         free_w(&tmppath2);
     347           4 :         return ret;
     348             : }
     349             : 
     350             : // a = length of struct bu array
     351             : // i = position to restore from
     352             : #ifndef UTEST
     353             : static
     354             : #endif
     355           5 : int restore_file(struct asfd *asfd, struct bu *bu,
     356             :         struct sbuf *sb, enum action act,
     357             :         struct sdirs *sdirs, struct conf **cconfs)
     358             : {
     359           5 :         int ret=-1;
     360           5 :         char *path=NULL;
     361             :         struct bu *b;
     362           5 :         struct bu *hlwarn=NULL;
     363             :         struct stat statp;
     364           5 :         struct cntr *cntr=NULL;
     365           5 :         if(cconfs) cntr=get_cntr(cconfs);
     366             : 
     367             :         // Go up the array until we find the file in the data directory.
     368          10 :         for(b=bu; b; b=b->next)
     369             :         {
     370           4 :                 free_w(&path);
     371           4 :                 if(!(path=prepend_s(b->data, sb->datapth.buf)))
     372             :                         goto end;
     373             : 
     374           8 :                 if(lstat(path, &statp) || !S_ISREG(statp.st_mode))
     375           0 :                         continue;
     376             : 
     377           4 :                 if(b!=bu && (bu->flags & BU_HARDLINKED)) hlwarn=b;
     378             : 
     379           4 :                 if(process_data_dir_file(asfd, bu, b,
     380             :                         path, sb, act, sdirs, cconfs))
     381             :                                 goto end;
     382             : 
     383             :                 // This warning must be done after everything else,
     384             :                 // Because the client does not expect another cmd after
     385             :                 // the warning.
     386           4 :                 if(hlwarn) logw(asfd, cntr, "restore found %s in %s\n",
     387             :                         iobuf_to_printable(&sb->path),
     388             :                         hlwarn->basename);
     389             :                 ret=0; // All OK.
     390             :                 break;
     391             :         }
     392             : 
     393           5 :         if(!b)
     394             :         {
     395           1 :                 logw(asfd, cntr, "restore could not find %s (%s)\n",
     396             :                         iobuf_to_printable(&sb->path),
     397             :                         iobuf_to_printable(&sb->datapth));
     398           1 :                 ret=0; // Carry on to subsequent files.
     399             :         }
     400             : end:
     401           5 :         free_w(&path);
     402           5 :         return ret;
     403             : }
     404             : 
     405          10 : int restore_sbuf_all(struct asfd *asfd, struct sbuf *sb, struct bu *bu,
     406             :         enum action act, struct sdirs *sdirs, struct conf **cconfs)
     407             : {
     408          10 :         if((sb->datapth.buf
     409           4 :                 && asfd->write(asfd, &(sb->datapth)))
     410          10 :           || asfd->write(asfd, &sb->attr))
     411             :                 return -1;
     412          10 :         else if(sbuf_is_filedata(sb)
     413           6 :           || sbuf_is_vssdata(sb))
     414             :         {
     415           4 :                 if(!sb->datapth.buf)
     416             :                 {
     417           0 :                         logw(asfd, get_cntr(cconfs),
     418             :                                 "Got filedata entry with no datapth: %s\n",
     419             :                                         iobuf_to_printable(&sb->path));
     420           0 :                         return 0;
     421             :                 }
     422           4 :                 return restore_file(asfd, bu, sb, act, sdirs, cconfs);
     423             :         }
     424             :         else
     425             :         {
     426           6 :                 if(asfd->write(asfd, &sb->path))
     427             :                         return -1;
     428             :                 // If it is a link, send what
     429             :                 // it points to.
     430           6 :                 else if(sbuf_is_link(sb)
     431           4 :                   && asfd->write(asfd, &sb->link)) return -1;
     432           6 :                 cntr_add(get_cntr(cconfs), sb->path.cmd, 0);
     433             :         }
     434           6 :         return 0;
     435             : }

Generated by: LCOV version 1.13