LCOV - code coverage report
Current view: top level - src/server/protocol1 - restore.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 115 167 68.9 %
Date: 2017-05-30 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 "../../hexmap.h"
      10             : #include "../../log.h"
      11             : #include "../../prepend.h"
      12             : #include "../../protocol1/handy.h"
      13             : #include "../../server/protocol1/backup_phase4.h"
      14             : #include "../../server/protocol1/link.h"
      15             : #include "../../server/protocol1/zlibio.h"
      16             : #include "../../server/protocol2/restore.h"
      17             : #include "../../sbuf.h"
      18             : #include "../../slist.h"
      19             : #include "../sdirs.h"
      20             : #include "dpth.h"
      21             : #include "restore.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_protocol1_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           0 :         return ret;
      70             : }
      71             : 
      72           4 : static int burp_send_file(struct asfd *asfd, struct sbuf *sb,
      73             :         int patches, const char *best, struct cntr *cntr)
      74             : {
      75           4 :         int ret=-1;
      76             :         struct BFILE bfd;
      77           4 :         uint64_t bytes=0; // Unused.
      78             : 
      79           4 :         bfile_init(&bfd, 0, cntr);
      80           4 :         if(bfd.open_for_send(&bfd, asfd, best, sb->winattr,
      81             :                 1 /* no O_NOATIME */, cntr, PROTO_1)) return -1;
      82             :         //logp("sending: %s\n", best);
      83           4 :         if(asfd->write(asfd, &sb->path))
      84             :                 ret=-1;
      85           4 :         else if(patches)
      86             :         {
      87             :                 // If we did some patches, the resulting file
      88             :                 // is not gzipped. Gzip it during the send. 
      89           0 :                 ret=send_whole_file_gzl(asfd, sb->protocol1->datapth.buf,
      90             :                         1, &bytes, NULL, cntr, 9, &bfd, NULL, 0);
      91             :         }
      92             :         else
      93             :         {
      94             :                 // If it was encrypted, it may or may not have been compressed
      95             :                 // before encryption. Send it as it as, and let the client
      96             :                 // sort it out.
      97           4 :                 if(sbuf_is_encrypted(sb))
      98             :                 {
      99           2 :                         ret=send_whole_filel(asfd,
     100             : #ifdef HAVE_WIN32
     101             :                                 sb->path.cmd
     102             : #endif
     103           2 :                                 sb->protocol1->datapth.buf,
     104             :                                 1, &bytes, cntr, &bfd, NULL, 0);
     105             :                 }
     106             :                 // It might have been stored uncompressed. Gzip it during
     107             :                 // the send. If the client knew what kind of file it would be
     108             :                 // receiving, this step could disappear.
     109           2 :                 else if(!dpth_protocol1_is_compressed(sb->compression,
     110           2 :                         sb->protocol1->datapth.buf))
     111             :                 {
     112           2 :                         ret=send_whole_file_gzl(asfd,
     113           2 :                                 sb->protocol1->datapth.buf, 1, &bytes,
     114             :                                 NULL, cntr, 9, &bfd, NULL, 0);
     115             :                 }
     116             :                 else
     117             :                 {
     118             :                         // If we did not do some patches, the resulting
     119             :                         // file might already be gzipped. Send it as it is.
     120           0 :                         ret=send_whole_filel(asfd,
     121             : #ifdef HAVE_WIN32
     122             :                                 sb->path.cmd
     123             : #endif
     124           0 :                                 sb->protocol1->datapth.buf,
     125             :                                 1, &bytes, cntr, &bfd, NULL, 0);
     126             :                 }
     127             :         }
     128           4 :         bfd.close(&bfd, asfd);
     129           4 :         return ret;
     130             : }
     131             : 
     132             : #ifndef UTEST
     133             : static
     134             : #endif
     135           5 : int verify_file(struct asfd *asfd, struct sbuf *sb,
     136             :         int patches, const char *best, struct cntr *cntr)
     137             : {
     138             :         MD5_CTX md5;
     139           5 :         int b=0;
     140           5 :         const char *cp=NULL;
     141           5 :         const char *newsum=NULL;
     142             :         uint8_t in[ZCHUNK];
     143             :         uint8_t checksum[MD5_DIGEST_LENGTH];
     144           5 :         uint64_t cbytes=0;
     145           5 :         struct fzp *fzp=NULL;
     146             : 
     147           5 :         if(!sb->endfile.buf
     148           5 :           || !(cp=strrchr(sb->endfile.buf, ':')))
     149             :         {
     150           1 :                 logw(asfd, cntr,
     151           1 :                         "%s has no md5sum!\n", sb->protocol1->datapth.buf);
     152           1 :                 return 0;
     153             :         }
     154           4 :         cp++;
     155           4 :         if(!MD5_Init(&md5))
     156             :         {
     157           0 :                 logp("MD5_Init() failed\n");
     158           0 :                 return -1;
     159             :         }
     160           4 :         if(patches
     161           4 :           || sb->path.cmd==CMD_ENC_FILE
     162           4 :           || sb->path.cmd==CMD_ENC_METADATA
     163           4 :           || sb->path.cmd==CMD_EFS_FILE
     164           4 :           || sb->path.cmd==CMD_ENC_VSS
     165           4 :           || (!patches && !dpth_protocol1_is_compressed(sb->compression, best)))
     166           2 :                 fzp=fzp_open(best, "rb");
     167             :         else
     168           2 :                 fzp=fzp_gzopen(best, "rb");
     169             : 
     170           4 :         if(!fzp)
     171             :         {
     172           1 :                 logw(asfd, cntr, "could not open %s\n", best);
     173           1 :                 return 0;
     174             :         }
     175           5 :         while((b=fzp_read(fzp, in, ZCHUNK))>0)
     176             :         {
     177           2 :                 cbytes+=b;
     178           2 :                 if(!MD5_Update(&md5, in, b))
     179             :                 {
     180           0 :                         logp("MD5_Update() failed\n");
     181           0 :                         fzp_close(&fzp);
     182           0 :                         return -1;
     183             :                 }
     184             :         }
     185           3 :         if(!fzp_eof(fzp))
     186             :         {
     187           1 :                 logw(asfd, cntr, "error while reading %s\n", best);
     188           1 :                 fzp_close(&fzp);
     189           1 :                 return 0;
     190             :         }
     191           2 :         fzp_close(&fzp);
     192           2 :         if(!MD5_Final(checksum, &md5))
     193             :         {
     194           0 :                 logp("MD5_Final() failed\n");
     195           0 :                 return -1;
     196             :         }
     197           2 :         newsum=bytes_to_md5str(checksum);
     198             : 
     199           2 :         if(strcmp(newsum, cp))
     200             :         {
     201           1 :                 logp("%s %s\n", newsum, cp);
     202           1 :                 logw(asfd, cntr, "md5sum for '%s (%s)' did not match!\n",
     203           1 :                         sb->path.buf, sb->protocol1->datapth.buf);
     204           1 :                 logp("md5sum for '%s (%s)' did not match!\n",
     205           1 :                         sb->path.buf, sb->protocol1->datapth.buf);
     206           1 :                 return 0;
     207             :         }
     208             : 
     209             :         // Just send the file name to the client, so that it can show cntr.
     210           1 :         if(asfd->write(asfd, &sb->path)) return -1;
     211           1 :         return 0;
     212             : }
     213             : 
     214           4 : static int process_data_dir_file(struct asfd *asfd,
     215             :         struct bu *bu, struct bu *b, const char *path,
     216             :         struct sbuf *sb, enum action act, struct sdirs *sdirs,
     217             :         struct conf **cconfs)
     218             : {
     219           4 :         int ret=-1;
     220           4 :         int patches=0;
     221           4 :         char *dpath=NULL;
     222             :         struct stat dstatp;
     223           4 :         const char *tmp=NULL;
     224           4 :         const char *best=NULL;
     225             :         static char *tmppath1=NULL;
     226             :         static char *tmppath2=NULL;
     227           4 :         struct cntr *cntr=NULL;
     228           4 :         if(cconfs) cntr=get_cntr(cconfs);
     229             : 
     230           4 :         if((!tmppath1 && !(tmppath1=prepend_s(bu->path, "tmp1")))
     231           4 :           || (!tmppath2 && !(tmppath2=prepend_s(bu->path, "tmp2"))))
     232             :                 goto end;
     233             : 
     234           4 :         best=path;
     235           4 :         tmp=tmppath1;
     236             :         // Now go down the list, applying any deltas.
     237           4 :         for(b=b->prev; b && b->next!=bu; b=b->prev)
     238             :         {
     239           0 :                 free_w(&dpath);
     240           0 :                 if(!(dpath=prepend_s(b->delta, sb->protocol1->datapth.buf)))
     241             :                         goto end;
     242             : 
     243           0 :                 if(lstat(dpath, &dstatp) || !S_ISREG(dstatp.st_mode))
     244           0 :                         continue;
     245             : 
     246           0 :                 if(!patches)
     247             :                 {
     248             :                         // Need to gunzip the first one.
     249           0 :                         if(inflate_or_link_oldfile(asfd, best, tmp,
     250             :                                 cconfs, sb->compression))
     251             :                         {
     252           0 :                                 logw(asfd, cntr,
     253             :                                   "problem when inflating %s\n", best);
     254           0 :                                 ret=0;
     255             :                                 goto end;
     256             :                         }
     257           0 :                         best=tmp;
     258           0 :                         if(tmp==tmppath1) tmp=tmppath2;
     259             :                         else tmp=tmppath1;
     260             :                 }
     261             : 
     262           0 :                 if(do_patch(best, dpath, tmp,
     263             :                         0 /* do not gzip the result */,
     264             :                         sb->compression /* from the manifest */))
     265             :                 {
     266           0 :                         logw(asfd, cntr, "problem when patching %s with %s\n", path, b->timestamp);
     267           0 :                         ret=0;
     268             :                         goto end;
     269             :                 }
     270             : 
     271           0 :                 best=tmp;
     272           0 :                 if(tmp==tmppath1) tmp=tmppath2;
     273             :                 else tmp=tmppath1;
     274           0 :                 unlink(tmp);
     275           0 :                 patches++;
     276             :         }
     277             : 
     278           4 :         switch(act)
     279             :         {
     280             :                 case ACTION_RESTORE:
     281           4 :                         if(burp_send_file(asfd, sb, patches, best, cntr))
     282             :                                 goto end;
     283             :                         break;
     284             :                 case ACTION_VERIFY:
     285           0 :                         if(verify_file(asfd, sb, patches, best, cntr))
     286             :                                 goto end;
     287             :                         break;
     288             :                 default:
     289           0 :                         logp("Unknown action: %d\n", act);
     290             :                         goto end;
     291             :         }
     292           4 :         cntr_add(cntr, sb->path.cmd, 0);
     293           4 :         cntr_add_bytes(cntr, strtoull(sb->endfile.buf, NULL, 10));
     294             : 
     295           4 :         ret=0;
     296             : end:
     297           4 :         free_w(&dpath);
     298           4 :         if(tmppath1) unlink(tmppath1);
     299           4 :         if(tmppath2) unlink(tmppath2);
     300           4 :         free_w(&tmppath1);
     301           4 :         free_w(&tmppath2);
     302           4 :         return ret;
     303             : }
     304             : 
     305             : // a = length of struct bu array
     306             : // i = position to restore from
     307             : #ifndef UTEST
     308             : static
     309             : #endif
     310           5 : int restore_file(struct asfd *asfd, struct bu *bu,
     311             :         struct sbuf *sb, enum action act,
     312             :         struct sdirs *sdirs, struct conf **cconfs)
     313             : {
     314           5 :         int ret=-1;
     315           5 :         char *path=NULL;
     316             :         struct bu *b;
     317           5 :         struct bu *hlwarn=NULL;
     318             :         struct stat statp;
     319           5 :         struct cntr *cntr=NULL;
     320           5 :         if(cconfs) cntr=get_cntr(cconfs);
     321             : 
     322             :         // Go up the array until we find the file in the data directory.
     323          10 :         for(b=bu; b; b=b->next)
     324             :         {
     325           4 :                 free_w(&path);
     326           4 :                 if(!(path=prepend_s(b->data, sb->protocol1->datapth.buf)))
     327             :                         goto end;
     328             : 
     329           8 :                 if(lstat(path, &statp) || !S_ISREG(statp.st_mode))
     330           0 :                         continue;
     331             : 
     332           4 :                 if(b!=bu && (bu->flags & BU_HARDLINKED)) hlwarn=b;
     333             : 
     334           4 :                 if(process_data_dir_file(asfd, bu, b,
     335             :                         path, sb, act, sdirs, cconfs))
     336             :                                 goto end;
     337             : 
     338             :                 // This warning must be done after everything else,
     339             :                 // Because the client does not expect another cmd after
     340             :                 // the warning.
     341           4 :                 if(hlwarn) logw(asfd, cntr, "restore found %s in %s\n",
     342             :                         sb->path.buf, hlwarn->basename);
     343             :                 ret=0; // All OK.
     344             :                 break;
     345             :         }
     346             : 
     347           5 :         if(!b)
     348             :         {
     349           1 :                 logw(asfd, cntr, "restore could not find %s (%s)\n",
     350           1 :                         sb->path.buf, sb->protocol1->datapth.buf);
     351           1 :                 ret=0; // Carry on to subsequent files.
     352             :         }
     353             : end:
     354           5 :         free_w(&path);
     355           5 :         return ret;
     356             : }
     357             : 
     358          10 : int restore_sbuf_protocol1(struct asfd *asfd, struct sbuf *sb, struct bu *bu,
     359             :         enum action act, struct sdirs *sdirs, struct conf **cconfs)
     360             : {
     361          10 :         if((sb->protocol1->datapth.buf
     362           4 :                 && asfd->write(asfd, &(sb->protocol1->datapth)))
     363          10 :           || asfd->write(asfd, &sb->attr))
     364             :                 return -1;
     365          10 :         else if(sbuf_is_filedata(sb)
     366           6 :           || sbuf_is_vssdata(sb))
     367             :         {
     368           4 :                 if(!sb->protocol1->datapth.buf)
     369             :                 {
     370           0 :                         logw(asfd, get_cntr(cconfs),
     371             :                                 "Got filedata entry with no datapth: %c:%s\n",
     372           0 :                                         sb->path.cmd, sb->path.buf);
     373           0 :                         return 0;
     374             :                 }
     375           4 :                 return restore_file(asfd, bu, sb, act, sdirs, cconfs);
     376             :         }
     377             :         else
     378             :         {
     379           6 :                 if(asfd->write(asfd, &sb->path))
     380             :                         return -1;
     381             :                 // If it is a link, send what
     382             :                 // it points to.
     383           6 :                 else if(sbuf_is_link(sb)
     384           4 :                   && asfd->write(asfd, &sb->link)) return -1;
     385           6 :                 cntr_add(get_cntr(cconfs), sb->path.cmd, 0);
     386             :         }
     387           6 :         return 0;
     388             : }

Generated by: LCOV version 1.10