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

Generated by: LCOV version 1.10