LCOV - code coverage report
Current view: top level - src/client - backup_phase2.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 157 212 74.1 %
Date: 2022-12-03 01:09:05 Functions: 9 10 90.0 %

          Line data    Source code
       1             : #include "../burp.h"
       2             : #include "../action.h"
       3             : #include "../alloc.h"
       4             : #include "../asfd.h"
       5             : #include "../async.h"
       6             : #include "../attribs.h"
       7             : #include "../cmd.h"
       8             : #include "../cntr.h"
       9             : #include "../conf.h"
      10             : #include "../handy_extra.h"
      11             : #include "../log.h"
      12             : #include "../md5.h"
      13             : #include "../transfer.h"
      14             : #include "cvss.h"
      15             : #include "extrameta.h"
      16             : #include "find.h"
      17             : #include "backup_phase2.h"
      18             : 
      19           2 : static int rs_loadsig_network_run(struct asfd *asfd,
      20             :         rs_job_t *job, struct cntr *cntr)
      21             : {
      22           2 :         int ret=-1;
      23             :         rs_buffers_t buf;
      24             :         rs_result result;
      25           2 :         rs_filebuf_t *in_fb=NULL;
      26           2 :         memset(&buf, 0, sizeof(buf));
      27             : 
      28           2 :         if(!(in_fb=rs_filebuf_new(NULL,
      29             :                 NULL, asfd, ASYNC_BUF_LEN, -1)))
      30             :                 goto end;
      31             : 
      32             :         while(1)
      33             :         {
      34           4 :                 iobuf_free_content(asfd->rbuf);
      35           4 :                 if(asfd->read(asfd)) goto end;
      36           8 :                 if(asfd->rbuf->cmd==CMD_MESSAGE
      37           4 :                   || asfd->rbuf->cmd==CMD_WARNING)
      38             :                 {
      39           0 :                         log_recvd(asfd->rbuf, cntr, 0);
      40           0 :                         continue;
      41             :                 }
      42           4 :                 switch((result=rs_async(job, &buf, in_fb, NULL)))
      43             :                 {
      44             :                         case RS_BLOCKED:
      45             :                         case RS_RUNNING:
      46           2 :                                 continue;
      47             :                         case RS_DONE:
      48             :                                 ret=0;
      49             :                                 goto end;
      50             :                         default:
      51           0 :                                 logp("error in rs_async for sig: %d\n",
      52             :                                         result);
      53           0 :                                 goto end;
      54             :                 }
      55             :         }
      56             : 
      57             : end:
      58           2 :         iobuf_free_content(asfd->rbuf);
      59           2 :         rs_filebuf_free(&in_fb);
      60           2 :         return ret;
      61             : }
      62             : 
      63           2 : static int load_signature(struct asfd *asfd,
      64             :         rs_signature_t **sumset, struct cntr *cntr)
      65             : {
      66             :         rs_job_t *job;
      67             : 
      68           2 :         if(!(job=rs_loadsig_begin(sumset)))
      69             :         {
      70           0 :                 logp("could not start sig job.\n");
      71           0 :                 return -1;
      72             :         }
      73           2 :         if(rs_loadsig_network_run(asfd, job, cntr))
      74             :                 return -1;
      75           2 :         if(rs_build_hash_table(*sumset))
      76             :                 return -1;
      77           2 :         rs_job_free(job);
      78           2 :         return 0;
      79             : }
      80             : 
      81           2 : static int load_signature_and_send_delta(struct asfd *asfd,
      82             :         struct BFILE *bfd, uint64_t *bytes, uint64_t *sentbytes,
      83             :         struct cntr *cntr)
      84             : {
      85           2 :         int ret=-1;
      86           2 :         rs_job_t *job=NULL;
      87           2 :         rs_signature_t *sumset=NULL;
      88             :         uint8_t checksum[MD5_DIGEST_LENGTH];
      89           2 :         rs_filebuf_t *infb=NULL;
      90           2 :         rs_filebuf_t *outfb=NULL;
      91             :         rs_buffers_t rsbuf;
      92           2 :         memset(&rsbuf, 0, sizeof(rsbuf));
      93             : 
      94           2 :         if(load_signature(asfd, &sumset, cntr))
      95             :                 goto end;
      96             : 
      97           2 :         if(!(job=rs_delta_begin(sumset)))
      98             :         {
      99           0 :                 logp("could not start delta job.\n");
     100           0 :                 goto end;
     101             :         }
     102             : 
     103           2 :         if(!(infb=rs_filebuf_new(bfd,
     104             :                 NULL, NULL, ASYNC_BUF_LEN, bfd->datalen))
     105           2 :           || !(outfb=rs_filebuf_new(NULL,
     106             :                 NULL, asfd, ASYNC_BUF_LEN, -1)))
     107             :         {
     108           0 :                 logp("could not rs_filebuf_new for delta\n");
     109           0 :                 goto end;
     110             :         }
     111             : 
     112             :         while(1)
     113           4 :         {
     114             :                 rs_result result;
     115           6 :                 switch((result=rs_async(job, &rsbuf, infb, outfb)))
     116             :                 {
     117             :                         case RS_DONE:
     118           2 :                                 *bytes=infb->bytes;
     119           2 :                                 *sentbytes=outfb->bytes;
     120           2 :                                 if(!md5_final(infb->md5, checksum))
     121             :                                 {
     122           0 :                                         logp("md5_final() failed\n");
     123           0 :                                         goto end;
     124             :                                 }
     125           2 :                                 if(write_endfile(asfd, *bytes, checksum))
     126             :                                         goto end;
     127           2 :                                 ret=0;
     128           2 :                                 goto end;
     129             :                         case RS_BLOCKED:
     130             :                         case RS_RUNNING:
     131             :                                 // FIX ME: get it to read stuff here too.
     132             :                                 // (errors, for example)
     133           4 :                                 if(asfd->as->write(asfd->as))
     134             :                                         goto end;
     135           4 :                                 continue;
     136             :                         default:
     137           0 :                                 logp("error in rs_async for delta: %d\n",
     138             :                                         result);
     139           0 :                                 goto end;
     140             :                 }
     141             :         }
     142             : end:
     143           2 :         rs_filebuf_free(&infb);
     144           2 :         rs_filebuf_free(&outfb);
     145           2 :         if(job) rs_job_free(job);
     146           2 :         if(sumset) rs_free_sumset(sumset);
     147           2 :         return ret;
     148             : }
     149             : 
     150           6 : static enum send_e send_whole_file_w(struct asfd *asfd,
     151             :         struct sbuf *sb, const char *datapth,
     152             :         int quick_read, uint64_t *bytes, const char *encpassword,
     153             :         struct cntr *cntr, int compression, struct BFILE *bfd,
     154             :         const char *extrameta, size_t elen)
     155             : {
     156           6 :         if((compression || encpassword) && sb->path.cmd!=CMD_EFS_FILE)
     157             :         {
     158           0 :                 int key_deriv=sb->encryption;
     159           0 :                 return send_whole_file_gzl(asfd, datapth, quick_read, bytes,
     160             :                   encpassword, cntr, compression, bfd, extrameta, elen,
     161             :                   key_deriv, sb->salt);
     162             :         }
     163             :         else
     164           6 :                 return send_whole_filel(asfd,
     165             : #ifdef HAVE_WIN32
     166             :                   sb->path.cmd,
     167             : #endif
     168             :                   datapth, quick_read, bytes,
     169             :                   cntr, bfd, extrameta, elen);
     170             : }
     171             : 
     172           0 : static int forget_file(struct asfd *asfd, struct sbuf *sb, struct conf **confs)
     173             : {
     174             :         // Tell the server to forget about this
     175             :         // file, otherwise it might get stuck
     176             :         // on a select waiting for it to arrive.
     177           0 :         if(asfd->write_str(asfd, CMD_INTERRUPT, sb->path.buf))
     178             :                 return 0;
     179             : 
     180           0 :         if(sb->path.cmd==CMD_FILE && sb->datapth.buf)
     181             :         {
     182           0 :                 rs_signature_t *sumset=NULL;
     183             :                 // The server will be sending us a signature.
     184             :                 // Munch it up then carry on.
     185           0 :                 if(load_signature(asfd, &sumset, get_cntr(confs))) return -1;
     186           0 :                 else rs_free_sumset(sumset);
     187             :         }
     188             :         return 0;
     189             : }
     190             : 
     191           8 : static int size_checks(struct asfd *asfd, struct sbuf *sb, struct conf **confs)
     192             : {
     193          16 :         if(sb->path.cmd!=CMD_FILE
     194           8 :           && sb->path.cmd!=CMD_ENC_FILE
     195           0 :           && sb->path.cmd!=CMD_EFS_FILE)
     196             :                 return 0;
     197           8 :         if(get_uint64_t(confs[OPT_MIN_FILE_SIZE])
     198           0 :           && (uint64_t)sb->statp.st_size<get_uint64_t(confs[OPT_MIN_FILE_SIZE]))
     199             :         {
     200           0 :                 logw(asfd, get_cntr(confs), "File size decreased below min_file_size after initial scan: %s\n", iobuf_to_printable(&sb->path));
     201           0 :                 return -1;
     202             :         }
     203           8 :         if(get_uint64_t(confs[OPT_MAX_FILE_SIZE])
     204           0 :           && (uint64_t)sb->statp.st_size>get_uint64_t(confs[OPT_MAX_FILE_SIZE]))
     205             :         {
     206           0 :                 logw(asfd, get_cntr(confs), "File size increased above max_file_size after initial scan: %s\n", iobuf_to_printable(&sb->path));
     207           0 :                 return -1;
     208             :         }
     209             :         return 0;
     210             : }
     211             : 
     212           8 : static int deal_with_data(struct asfd *asfd, struct sbuf *sb,
     213             :         struct BFILE *bfd, struct conf **confs)
     214             : {
     215           8 :         int ret=-1;
     216           8 :         int forget=0;
     217           8 :         size_t elen=0;
     218           8 :         char *extrameta=NULL;
     219           8 :         uint64_t bytes=0;
     220           8 :         int conf_compression=get_int(confs[OPT_COMPRESSION]);
     221           8 :         struct cntr *cntr=get_cntr(confs);
     222           8 :         const char *enc_password=get_string(confs[OPT_ENCRYPTION_PASSWORD]);
     223             : 
     224           8 :         sb->compression=conf_compression;
     225           8 :         if(enc_password)
     226             :         {
     227           0 :                 sb->encryption=ENCRYPTION_KEY_DERIVED_AES_CBC_256;
     228           0 :                 if(!RAND_bytes((uint8_t *)&sb->salt, 8))
     229             :                 {
     230           0 :                         logp("RAND_bytes() failed\n");
     231           0 :                         return -1;
     232             :                 }
     233             :         }
     234             : 
     235           8 :         iobuf_copy(&sb->path, asfd->rbuf);
     236           8 :         iobuf_init(asfd->rbuf);
     237             : 
     238             : #ifdef HAVE_WIN32
     239             :         sb->use_winapi=get_use_winapi(
     240             :                 get_string(confs[OPT_REMOTE_DRIVES]),
     241             :                 sb->path.buf[0]
     242             :         );
     243             :         if(win32_lstat(sb->path.buf, &sb->statp, &sb->winattr))
     244             : #else
     245          16 :         if(lstat(sb->path.buf, &sb->statp))
     246             : #endif
     247             :         {
     248           0 :                 logw(asfd, cntr, "Path has vanished: %s\n",
     249             :                         iobuf_to_printable(&sb->path));
     250           0 :                 forget++;
     251           0 :                 goto end;
     252             :         }
     253             : 
     254           8 :         if(size_checks(asfd, sb, confs))
     255             :         {
     256             :                 forget++;
     257             :                 goto end;
     258             :         }
     259             : 
     260           8 :         sb->compression=in_exclude_comp(get_strlist(confs[OPT_EXCOM]),
     261           8 :                 sb->path.buf, conf_compression);
     262           8 :         if(attribs_encode(sb)) goto error;
     263             : 
     264          16 :         if(sb->path.cmd!=CMD_METADATA
     265           8 :           && sb->path.cmd!=CMD_ENC_METADATA)
     266             :         {
     267          32 :                 if(bfd->open_for_send(
     268             :                         bfd,
     269             :                         asfd,
     270           8 :                         sb->path.buf,
     271           8 :                         sb->use_winapi,
     272           8 :                         sb->winattr,
     273             :                         get_int(confs[OPT_ATIME]),
     274             :                         cntr
     275             :                 )) {
     276             :                         forget++;
     277             :                         goto end;
     278             :                 }
     279             :         }
     280             : 
     281          16 :         if(sb->path.cmd==CMD_METADATA
     282             :           || sb->path.cmd==CMD_ENC_METADATA
     283           8 :           || sb->path.cmd==CMD_VSS
     284           8 :           || sb->path.cmd==CMD_ENC_VSS
     285             : #ifdef HAVE_WIN32
     286             :           || get_int(confs[OPT_STRIP_VSS])
     287             : #endif
     288             :           )
     289             :         {
     290           0 :                 if(get_extrameta(asfd,
     291             : #ifdef HAVE_WIN32
     292             :                         bfd,
     293             : #endif
     294           0 :                         sb->path.buf,
     295           0 :                         S_ISDIR(sb->statp.st_mode),
     296             :                         &extrameta, &elen, cntr))
     297             :                 {
     298           0 :                         logw(asfd, cntr,
     299             :                                 "Meta data error for %s\n",
     300             :                                 iobuf_to_printable(&sb->path));
     301           0 :                         forget++;
     302           0 :                         goto end;
     303             :                 }
     304           0 :                 if(extrameta)
     305             :                 {
     306             : #ifdef HAVE_WIN32
     307             :                         if(get_int(confs[OPT_STRIP_VSS]))
     308             :                         {
     309             :                                 free_w(&extrameta);
     310             :                                 elen=0;
     311             :                         }
     312             : #endif
     313             :                 }
     314             :                 else
     315             :                 {
     316           0 :                         logw(asfd, cntr,
     317             :                                 "No meta data after all: %s\n",
     318             :                                 iobuf_to_printable(&sb->path));
     319           0 :                         forget++;
     320           0 :                         goto end;
     321             :                 }
     322             :         }
     323             : 
     324           8 :         if(sb->path.cmd==CMD_FILE
     325           4 :           && sb->datapth.buf)
     326           2 :         {
     327           2 :                 uint64_t sentbytes=0;
     328             :                 // Need to do sig/delta stuff.
     329           2 :                 if(asfd->write(asfd, &(sb->datapth))
     330           2 :                   || asfd->write(asfd, &sb->attr)
     331           2 :                   || asfd->write(asfd, &sb->path)
     332           2 :                   || load_signature_and_send_delta(asfd, bfd,
     333             :                         &bytes, &sentbytes, cntr))
     334             :                 {
     335           0 :                         logp("error in sig/delta for %s (%s)\n",
     336             :                                 iobuf_to_printable(&sb->path),
     337             :                                 iobuf_to_printable(&sb->datapth));
     338           0 :                         forget++;
     339           0 :                         goto end;
     340             :                 }
     341           2 :                 cntr_add(cntr, CMD_FILE_CHANGED, 1);
     342             :         }
     343             :         else
     344             :         {
     345             :                 //logp("need to send whole file: %s\n", sb.path);
     346             :                 // send the whole file.
     347             : 
     348           6 :                 if(asfd->write(asfd, &sb->attr)
     349           6 :                   || asfd->write(asfd, &sb->path))
     350             :                         goto end;
     351             : 
     352           6 :                 switch(send_whole_file_w(asfd, sb, NULL, 0, &bytes,
     353             :                         enc_password,
     354             :                         cntr, sb->compression,
     355             :                         bfd, extrameta, elen))
     356             :                 {
     357             :                         case SEND_OK:
     358             :                                 break;
     359             :                         case SEND_ERROR:
     360           0 :                                 forget++;
     361           0 :                                 break;
     362             :                         case SEND_FATAL:
     363             :                         default:
     364             :                                 goto error;
     365             :                 }
     366           6 :                 cntr_add(cntr, sb->path.cmd, 1);
     367             :         }
     368           8 :         cntr_add_bytes(cntr, bytes);
     369             : 
     370             : end:
     371           8 :         ret=0;
     372           8 :         if(forget && forget_file(asfd, sb, confs))
     373           0 :                 ret=-1;
     374             : error:
     375             : #ifdef HAVE_WIN32
     376             :         // If using Windows do not close bfd - it needs
     377             :         // to stay open to read VSS/file data/VSS.
     378             :         // It will get closed either when given a
     379             :         // different file path, or when this function
     380             :         // exits.
     381             : #else
     382           8 :         bfd->close(bfd, asfd);
     383             : #endif
     384           8 :         sbuf_free_content(sb);
     385           8 :         free_w(&extrameta);
     386           8 :         return ret;
     387             : }
     388             : 
     389          19 : static int parse_rbuf(struct asfd *asfd, struct sbuf *sb,
     390             :         struct BFILE *bfd, struct conf **confs)
     391             : {
     392             :         static struct iobuf *rbuf;
     393          19 :         rbuf=asfd->rbuf;
     394          19 :         if(rbuf->cmd==CMD_DATAPTH)
     395             :         {
     396           2 :                 iobuf_move(&(sb->datapth), rbuf);
     397             :         }
     398          17 :         else if(rbuf->cmd==CMD_ATTRIBS)
     399             :         {
     400             :                 // Ignore the stat data - we will fill it
     401             :                 // in again. Some time may have passed by now,
     402             :                 // and it is best to make it as fresh as
     403             :                 // possible.
     404             :         }
     405           9 :         else if(iobuf_is_filedata(rbuf)
     406           1 :           || iobuf_is_vssdata(rbuf))
     407             :         {
     408           8 :                 if(deal_with_data(asfd, sb, bfd, confs))
     409             :                         return -1;
     410             :         }
     411           2 :         else if(rbuf->cmd==CMD_MESSAGE
     412           1 :           || rbuf->cmd==CMD_WARNING)
     413             :         {
     414           1 :                 struct cntr *cntr=NULL;
     415           1 :                 if(confs) cntr=get_cntr(confs);
     416           1 :                 log_recvd(rbuf, cntr, 0);
     417             :         }
     418             :         else
     419             :         {
     420           0 :                 iobuf_log_unexpected(rbuf, __func__);
     421           0 :                 return -1;
     422             :         }
     423             :         return 0;
     424             : }
     425             : 
     426           6 : static int do_backup_phase2_client(struct asfd *asfd,
     427             :         struct conf **confs, int resume)
     428             : {
     429           6 :         int ret=-1;
     430             :         // For efficiency, open Windows files for the VSS data, and do not
     431             :         // close them until another time around the loop, when the actual
     432             :         // data is read.
     433           6 :         struct BFILE *bfd=NULL;
     434           6 :         struct sbuf *sb=NULL;
     435           6 :         struct iobuf *rbuf=NULL;
     436           6 :         struct cntr *cntr=NULL;
     437           6 :         if(confs) cntr=get_cntr(confs);
     438             : 
     439           6 :         if(!asfd)
     440             :         {
     441           1 :                 logp("%s() called without asfd!\n", __func__);
     442           1 :                 goto end;
     443             :         }
     444           5 :         rbuf=asfd->rbuf;
     445             : 
     446           5 :         if(!(bfd=bfile_alloc())
     447           5 :           || !(sb=sbuf_alloc()))
     448             :                 goto end;
     449           5 :         bfile_init(bfd, 0, 0, cntr);
     450             : 
     451           5 :         if(!resume)
     452             :         {
     453             :                 // Only do this bit if the server did not tell us to resume.
     454           5 :                 if(asfd->write_str(asfd, CMD_GEN, "backupphase2")
     455           5 :                   || asfd_read_expect(asfd, CMD_GEN, "ok"))
     456             :                         goto end;
     457             :         }
     458             :         else
     459             :         {
     460             :                 // On resume, the server might update the client with cntr.
     461           0 :                 if(cntr_recv(asfd, confs))
     462             :                         goto end;
     463             :         }
     464             : 
     465             :         while(1)
     466             :         {
     467          24 :                 iobuf_free_content(rbuf);
     468          24 :                 if(asfd->read(asfd)) goto end;
     469          23 :                 else if(!rbuf->buf) continue;
     470             : 
     471          23 :                 if(rbuf->cmd==CMD_GEN && !strcmp(rbuf->buf, "backupphase2end"))
     472             :                 {
     473           4 :                         if(asfd->write_str(asfd, CMD_GEN, "okbackupphase2end"))
     474             :                                 goto end;
     475           4 :                         ret=0;
     476           4 :                         break;
     477             :                 }
     478             : 
     479          19 :                 if(parse_rbuf(asfd, sb, bfd, confs))
     480             :                         goto end;
     481             :         }
     482             : 
     483             : end:
     484             :         // It is possible for a bfd to still be open.
     485           6 :         if(bfd) bfd->close(bfd, asfd);
     486           6 :         bfile_free(&bfd);
     487           6 :         iobuf_free_content(rbuf);
     488           6 :         sbuf_free(&sb);
     489           6 :         return ret;
     490             : }
     491             : 
     492           6 : int backup_phase2_client(struct asfd *asfd,
     493             :         struct conf **confs, int resume)
     494             : {
     495           6 :         int ret=0;
     496           6 :         struct cntr *cntr=NULL;
     497           6 :         if(confs) cntr=get_cntr(confs);
     498             : 
     499           6 :         logp("Phase 2 begin (send backup data)\n");
     500           6 :         logfmt("\n");
     501             : 
     502           6 :         ret=do_backup_phase2_client(asfd, confs, resume);
     503             : 
     504           6 :         cntr_print_end(cntr);
     505           6 :         cntr_set_bytes(cntr, asfd);
     506           6 :         cntr_print(cntr, ACTION_BACKUP);
     507             : 
     508           6 :         if(ret) logp("Error in phase 2\n");
     509           6 :         logp("Phase 2 end (send file data)\n");
     510             : 
     511           6 :         return ret;
     512             : }

Generated by: LCOV version 1.13