LCOV - code coverage report
Current view: top level - src/server/protocol1 - restore.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 67 162 41.4 %
Date: 2016-09-04 Functions: 4 7 57.1 %

          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 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           0 : static int verify_file(struct asfd *asfd, struct sbuf *sb,
     133             :         int patches, const char *best, struct cntr *cntr)
     134             : {
     135             :         MD5_CTX md5;
     136           0 :         size_t b=0;
     137           0 :         const char *cp=NULL;
     138           0 :         const char *newsum=NULL;
     139             :         uint8_t in[ZCHUNK];
     140             :         uint8_t checksum[MD5_DIGEST_LENGTH];
     141           0 :         uint64_t cbytes=0;
     142           0 :         struct fzp *fzp=NULL;
     143             : 
     144           0 :         if(!(cp=strrchr(sb->endfile.buf, ':')))
     145             :         {
     146           0 :                 logw(asfd, cntr,
     147           0 :                         "%s has no md5sum!\n", sb->protocol1->datapth.buf);
     148           0 :                 return 0;
     149             :         }
     150           0 :         cp++;
     151           0 :         if(!MD5_Init(&md5))
     152             :         {
     153           0 :                 logp("MD5_Init() failed\n");
     154           0 :                 return -1;
     155             :         }
     156           0 :         if(patches
     157           0 :           || sb->path.cmd==CMD_ENC_FILE
     158           0 :           || sb->path.cmd==CMD_ENC_METADATA
     159           0 :           || sb->path.cmd==CMD_EFS_FILE
     160           0 :           || sb->path.cmd==CMD_ENC_VSS
     161           0 :           || (!patches && !dpth_protocol1_is_compressed(sb->compression, best)))
     162           0 :                 fzp=fzp_open(best, "rb");
     163             :         else
     164           0 :                 fzp=fzp_gzopen(best, "rb");
     165             : 
     166           0 :         if(!fzp)
     167             :         {
     168           0 :                 logw(asfd, cntr, "could not open %s\n", best);
     169           0 :                 return 0;
     170             :         }
     171           0 :         while((b=fzp_read(fzp, in, ZCHUNK))>0)
     172             :         {
     173           0 :                 cbytes+=b;
     174           0 :                 if(!MD5_Update(&md5, in, b))
     175             :                 {
     176           0 :                         logp("MD5_Update() failed\n");
     177           0 :                         fzp_close(&fzp);
     178           0 :                         return -1;
     179             :                 }
     180             :         }
     181           0 :         if(!fzp_eof(fzp))
     182             :         {
     183           0 :                 logw(asfd, cntr, "error while reading %s\n", best);
     184           0 :                 fzp_close(&fzp);
     185           0 :                 return 0;
     186             :         }
     187           0 :         fzp_close(&fzp);
     188           0 :         if(!MD5_Final(checksum, &md5))
     189             :         {
     190           0 :                 logp("MD5_Final() failed\n");
     191           0 :                 return -1;
     192             :         }
     193           0 :         newsum=bytes_to_md5str(checksum);
     194             : 
     195           0 :         if(strcmp(newsum, cp))
     196             :         {
     197           0 :                 logp("%s %s\n", newsum, cp);
     198           0 :                 logw(asfd, cntr, "md5sum for '%s (%s)' did not match!\n",
     199           0 :                         sb->path.buf, sb->protocol1->datapth.buf);
     200           0 :                 logp("md5sum for '%s (%s)' did not match!\n",
     201           0 :                         sb->path.buf, sb->protocol1->datapth.buf);
     202           0 :                 return 0;
     203             :         }
     204             : 
     205             :         // Just send the file name to the client, so that it can show cntr.
     206           0 :         if(asfd->write(asfd, &sb->path)) return -1;
     207           0 :         return 0;
     208             : }
     209             : 
     210           4 : static int process_data_dir_file(struct asfd *asfd,
     211             :         struct bu *bu, struct bu *b, const char *path,
     212             :         struct sbuf *sb, enum action act, struct sdirs *sdirs,
     213             :         struct conf **cconfs)
     214             : {
     215           4 :         int ret=-1;
     216           4 :         int patches=0;
     217           4 :         char *dpath=NULL;
     218             :         struct stat dstatp;
     219           4 :         const char *tmp=NULL;
     220           4 :         const char *best=NULL;
     221             :         static char *tmppath1=NULL;
     222             :         static char *tmppath2=NULL;
     223           4 :         struct cntr *cntr=NULL;
     224           4 :         if(cconfs) cntr=get_cntr(cconfs);
     225             : 
     226           4 :         if((!tmppath1 && !(tmppath1=prepend_s(sdirs->client, "tmp1")))
     227           4 :           || (!tmppath2 && !(tmppath2=prepend_s(sdirs->client, "tmp2"))))
     228             :                 goto end;
     229             : 
     230           4 :         best=path;
     231           4 :         tmp=tmppath1;
     232             :         // Now go down the list, applying any deltas.
     233           4 :         for(b=b->prev; b && b->next!=bu; b=b->prev)
     234             :         {
     235           0 :                 free_w(&dpath);
     236           0 :                 if(!(dpath=prepend_s(b->delta, sb->protocol1->datapth.buf)))
     237             :                         goto end;
     238             : 
     239           0 :                 if(lstat(dpath, &dstatp) || !S_ISREG(dstatp.st_mode))
     240           0 :                         continue;
     241             : 
     242           0 :                 if(!patches)
     243             :                 {
     244             :                         // Need to gunzip the first one.
     245           0 :                         if(inflate_or_link_oldfile(asfd, best, tmp,
     246             :                                 cconfs, sb->compression))
     247             :                         {
     248           0 :                                 logw(asfd, cntr,
     249             :                                   "problem when inflating %s\n", best);
     250           0 :                                 ret=0;
     251             :                                 goto end;
     252             :                         }
     253           0 :                         best=tmp;
     254           0 :                         if(tmp==tmppath1) tmp=tmppath2;
     255             :                         else tmp=tmppath1;
     256             :                 }
     257             : 
     258           0 :                 if(do_patch(best, dpath, tmp,
     259             :                         0 /* do not gzip the result */,
     260             :                         sb->compression /* from the manifest */))
     261             :                 {
     262           0 :                         logw(asfd, cntr, "problem when patching %s with %s\n", path, b->timestamp);
     263           0 :                         ret=0;
     264             :                         goto end;
     265             :                 }
     266             : 
     267           0 :                 best=tmp;
     268           0 :                 if(tmp==tmppath1) tmp=tmppath2;
     269             :                 else tmp=tmppath1;
     270           0 :                 unlink(tmp);
     271           0 :                 patches++;
     272             :         }
     273             : 
     274           4 :         switch(act)
     275             :         {
     276             :                 case ACTION_RESTORE:
     277           4 :                         if(send_file(asfd, sb, patches, best, cntr))
     278             :                                 goto end;
     279             :                         break;
     280             :                 case ACTION_VERIFY:
     281           0 :                         if(verify_file(asfd, sb, patches, best, cntr))
     282             :                                 goto end;
     283             :                         break;
     284             :                 default:
     285           0 :                         logp("Unknown action: %d\n", act);
     286             :                         goto end;
     287             :         }
     288           4 :         cntr_add(cntr, sb->path.cmd, 0);
     289           4 :         cntr_add_bytes(cntr, strtoull(sb->endfile.buf, NULL, 10));
     290             : 
     291           4 :         ret=0;
     292             : end:
     293           4 :         free_w(&dpath);
     294           4 :         free_w(&tmppath1);
     295           4 :         free_w(&tmppath2);
     296           4 :         return ret;
     297             : }
     298             : 
     299             : // a = length of struct bu array
     300             : // i = position to restore from
     301           4 : static int restore_file(struct asfd *asfd, struct bu *bu,
     302             :         struct sbuf *sb, enum action act,
     303             :         struct sdirs *sdirs, struct conf **cconfs)
     304             : {
     305           4 :         int ret=-1;
     306           4 :         char *path=NULL;
     307             :         struct bu *b;
     308           4 :         struct bu *hlwarn=NULL;
     309             :         struct stat statp;
     310           4 :         struct cntr *cntr=NULL;
     311           4 :         if(cconfs) cntr=get_cntr(cconfs);
     312             : 
     313             :         // Go up the array until we find the file in the data directory.
     314           8 :         for(b=bu; b; b=b->next)
     315             :         {
     316           4 :                 free_w(&path);
     317           4 :                 if(!(path=prepend_s(b->data, sb->protocol1->datapth.buf)))
     318             :                         goto end;
     319             : 
     320           8 :                 if(lstat(path, &statp) || !S_ISREG(statp.st_mode))
     321           0 :                         continue;
     322             : 
     323           4 :                 if(b!=bu && (bu->flags & BU_HARDLINKED)) hlwarn=b;
     324             : 
     325           4 :                 if(process_data_dir_file(asfd, bu, b,
     326             :                         path, sb, act, sdirs, cconfs)) goto end;
     327             : 
     328             :                 // This warning must be done after everything else,
     329             :                 // Because the client does not expect another cmd after
     330             :                 // the warning.
     331           4 :                 if(hlwarn) logw(asfd, cntr, "restore found %s in %s\n",
     332             :                         sb->path.buf, hlwarn->basename);
     333             :                 ret=0; // All OK.
     334             :                 break;
     335             :         }
     336             : 
     337           4 :         if(!b) logw(asfd, cntr, "restore could not find %s (%s)\n",
     338           0 :                 sb->path.buf, sb->protocol1->datapth.buf);
     339             : end:
     340           4 :         free_w(&path);
     341           4 :         return ret;
     342             : }
     343             : 
     344          10 : int restore_sbuf_protocol1(struct asfd *asfd, struct sbuf *sb, struct bu *bu,
     345             :         enum action act, struct sdirs *sdirs, struct conf **cconfs)
     346             : {
     347          10 :         if((sb->protocol1->datapth.buf
     348           4 :                 && asfd->write(asfd, &(sb->protocol1->datapth)))
     349          10 :           || asfd->write(asfd, &sb->attr))
     350             :                 return -1;
     351          10 :         else if(sbuf_is_filedata(sb)
     352           6 :           || sbuf_is_vssdata(sb))
     353             :         {
     354           4 :                 if(!sb->protocol1->datapth.buf)
     355             :                 {
     356           0 :                         logw(asfd, get_cntr(cconfs),
     357             :                                 "Got filedata entry with no datapth: %c:%s\n",
     358           0 :                                         sb->path.cmd, sb->path.buf);
     359           0 :                         return 0;
     360             :                 }
     361           4 :                 return restore_file(asfd, bu, sb, act, sdirs, cconfs);
     362             :         }
     363             :         else
     364             :         {
     365           6 :                 if(asfd->write(asfd, &sb->path))
     366             :                         return -1;
     367             :                 // If it is a link, send what
     368             :                 // it points to.
     369           6 :                 else if(sbuf_is_link(sb)
     370           4 :                   && asfd->write(asfd, &sb->link)) return -1;
     371           6 :                 cntr_add(get_cntr(cconfs), sb->path.cmd, 0);
     372             :         }
     373           6 :         return 0;
     374             : }

Generated by: LCOV version 1.10