LCOV - code coverage report
Current view: top level - src/server/protocol1 - backup_phase4.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 115 335 34.3 %
Date: 2016-07-02 Functions: 5 12 41.7 %

          Line data    Source code
       1             : #include "../../burp.h"
       2             : #include "../../alloc.h"
       3             : #include "../../asfd.h"
       4             : #include "../../async.h"
       5             : #include "../../cmd.h"
       6             : #include "../../cntr.h"
       7             : #include "../../conf.h"
       8             : #include "../../fsops.h"
       9             : #include "../../fzp.h"
      10             : #include "../../handy.h"
      11             : #include "../../log.h"
      12             : #include "../../prepend.h"
      13             : #include "../../sbuf.h"
      14             : #include "../../strlist.h"
      15             : #include "../child.h"
      16             : #include "../compress.h"
      17             : #include "../timestamp.h"
      18             : #include "blocklen.h"
      19             : #include "deleteme.h"
      20             : #include "fdirs.h"
      21             : #include "link.h"
      22             : #include "zlibio.h"
      23             : 
      24             : #include <librsync.h>
      25             : 
      26             : // Also used by restore.c.
      27             : // FIX THIS: This stuff is very similar to make_rev_delta, can maybe share
      28             : // some code.
      29           0 : int do_patch(struct asfd *asfd, const char *dst, const char *del,
      30             :         const char *upd, bool gzupd, int compression)
      31             : {
      32           0 :         struct fzp *dstp=NULL;
      33           0 :         struct fzp *delfzp=NULL;
      34           0 :         struct fzp *upfzp=NULL;
      35           0 :         rs_result result=RS_IO_ERROR;
      36             : 
      37           0 :         if(!(dstp=fzp_open(dst, "rb"))) goto end;
      38             : 
      39           0 :         if(!(delfzp=fzp_gzopen(del, "rb")))
      40             :                 goto end;
      41             : 
      42           0 :         if(gzupd)
      43           0 :                 upfzp=fzp_gzopen(upd, comp_level(compression));
      44             :         else
      45           0 :                 upfzp=fzp_open(upd, "wb");
      46             : 
      47           0 :         if(!upfzp) goto end;
      48             : 
      49           0 :         result=rs_patch_gzfile(dstp, delfzp, upfzp);
      50             : end:
      51           0 :         fzp_close(&dstp);
      52           0 :         fzp_close(&delfzp);
      53           0 :         if(fzp_close(&upfzp))
      54             :         {
      55           0 :                 logp("error closing %s in %s\n", upd, __func__);
      56           0 :                 result=RS_IO_ERROR;
      57             :         }
      58           0 :         return result;
      59             : }
      60             : 
      61             : // Help librsync-1.0.0
      62             : #ifndef RS_DEFAULT_STRONG_LEN
      63             : #define RS_DEFAULT_STRONG_LEN   8
      64             : #endif
      65             : 
      66           0 : static int make_rev_sig(const char *dst, const char *sig, const char *endfile,
      67             :         int compression, struct conf **confs)
      68             : {
      69           0 :         int ret=-1;
      70           0 :         struct fzp *dstfzp=NULL;
      71           0 :         struct fzp *sigp=NULL;
      72             : //logp("make rev sig: %s %s\n", dst, sig);
      73             : 
      74           0 :         if(dpth_protocol1_is_compressed(compression, dst))
      75           0 :                 dstfzp=fzp_gzopen(dst, "rb");
      76             :         else
      77           0 :                 dstfzp=fzp_open(dst, "rb");
      78             : 
      79           0 :         if(!dstfzp
      80           0 :           || !(sigp=fzp_open(sig, "wb"))
      81           0 :           || rs_sig_gzfile(dstfzp, sigp,
      82             :                 get_librsync_block_len(endfile),
      83           0 :                 RS_DEFAULT_STRONG_LEN, confs)!=RS_DONE)
      84             :                         goto end;
      85           0 :         ret=0;
      86             : end:
      87             : //logp("end of make rev sig\n");
      88           0 :         fzp_close(&dstfzp);
      89           0 :         if(fzp_close(&sigp))
      90             :         {
      91           0 :                 logp("error closing %s in %s\n", sig, __func__);
      92           0 :                 return -1;
      93             :         }
      94             :         return ret;
      95             : }
      96             : 
      97           0 : static int make_rev_delta(const char *src, const char *sig, const char *del,
      98             :         int compression, struct conf **cconfs)
      99             : {
     100           0 :         int ret=-1;
     101           0 :         struct fzp *srcfzp=NULL;
     102           0 :         struct fzp *delfzp=NULL;
     103           0 :         struct fzp *sigp=NULL;
     104           0 :         rs_signature_t *sumset=NULL;
     105             : 
     106             : //logp("make rev delta: %s %s %s\n", src, sig, del);
     107           0 :         if(!(sigp=fzp_open(sig, "rb"))) goto end;
     108             : 
     109           0 :         if(rs_loadsig_fzp(sigp, &sumset, NULL)!=RS_DONE
     110           0 :           || rs_build_hash_table(sumset)!=RS_DONE)
     111             :                 goto end;
     112             : 
     113             : //logp("make rev deltb: %s %s %s\n", src, sig, del);
     114             : 
     115           0 :         if(dpth_protocol1_is_compressed(compression, src))
     116           0 :                 srcfzp=fzp_gzopen(src, "rb");
     117             :         else
     118           0 :                 srcfzp=fzp_open(src, "rb");
     119             : 
     120           0 :         if(!srcfzp) goto end;
     121             : 
     122           0 :         if(get_int(cconfs[OPT_COMPRESSION]))
     123             :                 delfzp=fzp_gzopen(del,
     124           0 :                         comp_level(get_int(cconfs[OPT_COMPRESSION])));
     125             :         else
     126           0 :                 delfzp=fzp_open(del, "wb");
     127           0 :         if(!delfzp) goto end;
     128             : 
     129           0 :         if(rs_delta_gzfile(sumset, srcfzp, delfzp)!=RS_DONE)
     130             :                 goto end;
     131           0 :         ret=0;
     132             : end:
     133           0 :         if(sumset) rs_free_sumset(sumset);
     134           0 :         fzp_close(&srcfzp);
     135           0 :         fzp_close(&sigp);
     136           0 :         if(fzp_close(&delfzp))
     137             :         {
     138           0 :                 logp("error closing delfzp %s in %s\n", del, __func__);
     139           0 :                 ret=-1;
     140             :         }
     141           0 :         return ret;
     142             : }
     143             : 
     144           0 : static int gen_rev_delta(const char *sigpath, const char *deltadir,
     145             :         const char *oldpath, const char *finpath, const char *path,
     146             :         struct sbuf *sb, struct conf **cconfs)
     147             : {
     148           0 :         int ret=-1;
     149           0 :         char *delpath=NULL;
     150           0 :         if(!(delpath=prepend_s(deltadir, path)))
     151             :         {
     152           0 :                 log_out_of_memory(__func__);
     153             :                 goto end;
     154             :         }
     155             :         //logp("Generating reverse delta...\n");
     156             : /*
     157             :         logp("delpath: %s\n", delpath);
     158             :         logp("finpath: %s\n", finpath);
     159             :         logp("sigpath: %s\n", sigpath);
     160             :         logp("oldpath: %s\n", oldpath);
     161             : */
     162           0 :         if(mkpath(&delpath, deltadir))
     163             :         {
     164           0 :                 logp("could not mkpaths for: %s\n", delpath);
     165             :                 goto end;
     166             :         }
     167           0 :         else if(make_rev_sig(finpath, sigpath,
     168           0 :                 sb->endfile.buf, sb->compression, cconfs))
     169             :         {
     170           0 :                 logp("could not make signature from: %s\n", finpath);
     171             :                 goto end;
     172             :         }
     173           0 :         else if(make_rev_delta(oldpath, sigpath,
     174           0 :                 delpath, sb->compression, cconfs))
     175             :         {
     176           0 :                 logp("could not make delta from: %s\n", oldpath);
     177             :                 goto end;
     178             :         }
     179           0 :         else unlink(sigpath);   
     180             : 
     181           0 :         ret=0;
     182             : end:
     183           0 :         free_w(&delpath);
     184           0 :         return ret;
     185             : }
     186             : 
     187           0 : static int inflate_oldfile(const char *opath, const char *infpath,
     188             :         struct stat *statp, struct cntr *cntr)
     189             : {
     190           0 :         int ret=0;
     191             : 
     192           0 :         if(!statp->st_size)
     193             :         {
     194           0 :                 struct fzp *dest=NULL;
     195             :                 // Empty file - cannot inflate.
     196             :                 // just close the destination and we have duplicated a
     197             :                 // zero length file.
     198           0 :                 if(!(dest=fzp_open(infpath, "wb"))) goto end;
     199           0 :                 logp("asked to inflate zero length file: %s\n", opath);
     200           0 :                 if(fzp_close(&dest))
     201           0 :                         logp("error closing %s in %s\n", infpath, __func__);
     202             :         }
     203           0 :         else if(zlib_inflate(NULL, opath, infpath, cntr))
     204             :         {
     205           0 :                 logp("zlib_inflate returned error\n");
     206           0 :                 ret=-1;
     207             :         }
     208             : end:
     209           0 :         return ret;
     210             : }
     211             : 
     212           0 : static int inflate_or_link_oldfile(const char *oldpath, const char *infpath,
     213             :         int compression, struct conf **cconfs)
     214             : {
     215             :         struct stat statp;
     216             : 
     217           0 :         if(lstat(oldpath, &statp))
     218             :         {
     219           0 :                 logp("could not lstat %s\n", oldpath);
     220           0 :                 return -1;
     221             :         }
     222             : 
     223           0 :         if(dpth_protocol1_is_compressed(compression, oldpath))
     224             :                 return inflate_oldfile(oldpath, infpath, &statp,
     225           0 :                         get_cntr(cconfs));
     226             : 
     227             :         // If it was not a compressed file, just hard link it.
     228             :         // It is possible that infpath already exists, if the server
     229             :         // was interrupted on a previous run just after this point.
     230             :         return do_link(oldpath, infpath, &statp, cconfs,
     231           0 :                 1 /* allow overwrite of infpath */);
     232             : }
     233             : 
     234           0 : static int forward_patch_and_reverse_diff(
     235             :         struct fdirs *fdirs,
     236             :         struct fzp **delfp,
     237             :         const char *deltabdir,
     238             :         const char *deltafdir,
     239             :         const char *deltafpath,
     240             :         const char *sigpath,
     241             :         const char *oldpath,
     242             :         const char *newpath,
     243             :         const char *datapth,
     244             :         const char *finpath,
     245             :         int hardlinked_current,
     246             :         struct sbuf *sb,
     247             :         struct conf **cconfs
     248             : )
     249             : {
     250             :         int lrs;
     251           0 :         int ret=-1;
     252           0 :         char *infpath=NULL;
     253             : 
     254             :         // Got a forward patch to do.
     255             :         // First, need to gunzip the old file, otherwise the librsync patch
     256             :         // will take forever, because it will be doing seeks all over the
     257             :         // place, and gzseeks are slow.
     258           0 :         if(!(infpath=prepend_s(deltafdir, "inflate")))
     259             :         {
     260           0 :                 log_out_of_memory(__func__);
     261             :                 goto end;
     262             :         }
     263             : 
     264             :         //logp("Fixing up: %s\n", datapth);
     265           0 :         if(inflate_or_link_oldfile(oldpath, infpath, sb->compression, cconfs))
     266             :         {
     267           0 :                 logp("error when inflating old file: %s\n", oldpath);
     268             :                 goto end;
     269             :         }
     270             : 
     271           0 :         if((lrs=do_patch(NULL, infpath, deltafpath, newpath,
     272           0 :                 sb->compression, sb->compression /* from manifest */)))
     273             :         {
     274             :                 logp("WARNING: librsync error when patching %s: %d\n",
     275           0 :                         oldpath, lrs);
     276           0 :                 cntr_add(get_cntr(cconfs), CMD_WARNING, 1);
     277             :                 // Try to carry on with the rest of the backup regardless.
     278             :                 // Remove anything that got written.
     279           0 :                 unlink(newpath);
     280             : 
     281             :                 // First, note that we want to remove this entry from
     282             :                 // the manifest.
     283           0 :                 if(!*delfp
     284           0 :                   && !(*delfp=fzp_open(fdirs->deletionsfile, "ab")))
     285             :                 {
     286             :                         // Could not mark this file as deleted. Fatal.
     287             :                         goto end;
     288             :                 }
     289           0 :                 if(sbuf_to_manifest(sb, *delfp))
     290             :                         goto end;
     291           0 :                 if(fzp_flush(*delfp))
     292             :                 {
     293             :                         logp("error fflushing deletions file in %s: %s\n",
     294           0 :                                 __func__, strerror(errno));
     295             :                         goto end;
     296             :                 }
     297             :                 ret=0;
     298             :                 goto end;
     299             :         }
     300             : 
     301             :         // Need to generate a reverse diff, unless we are keeping a hardlinked
     302             :         // archive.
     303           0 :         if(!hardlinked_current)
     304             :         {
     305           0 :                 if(gen_rev_delta(sigpath, deltabdir,
     306           0 :                         oldpath, newpath, datapth, sb, cconfs))
     307             :                                 goto end;
     308             :         }
     309             : 
     310             :         // Power interruptions should be recoverable. If it happens before this
     311             :         // point, the data jiggle for this file has to be done again.
     312             :         // Once finpath is in place, no more jiggle is required.
     313             : 
     314             :         // Use the fresh new file.
     315             :         // Rename race condition is of no consequence, because finpath will
     316             :         // just get recreated automatically.
     317           0 :         if(do_rename(newpath, finpath))
     318             :                 goto end;
     319             : 
     320             :         // Remove the forward delta, as it is no longer needed. There is a
     321             :         // reverse diff and the finished finished file is in place.
     322             :         //logp("Deleting delta.forward...\n");
     323           0 :         unlink(deltafpath);
     324             : 
     325             :         // Remove the old file. If a power cut happens just before this, the
     326             :         // old file will hang around forever.
     327             :         // FIX THIS: maybe put in something to detect this.
     328             :         // ie, both a reverse delta and the old file exist.
     329           0 :         if(!hardlinked_current)
     330             :         {
     331             :                 //logp("Deleting oldpath...\n");
     332           0 :                 unlink(oldpath);
     333             :         }
     334             : 
     335             :         ret=0;
     336             : end:
     337           0 :         if(infpath)
     338             :         {
     339           0 :                 unlink(infpath);
     340           0 :                 free_w(&infpath);
     341             :         }
     342           0 :         return ret;
     343             : }
     344             : 
     345          91 : static int jiggle(struct sdirs *sdirs, struct fdirs *fdirs, struct sbuf *sb,
     346             :         int hardlinked_current, const char *deltabdir, const char *deltafdir,
     347             :         const char *sigpath, struct fzp **delfp, struct conf **cconfs)
     348             : {
     349          91 :         int ret=-1;
     350             :         struct stat statp;
     351          91 :         char *oldpath=NULL;
     352          91 :         char *newpath=NULL;
     353          91 :         char *finpath=NULL;
     354          91 :         char *deltafpath=NULL;
     355          91 :         const char *datapth=sb->protocol1->datapth.buf;
     356             : 
     357             :         // If the previous backup was a hardlinked_archive, there will not be
     358             :         // a currentdup directory - just directly use the file in the previous
     359             :         // backup.
     360          91 :         if(!(oldpath=prepend_s(hardlinked_current?
     361          91 :                 sdirs->currentdata:fdirs->currentdupdata, datapth))
     362          91 :           || !(newpath=prepend_s(fdirs->datadirtmp, datapth))
     363          91 :           || !(finpath=prepend_s(fdirs->datadir, datapth))
     364         182 :           || !(deltafpath=prepend_s(deltafdir, datapth)))
     365             :                 goto end;
     366             : 
     367         182 :         if(!lstat(finpath, &statp) && S_ISREG(statp.st_mode))
     368             :         {
     369             :                 // Looks like an interrupted jiggle did this file already.
     370             :                 static int donemsg=0;
     371           6 :                 if(!unlink(deltafpath))
     372             :                         logp("deleted unneeded forward delta: %s\n",
     373           0 :                                 deltafpath);
     374           6 :                 if(!donemsg)
     375             :                 {
     376           1 :                         logp("skipping already present file: %s\n", finpath);
     377           1 :                         logp("to save log space, skips of other already present files will not be logged\n");
     378           1 :                         donemsg++;
     379             :                 }
     380             :                 ret=0;
     381             :                 goto end;
     382             :         }
     383             : 
     384          85 :         if(mkpath(&finpath, fdirs->datadir))
     385             :         {
     386           0 :                 logp("could not create path for: %s\n", finpath);
     387             :                 goto end;
     388             :         }
     389             : 
     390         170 :         if(!lstat(deltafpath, &statp) && S_ISREG(statp.st_mode))
     391             :         {
     392           0 :                 if(mkpath(&newpath, fdirs->datadirtmp))
     393             :                 {
     394           0 :                         logp("could not create path for: %s\n", newpath);
     395             :                         goto end;
     396             :                 }
     397             :                 ret=forward_patch_and_reverse_diff(
     398             :                         fdirs,
     399             :                         delfp,
     400             :                         deltabdir,
     401             :                         deltafdir,
     402             :                         deltafpath,
     403             :                         sigpath,
     404             :                         oldpath,
     405             :                         newpath,
     406             :                         datapth,
     407             :                         finpath,
     408             :                         hardlinked_current,
     409             :                         sb,
     410             :                         cconfs
     411           0 :                 );
     412             :                 goto end;
     413             :         }
     414             : 
     415         170 :         if(!lstat(newpath, &statp) && S_ISREG(statp.st_mode))
     416             :         {
     417             :                 // Use the fresh new file.
     418             :                 // This needs to happen after checking
     419             :                 // for the forward delta, because the
     420             :                 // patching stuff writes to newpath.
     421             : 
     422             :                 // Rename race condition is of no consequence, because finpath
     423             :                 // will just get recreated automatically.
     424             : 
     425             :                 //logp("Using newly received file\n");
     426          85 :                 ret=do_rename(newpath, finpath);
     427             :                 goto end;
     428             :         }
     429             : 
     430           0 :         if(!lstat(oldpath, &statp) && S_ISREG(statp.st_mode))
     431             :         {
     432             :                 // Use the old unchanged file.
     433             :                 // Hard link it first.
     434             :                 //logp("Hard linking to old file: %s\n", datapth);
     435           0 :                 if(do_link(oldpath, finpath, &statp, cconfs,
     436           0 :                   0 /* do not overwrite finpath (should never need to) */))
     437             :                         goto end;
     438             :                 else
     439             :                 {
     440             :                         // If we are not keeping a hardlinked
     441             :                         // archive, delete the old link.
     442           0 :                         if(!hardlinked_current)
     443             :                         {
     444             :                                 //logp("Unlinking old file: %s\n", oldpath);
     445           0 :                                 unlink(oldpath);
     446             :                         }
     447             :                 }
     448             :                 ret=0;
     449             :                 goto end;
     450             :         }
     451             : 
     452           0 :         logp("could not find: %s\n", oldpath);
     453             : end:
     454          91 :         free_w(&oldpath);
     455          91 :         free_w(&newpath);
     456          91 :         free_w(&finpath);
     457          91 :         free_w(&deltafpath);
     458          91 :         return ret;
     459             : }
     460             : 
     461             : /* If OPT_HARDLINKED_ARCHIVE set, hardlink everything.
     462             :    If unset and there is more than one 'keep' value, periodically hardlink,
     463             :    based on the first 'keep' value. This is so that we have more choice
     464             :    of backups to delete than just the oldest.
     465             : */
     466           2 : static int need_hardlinked_archive(struct conf **cconfs, uint64_t bno)
     467             : {
     468           2 :         int kp=0;
     469           2 :         int ret=0;
     470           2 :         struct strlist *keep=get_strlist(cconfs[OPT_KEEP]);
     471           2 :         if(get_int(cconfs[OPT_HARDLINKED_ARCHIVE]))
     472             :         {
     473           0 :                 logp("New backup is a hardlinked_archive\n");
     474           0 :                 return 1;
     475             :         }
     476           2 :         if(!keep || !keep->next)
     477             :         {
     478           2 :                 logp("New backup is not a hardlinked_archive\n");
     479           2 :                 return 0;
     480             :         }
     481             : 
     482             :         // If they have specified more than one 'keep' value, need to
     483             :         // periodically hardlink, based on the first 'keep' value.
     484           0 :         kp=keep->flag;
     485             : 
     486             :         logp("First keep value: %d, backup: %" PRIu64 " (%" PRIu64 "-1=%" PRIu64 ")\n",
     487           0 :                         kp, bno, bno, bno-1);
     488             : 
     489           0 :         ret=(bno-1)%kp;
     490             :         logp("New backup is %sa hardlinked_archive (%" PRIu64 "%%%d=%d)\n",
     491           0 :                 ret?"not ":"", bno-1, kp, ret);
     492             : 
     493           0 :         return !ret;
     494             : }
     495             : 
     496           2 : static int maybe_delete_files_from_manifest(const char *manifesttmp,
     497             :         struct fdirs *fdirs, struct conf **cconfs)
     498             : {
     499           2 :         int ars=0;
     500           2 :         int ret=-1;
     501           2 :         int pcmp=0;
     502           2 :         struct fzp *dfp=NULL;
     503           2 :         struct fzp *nmzp=NULL;
     504           2 :         struct fzp *omzp=NULL;
     505           2 :         struct sbuf *db=NULL;
     506           2 :         struct sbuf *mb=NULL;
     507             :         struct stat statp;
     508             : 
     509           4 :         if(lstat(fdirs->deletionsfile, &statp)) // No deletions, no problem.
     510             :                 return 0;
     511           0 :         logp("Performing deletions on manifest\n");
     512             : 
     513           0 :         if(!(manifesttmp=get_tmp_filename(fdirs->manifest)))
     514             :                 goto end;
     515             : 
     516           0 :         if(!(dfp=fzp_open(fdirs->deletionsfile, "rb"))
     517           0 :           || !(omzp=fzp_gzopen(fdirs->manifest, "rb"))
     518           0 :           || !(nmzp=fzp_gzopen(manifesttmp,
     519           0 :                 comp_level(get_int(cconfs[OPT_COMPRESSION]))))
     520           0 :           || !(db=sbuf_alloc(PROTO_1))
     521           0 :           || !(mb=sbuf_alloc(PROTO_1)))
     522             :                 goto end;
     523             : 
     524           0 :         while(omzp || dfp)
     525             :         {
     526           0 :                 if(dfp && !db->path.buf
     527           0 :                   && (ars=sbuf_fill_from_file(db, dfp, NULL, NULL)))
     528             :                 {
     529           0 :                         if(ars<0) goto end;
     530             :                         // ars==1 means it ended ok.
     531           0 :                         fzp_close(&dfp);
     532             :                 }
     533           0 :                 if(omzp && !mb->path.buf
     534           0 :                   && (ars=sbuf_fill_from_file(mb, omzp, NULL, NULL)))
     535             :                 {
     536           0 :                         if(ars<0) goto end;
     537             :                         // ars==1 means it ended ok.
     538           0 :                         fzp_close(&omzp);
     539             :                 }
     540             : 
     541           0 :                 if(mb->path.buf && !db->path.buf)
     542             :                 {
     543           0 :                         if(sbuf_to_manifest(mb, nmzp)) goto end;
     544           0 :                         sbuf_free_content(mb);
     545             :                 }
     546           0 :                 else if(!mb->path.buf && db->path.buf)
     547             :                 {
     548           0 :                         sbuf_free_content(db);
     549             :                 }
     550           0 :                 else if(!mb->path.buf && !db->path.buf)
     551             :                 {
     552             :                         continue;
     553             :                 }
     554           0 :                 else if(!(pcmp=sbuf_pathcmp(mb, db)))
     555             :                 {
     556             :                         // They were the same - do not write.
     557           0 :                         sbuf_free_content(mb);
     558           0 :                         sbuf_free_content(db);
     559             :                 }
     560           0 :                 else if(pcmp<0)
     561             :                 {
     562             :                         // Behind in manifest. Write.
     563           0 :                         if(sbuf_to_manifest(mb, nmzp)) goto end;
     564           0 :                         sbuf_free_content(mb);
     565             :                 }
     566             :                 else
     567             :                 {
     568             :                         // Behind in deletions file. Do not write.
     569           0 :                         sbuf_free_content(db);
     570             :                 }
     571             :         }
     572             : 
     573             :         ret=0;
     574             : end:
     575           0 :         if(fzp_close(&nmzp))
     576             :         {
     577           0 :                 logp("error closing %s in %s\n", manifesttmp, __func__);
     578           0 :                 ret=-1;
     579             :         }
     580             :         
     581           0 :         fzp_close(&dfp);
     582           0 :         fzp_close(&omzp);
     583           0 :         sbuf_free(&db);
     584           0 :         sbuf_free(&mb);
     585           0 :         if(!ret)
     586             :         {
     587           0 :                 unlink(fdirs->deletionsfile);
     588             :                 // The rename race condition is not a problem here, as long
     589             :                 // as manifesttmp is the same path as that generated in the
     590             :                 // atomic data jiggle.
     591           0 :                 if(do_rename(manifesttmp, fdirs->manifest))
     592             :                         return -1;
     593             :         }
     594           0 :         if(manifesttmp) unlink(manifesttmp);
     595             :         return ret;
     596             : }
     597             : 
     598             : /* Need to make all the stuff that this does atomic so that existing backups
     599             :    never get broken, even if somebody turns the power off on the server. */
     600           2 : static int atomic_data_jiggle(struct sdirs *sdirs, struct fdirs *fdirs,
     601             :         int hardlinked_current, struct conf **cconfs)
     602             : {
     603           2 :         int ret=-1;
     604           2 :         char *datapth=NULL;
     605           2 :         char *tmpman=NULL;
     606             :         struct stat statp;
     607             : 
     608           2 :         char *deltabdir=NULL;
     609           2 :         char *deltafdir=NULL;
     610           2 :         char *sigpath=NULL;
     611           2 :         struct fzp *zp=NULL;
     612           2 :         struct sbuf *sb=NULL;
     613             : 
     614           2 :         struct fzp *delfp=NULL;
     615             : 
     616           2 :         logp("Doing the atomic data jiggle...\n");
     617             : 
     618           2 :         if(!(tmpman=get_tmp_filename(fdirs->manifest)))
     619             :                 goto error;
     620           4 :         if(lstat(fdirs->manifest, &statp))
     621             :         {
     622             :                 // Manifest does not exist - maybe the server was killed before
     623             :                 // it could be renamed.
     624           0 :                 logp("%s did not exist - trying %s\n", fdirs->manifest, tmpman);
     625             :                 // Rename race condition is of no consequence, because manifest
     626             :                 // already does not exist.
     627           0 :                 do_rename(tmpman, fdirs->manifest);
     628             :         }
     629           2 :         if(!(zp=fzp_gzopen(fdirs->manifest, "rb")))
     630             :                 goto error;
     631             : 
     632           4 :         if(!(deltabdir=prepend_s(fdirs->currentdup, "deltas.reverse"))
     633           2 :           || !(deltafdir=prepend_s(sdirs->finishing, "deltas.forward"))
     634           2 :           || !(sigpath=prepend_s(fdirs->currentdup, "sig.tmp"))
     635           4 :           || !(sb=sbuf_alloc(PROTO_1)))
     636             :         {
     637           0 :                 log_out_of_memory(__func__);
     638           0 :                 goto error;
     639             :         }
     640             : 
     641           2 :         mkdir(fdirs->datadir, 0777);
     642             : 
     643             :         while(1)
     644             :         {
     645         202 :                 switch(sbuf_fill_from_file(sb, zp, NULL, NULL))
     646             :                 {
     647             :                         case 0: break;
     648             :                         case 1: goto end;
     649             :                         default: goto error;
     650             :                 }
     651         200 :                 if(sb->protocol1->datapth.buf)
     652             :                 {
     653          91 :                         if(write_status(CNTR_STATUS_SHUFFLING,
     654          91 :                                 sb->protocol1->datapth.buf, get_cntr(cconfs))
     655         182 :                           || jiggle(sdirs, fdirs, sb, hardlinked_current,
     656             :                                 deltabdir, deltafdir,
     657          91 :                                 sigpath, &delfp, cconfs))
     658             :                                         goto error;
     659             :                 }
     660         200 :                 sbuf_free_content(sb);
     661             :         }
     662             : 
     663             : end:
     664           2 :         if(fzp_close(&delfp))
     665             :         {
     666             :                 logp("error closing %s in atomic_data_jiggle\n",
     667           0 :                         fdirs->deletionsfile);
     668           0 :                 goto error;
     669             :         }
     670             : 
     671           2 :         if(maybe_delete_files_from_manifest(tmpman, fdirs, cconfs))
     672             :                 goto error;
     673             : 
     674             :         // Remove the temporary data directory, we have probably removed
     675             :         // useful files from it.
     676           2 :         recursive_delete_dirs_only(deltafdir);
     677             : 
     678           2 :         ret=0;
     679             : error:
     680           2 :         fzp_close(&zp);
     681           2 :         fzp_close(&delfp);
     682           2 :         sbuf_free(&sb);
     683           2 :         free_w(&deltabdir);
     684           2 :         free_w(&deltafdir);
     685           2 :         free_w(&sigpath);
     686           2 :         free_w(&datapth);
     687           2 :         free_w(&tmpman);
     688         202 :         return ret;
     689             : }
     690             : 
     691           2 : int backup_phase4_server_protocol1(struct sdirs *sdirs, struct conf **cconfs)
     692             : {
     693           2 :         int ret=-1;
     694             :         struct stat statp;
     695           2 :         char realcurrent[256]="";
     696           2 :         uint64_t bno=0;
     697           2 :         int hardlinked_current=0;
     698           2 :         char tstmp[64]="";
     699           2 :         int previous_backup=0;
     700           2 :         struct fdirs *fdirs=NULL;
     701             : 
     702           2 :         readlink_w(sdirs->current, realcurrent, sizeof(realcurrent));
     703             : 
     704           4 :         if(!(fdirs=fdirs_alloc())
     705           2 :           || fdirs_init(fdirs, sdirs, realcurrent))
     706             :                 goto end;
     707             : 
     708           2 :         if(log_fzp_set(fdirs->logpath, cconfs))
     709             :                 goto end;
     710             : 
     711           2 :         logp("Begin phase4 (shuffle files)\n");
     712             : 
     713           2 :         if(write_status(CNTR_STATUS_SHUFFLING, NULL, get_cntr(cconfs)))
     714             :                 goto end;
     715             : 
     716           4 :         if(!lstat(sdirs->current, &statp)) // Had a previous backup.
     717             :         {
     718           0 :                 previous_backup++;
     719             : 
     720           0 :                 if(lstat(fdirs->hlinkedcurrent, &statp))
     721             :                 {
     722           0 :                         hardlinked_current=0;
     723           0 :                         logp("Previous backup is not a hardlinked_archive\n");
     724           0 :                         logp(" will generate reverse deltas\n");
     725             :                 }
     726             :                 else
     727             :                 {
     728           0 :                         hardlinked_current=1;
     729           0 :                         logp("Previous backup is a hardlinked_archive\n");
     730           0 :                         logp(" will not generate reverse deltas\n");
     731             :                 }
     732             : 
     733             :                 // If current was not a hardlinked_archive, need to duplicate
     734             :                 // it.
     735           0 :                 if(!hardlinked_current && lstat(fdirs->currentdup, &statp))
     736             :                 {
     737             :                         // Have not duplicated the current backup yet.
     738           0 :                         if(!lstat(fdirs->currentduptmp, &statp))
     739             :                         {
     740             :                                 logp("Removing previous directory: %s\n",
     741           0 :                                         fdirs->currentduptmp);
     742           0 :                                 if(recursive_delete(fdirs->currentduptmp))
     743             :                                 {
     744             :                                         logp("Could not delete %s\n",
     745           0 :                                                 fdirs->currentduptmp);
     746           0 :                                         goto end;
     747             :                                 }
     748             :                         }
     749           0 :                         logp("Duplicating current backup.\n");
     750           0 :                         if(recursive_hardlink(sdirs->current,
     751           0 :                                 fdirs->currentduptmp, cconfs)
     752             :                         // The rename race condition is of no consequence here
     753             :                         // because currentdup does not exist.
     754           0 :                           || do_rename(fdirs->currentduptmp, fdirs->currentdup))
     755             :                                 goto end;
     756             :                 }
     757             :         }
     758             : 
     759           2 :         if(timestamp_read(fdirs->timestamp, tstmp, sizeof(tstmp)))
     760             :         {
     761             :                 logp("could not read timestamp file: %s\n",
     762           0 :                         fdirs->timestamp);
     763           0 :                 goto end;
     764             :         }
     765             :         // Get the backup number.
     766           2 :         bno=strtoull(tstmp, NULL, 10);
     767             : 
     768             :         // Determine whether the new backup should be a hardlinked
     769             :         // archive or not, from the confs and the backup number...
     770           2 :         if(need_hardlinked_archive(cconfs, bno))
     771             :         {
     772             :                 // Create a file to indicate that the previous backup
     773             :                 // does not have others depending on it.
     774           0 :                 struct fzp *hfp=NULL;
     775           0 :                 if(!(hfp=fzp_open(fdirs->hlinked, "wb"))) goto end;
     776             : 
     777             :                 // Stick the next backup timestamp in it. It might
     778             :                 // be useful one day when wondering when the next
     779             :                 // backup, now deleted, was made.
     780           0 :                 fzp_printf(hfp, "%s\n", tstmp);
     781           0 :                 if(fzp_close(&hfp))
     782             :                 {
     783           0 :                         logp("error closing hardlinked indication\n");
     784           0 :                         goto end;
     785             :                 }
     786             :         }
     787             :         else
     788           2 :                 unlink(fdirs->hlinked);
     789             : 
     790           2 :         if(atomic_data_jiggle(sdirs, fdirs, hardlinked_current, cconfs))
     791             :         {
     792           0 :                 logp("could not finish up backup.\n");
     793           0 :                 goto end;
     794             :         }
     795             : 
     796           2 :         if(write_status(CNTR_STATUS_SHUFFLING,
     797           2 :                 "deleting temporary files", get_cntr(cconfs)))
     798             :                         goto end;
     799             : 
     800             :         // Remove the temporary data directory, we have now removed
     801             :         // everything useful from it.
     802           2 :         recursive_delete(fdirs->datadirtmp);
     803             : 
     804             :         // Clean up the currentdata directory - this is now the 'old'
     805             :         // currentdata directory. Any files that were deleted from
     806             :         // the client will be left in there, so call recursive_delete
     807             :         // with the option that makes it not delete files.
     808             :         // This will have the effect of getting rid of unnecessary
     809             :         // directories.
     810           2 :         recursive_delete_dirs_only(fdirs->currentdupdata);
     811             : 
     812             :         // Rename the old current to something that we know to delete.
     813           2 :         if(previous_backup && !hardlinked_current)
     814             :         {
     815           0 :                 if(deleteme_move(sdirs,
     816           0 :                         fdirs->fullrealcurrent, realcurrent, cconfs)
     817             :                 // I have tested that potential race conditions on the
     818             :                 // rename() are automatically recoverable here.
     819           0 :                   || do_rename(fdirs->currentdup, fdirs->fullrealcurrent))
     820             :                         goto end;
     821             :         }
     822             : 
     823           2 :         if(deleteme_maybe_delete(cconfs, sdirs))
     824             :                 goto end;
     825             : 
     826           2 :         logp("End phase4 (shuffle files)\n");
     827             : 
     828           2 :         ret=0;
     829             : end:
     830           2 :         fdirs_free(&fdirs);
     831           2 :         log_fzp_set(NULL, cconfs);
     832           2 :         return ret;
     833             : }

Generated by: LCOV version 1.10