static int make_rev_sig(const char *dst, const char *sig, const char *endfile, int compression, struct conf **confs) { int ret=-1; FILE *dstfp=NULL; gzFile dstzp=NULL; FILE *sigp=NULL; //logp("make rev sig: %s %s\n", dst, sig); if(dpth_protocol1_is_compressed(compression, dst)) dstzp=gzopen_file(dst, "rb"); else dstfp=open_file(dst, "rb"); if((!dstzp && !dstfp) || !(sigp=open_file(sig, "wb")) || rs_sig_gzfile(NULL, dstfp, dstzp, sigp, get_librsync_block_len(endfile), RS_DEFAULT_STRONG_LEN, NULL, get_cntr(confs[OPT_CNTR]))!=RS_DONE) goto end; ret=0; end: //logp("end of make rev sig\n"); gzclose_fp(&dstzp); close_fp(&dstfp); if(close_fp(&sigp)) { logp("error closing %s in %s\n", sig, __func__); return -1; } return ret; }
static int make_rev_sig(const char *dst, const char *sig, const char *endfile, int compression, struct conf **confs) { int ret=-1; struct fzp *dstfzp=NULL; struct fzp *sigp=NULL; //logp("make rev sig: %s %s\n", dst, sig); if(dpth_protocol1_is_compressed(compression, dst)) dstfzp=fzp_gzopen(dst, "rb"); else dstfzp=fzp_open(dst, "rb"); if(!dstfzp || !(sigp=fzp_open(sig, "wb")) || rs_sig_gzfile(dstfzp, sigp, get_librsync_block_len(endfile), RS_DEFAULT_STRONG_LEN, confs)!=RS_DONE) goto end; ret=0; end: //logp("end of make rev sig\n"); fzp_close(&dstfzp); if(fzp_close(&sigp)) { logp("error closing %s in %s\n", sig, __func__); return -1; } return ret; }
static int make_rev_delta(const char *src, const char *sig, const char *del, int compression, struct conf **cconfs) { int ret=-1; rs_result result; struct fzp *srcfzp=NULL; struct fzp *delfzp=NULL; struct fzp *sigp=NULL; rs_signature_t *sumset=NULL; //logp("make rev delta: %s %s %s\n", src, sig, del); if(!(sigp=fzp_open(sig, "rb"))) goto end; if((result=rs_loadsig_fzp(sigp, &sumset))!=RS_DONE) { logp("rs_loadsig_fzp returned %d %s\n", result, rs_strerror(result)); goto end; } if((result=rs_build_hash_table(sumset))!=RS_DONE) { logp("rs_build_hash_table returned %d %s\n", result, rs_strerror(result)); goto end; } //logp("make rev deltb: %s %s %s\n", src, sig, del); if(dpth_protocol1_is_compressed(compression, src)) srcfzp=fzp_gzopen(src, "rb"); else srcfzp=fzp_open(src, "rb"); if(!srcfzp) goto end; if(get_int(cconfs[OPT_COMPRESSION])) delfzp=fzp_gzopen(del, comp_level(get_int(cconfs[OPT_COMPRESSION]))); else delfzp=fzp_open(del, "wb"); if(!delfzp) goto end; if((result=rs_delta_gzfile(sumset, srcfzp, delfzp))!=RS_DONE) { logp("rs_delta_gzfile returned %d %s\n", result, rs_strerror(result)); goto end; } ret=0; end: if(sumset) rs_free_sumset(sumset); fzp_close(&srcfzp); fzp_close(&sigp); if(fzp_close(&delfzp)) { logp("error closing delfzp %s in %s\n", del, __func__); ret=-1; } return ret; }
static int send_file(struct asfd *asfd, struct sbuf *sb, int patches, const char *best, uint64_t *bytes, struct cntr *cntr) { int ret=0; static BFILE *bfd=NULL; if(!bfd && !(bfd=bfile_alloc())) return -1; bfile_init(bfd, 0, cntr); if(bfd->open_for_send(bfd, asfd, best, sb->winattr, 1 /* no O_NOATIME */, cntr, PROTO_1)) return -1; //logp("sending: %s\n", best); if(asfd->write(asfd, &sb->path)) ret=-1; else if(patches) { // If we did some patches, the resulting file // is not gzipped. Gzip it during the send. ret=send_whole_file_gzl(asfd, best, sb->protocol1->datapth.buf, 1, bytes, NULL, cntr, 9, bfd, NULL, 0); } else { // If it was encrypted, it may or may not have been compressed // before encryption. Send it as it as, and let the client // sort it out. if(sbuf_is_encrypted(sb)) { ret=send_whole_filel(asfd, sb->path.cmd, best, sb->protocol1->datapth.buf, 1, bytes, cntr, bfd, NULL, 0); } // It might have been stored uncompressed. Gzip it during // the send. If the client knew what kind of file it would be // receiving, this step could disappear. else if(!dpth_protocol1_is_compressed(sb->compression, sb->protocol1->datapth.buf)) { ret=send_whole_file_gzl(asfd, best, sb->protocol1->datapth.buf, 1, bytes, NULL, cntr, 9, bfd, NULL, 0); } else { // If we did not do some patches, the resulting // file might already be gzipped. Send it as it is. ret=send_whole_filel(asfd, sb->path.cmd, best, sb->protocol1->datapth.buf, 1, bytes, cntr, bfd, NULL, 0); } } bfd->close(bfd, asfd); return ret; }
static int make_rev_delta(const char *src, const char *sig, const char *del, int compression, struct conf **cconfs) { int ret=-1; FILE *srcfp=NULL; FILE *delfp=NULL; FILE *sigp=NULL; gzFile srczp=NULL; gzFile delzp=NULL; rs_signature_t *sumset=NULL; //logp("make rev delta: %s %s %s\n", src, sig, del); if(!(sigp=open_file(sig, "rb"))) goto end; if(rs_loadsig_file(sigp, &sumset, NULL)!=RS_DONE || rs_build_hash_table(sumset)!=RS_DONE) goto end; //logp("make rev deltb: %s %s %s\n", src, sig, del); if(dpth_protocol1_is_compressed(compression, src)) srczp=gzopen_file(src, "rb"); else srcfp=open_file(src, "rb"); if(!srczp && !srcfp) goto end; if(get_int(cconfs[OPT_COMPRESSION])) delzp=gzopen_file(del, comp_level(cconfs)); else delfp=open_file(del, "wb"); if(!delzp && !delfp) goto end; if(rs_delta_gzfile(NULL, sumset, srcfp, srczp, delfp, delzp, NULL, get_cntr(cconfs[OPT_CNTR]))!=RS_DONE) goto end; ret=0; end: if(sumset) rs_free_sumset(sumset); gzclose_fp(&srczp); close_fp(&srcfp); close_fp(&sigp); if(gzclose_fp(&delzp)) { logp("error closing zp %s in %s\n", del, __func__); ret=-1; } if(close_fp(&delfp)) { logp("error closing fp %s in %s\n", del, __func__); ret=-1; } return ret; }
// Also used by restore.c. // FIX THIS: This stuff is very similar to make_rev_delta, can maybe share // some code. int do_patch(struct asfd *asfd, const char *dst, const char *del, const char *upd, bool gzupd, int compression, struct conf **cconfs) { FILE *dstp=NULL; FILE *delfp=NULL; gzFile delzp=NULL; gzFile updp=NULL; FILE *updfp=NULL; rs_result result=RS_IO_ERROR; //logp("patching...\n"); if(!(dstp=open_file(dst, "rb"))) goto end; if(dpth_protocol1_is_compressed(compression, del)) delzp=gzopen_file(del, "rb"); else delfp=open_file(del, "rb"); if(!delzp && !delfp) goto end; if(gzupd) updp=gzopen(upd, comp_level(cconfs)); else updfp=fopen(upd, "wb"); if(!updp && !updfp) goto end; result=rs_patch_gzfile(asfd, dstp, delfp, delzp, updfp, updp, NULL, get_cntr(cconfs[OPT_CNTR])); end: close_fp(&dstp); gzclose_fp(&delzp); close_fp(&delfp); if(close_fp(&updfp)) { logp("error closing %s in %s\n", upd, __func__); result=RS_IO_ERROR; } if(gzclose_fp(&updp)) { logp("error gzclosing %s in %s\n", upd, __func__); result=RS_IO_ERROR; } return result; }
static int inflate_or_link_oldfile(const char *oldpath, const char *infpath, int compression, struct conf **cconfs) { struct stat statp; if(lstat(oldpath, &statp)) { logp("could not lstat %s\n", oldpath); return -1; } if(dpth_protocol1_is_compressed(compression, oldpath)) return inflate_oldfile(oldpath, infpath, &statp, cconfs); // If it was not a compressed file, just hard link it. // It is possible that infpath already exists, if the server // was interrupted on a previous run just after this point. return do_link(oldpath, infpath, &statp, cconfs, 1 /* allow overwrite of infpath */); }
static int inflate_or_link_oldfile(struct asfd *asfd, const char *oldpath, const char *infpath, struct conf **cconfs, int compression) { int ret=0; struct stat statp; if(lstat(oldpath, &statp)) { logp("could not lstat %s\n", oldpath); return -1; } if(dpth_protocol1_is_compressed(compression, oldpath)) { //logp("inflating...\n"); if(!statp.st_size) { // Empty file - cannot inflate. logp("asked to inflate zero length file: %s\n", oldpath); return create_zero_length_file(infpath); } if((ret=zlib_inflate(asfd, oldpath, infpath, get_cntr(cconfs)))) logp("zlib_inflate returned: %d\n", ret); } else { // Not compressed - just hard link it. if(do_link(oldpath, infpath, &statp, cconfs, 1 /* allow overwrite of infpath */)) return -1; } return ret; }
static int do_restore_file_or_get_meta(struct asfd *asfd, BFILE *bfd, struct sbuf *sb, const char *fname, char **metadata, size_t *metalen, struct cntr *cntr, const char *rpath, const char *encryption_password) { int ret=-1; int enccompressed=0; uint64_t rcvdbytes=0; uint64_t sentbytes=0; const char *encpassword=NULL; if(sbuf_is_encrypted(sb)) encpassword=encryption_password; enccompressed=dpth_protocol1_is_compressed(sb->compression, sb->protocol1->datapth.buf); /* printf("%s \n", fname); if(encpassword && !enccompressed) printf("encrypted and not compressed\n"); else if(!encpassword && enccompressed) printf("not encrypted and compressed\n"); else if(!encpassword && !enccompressed) printf("not encrypted and not compressed\n"); else if(encpassword && enccompressed) printf("encrypted and compressed\n"); */ if(metadata) { ret=transfer_gzfile_inl(asfd, sb, fname, NULL, &rcvdbytes, &sentbytes, encpassword, enccompressed, cntr, metadata); *metalen=sentbytes; // skip setting cntr, as we do not actually // restore until a bit later goto end; } else { ret=transfer_gzfile_inl(asfd, sb, fname, bfd, &rcvdbytes, &sentbytes, encpassword, enccompressed, cntr, NULL); #ifndef HAVE_WIN32 if(bfd && bfd->close(bfd, asfd)) { logp("error closing %s in %s\n", fname, __func__); goto end; } #endif if(!ret) attribs_set(asfd, rpath, &sb->statp, sb->winattr, cntr); } ret=0; end: if(ret) { char msg[256]=""; snprintf(msg, sizeof(msg), "Could not transfer file in: %s", rpath); if(restore_interrupt(asfd, sb, msg, cntr, PROTO_1)) ret=-1; } return ret; }
static int verify_file(struct asfd *asfd, struct sbuf *sb, int patches, const char *best, uint64_t *bytes, struct cntr *cntr) { MD5_CTX md5; size_t b=0; const char *cp=NULL; const char *newsum=NULL; uint8_t in[ZCHUNK]; uint8_t checksum[MD5_DIGEST_LENGTH]; uint64_t cbytes=0; struct fzp *fzp=NULL; if(!(cp=strrchr(sb->endfile.buf, ':'))) { logw(asfd, cntr, "%s has no md5sum!\n", sb->protocol1->datapth.buf); return 0; } cp++; if(!MD5_Init(&md5)) { logp("MD5_Init() failed\n"); return -1; } if(patches || sb->path.cmd==CMD_ENC_FILE || sb->path.cmd==CMD_ENC_METADATA || sb->path.cmd==CMD_EFS_FILE || sb->path.cmd==CMD_ENC_VSS || (!patches && !dpth_protocol1_is_compressed(sb->compression, best))) fzp=fzp_open(best, "rb"); else fzp=fzp_gzopen(best, "rb"); if(!fzp) { logw(asfd, cntr, "could not open %s\n", best); return 0; } while((b=fzp_read(fzp, in, ZCHUNK))>0) { cbytes+=b; if(!MD5_Update(&md5, in, b)) { logp("MD5_Update() failed\n"); fzp_close(&fzp); return -1; } } if(!fzp_eof(fzp)) { logw(asfd, cntr, "error while reading %s\n", best); fzp_close(&fzp); return 0; } fzp_close(&fzp); if(!MD5_Final(checksum, &md5)) { logp("MD5_Final() failed\n"); return -1; } newsum=bytes_to_md5str(checksum); if(strcmp(newsum, cp)) { logp("%s %s\n", newsum, cp); logw(asfd, cntr, "md5sum for '%s (%s)' did not match!\n", sb->path.buf, sb->protocol1->datapth.buf); logp("md5sum for '%s (%s)' did not match!\n", sb->path.buf, sb->protocol1->datapth.buf); return 0; } *bytes+=cbytes; // Just send the file name to the client, so that it can show cntr. if(asfd->write(asfd, &sb->path)) return -1; return 0; }
static int maybe_do_delta_stuff(struct asfd *asfd, struct sdirs *sdirs, struct sbuf *cb, struct sbuf *p1b, struct fzp *ucfp, struct conf **cconfs) { int oldcompressed=0; int compression=get_int(cconfs[OPT_COMPRESSION]); // If the file type changed, I think it is time to back it up again // (for example, EFS changing to normal file, or back again). if(cb->path.cmd!=p1b->path.cmd) return process_new_file(sdirs, cconfs, cb, p1b, ucfp); // mtime is the actual file data. // ctime is the attributes or meta data. if(cb->statp.st_mtime==p1b->statp.st_mtime && cb->statp.st_ctime==p1b->statp.st_ctime) { // got an unchanged file //logp("got unchanged file: %s %c %c\n", // cb->path.buf, cb->path.cmd, p1b->path.cmd); return process_unchanged_file(p1b, cb, ucfp, cconfs); } if(cb->statp.st_mtime==p1b->statp.st_mtime && cb->statp.st_ctime!=p1b->statp.st_ctime) { // File data stayed the same, but attributes or meta data // changed. We already have the attributes, but may need to get // extra meta data. // FIX THIS horrible mess. if(cb->path.cmd==CMD_ENC_METADATA || p1b->path.cmd==CMD_ENC_METADATA // FIX THIS: make unencrypted metadata use the librsync || cb->path.cmd==CMD_METADATA || p1b->path.cmd==CMD_METADATA || cb->path.cmd==CMD_VSS || p1b->path.cmd==CMD_VSS || cb->path.cmd==CMD_ENC_VSS || p1b->path.cmd==CMD_ENC_VSS || cb->path.cmd==CMD_VSS_T || p1b->path.cmd==CMD_VSS_T || cb->path.cmd==CMD_ENC_VSS_T || p1b->path.cmd==CMD_ENC_VSS_T || cb->path.cmd==CMD_EFS_FILE || p1b->path.cmd==CMD_EFS_FILE) return process_new_file(sdirs, cconfs, cb, p1b, ucfp); // On Windows, we have to back up the whole file if ctime // changed, otherwise things like permission changes do not get // noticed. So, in that case, fall through to the changed stuff // below. // Non-Windows clients finish here. else if(!get_int(cconfs[OPT_CLIENT_IS_WINDOWS])) return process_unchanged_file(p1b, cb, ucfp, cconfs); } // Got a changed file. //logp("got changed file: %s\n", p1b->path); // If either old or new is encrypted, or librsync is off, we need to // get a new file. // FIX THIS horrible mess. if(get_int(cconfs[OPT_LIBRSYNC]) || cb->path.cmd==CMD_ENC_FILE || p1b->path.cmd==CMD_ENC_FILE || cb->path.cmd==CMD_ENC_METADATA || p1b->path.cmd==CMD_ENC_METADATA || cb->path.cmd==CMD_EFS_FILE || p1b->path.cmd==CMD_EFS_FILE // FIX THIS: make unencrypted metadata use the librsync || cb->path.cmd==CMD_METADATA || p1b->path.cmd==CMD_METADATA || cb->path.cmd==CMD_VSS || p1b->path.cmd==CMD_VSS || cb->path.cmd==CMD_ENC_VSS || p1b->path.cmd==CMD_ENC_VSS || cb->path.cmd==CMD_VSS_T || p1b->path.cmd==CMD_VSS_T || cb->path.cmd==CMD_ENC_VSS_T || p1b->path.cmd==CMD_ENC_VSS_T) return process_new_file(sdirs, cconfs, cb, p1b, ucfp); // Get new files if they have switched between compression on or off. if(cb->protocol1->datapth.buf && dpth_protocol1_is_compressed(cb->compression, cb->protocol1->datapth.buf)) oldcompressed=1; if( ( oldcompressed && !compression) || (!oldcompressed && compression)) return process_new_file(sdirs, cconfs, cb, p1b, ucfp); // Otherwise, do the delta stuff (if possible). if(cmd_is_filedata(p1b->path.cmd)) { if(process_changed_file(asfd, sdirs, cconfs, cb, p1b, sdirs->currentdata)) return -1; } else { if(changed_non_file(p1b, ucfp, p1b->path.cmd, cconfs)) return -1; } sbuf_free_content(cb); return 1; }
static int process_changed_file(struct asfd *asfd, struct sdirs *sdirs, struct conf **cconfs, struct sbuf *cb, struct sbuf *p1b, const char *adir) { size_t blocklen=0; char *curpath=NULL; //logp("need to process changed file: %s (%s)\n", // cb->path, cb->datapth); // Move datapth onto p1b. iobuf_move(&p1b->protocol1->datapth, &cb->protocol1->datapth); if(!(curpath=prepend_s(adir, p1b->protocol1->datapth.buf))) { log_out_of_memory(__func__); return -1; } if(dpth_protocol1_is_compressed(cb->compression, curpath)) p1b->protocol1->sigfzp=fzp_gzopen(curpath, "rb"); else p1b->protocol1->sigfzp=fzp_open(curpath, "rb"); if(!p1b->protocol1->sigfzp) { logp("could not open %s: %s\n", curpath, strerror(errno)); free(curpath); return -1; } free(curpath); blocklen=get_librsync_block_len(cb->protocol1->endfile.buf); if(!(p1b->protocol1->sigjob= #ifdef RS_DEFAULT_STRONG_LEN rs_sig_begin(blocklen, RS_DEFAULT_STRONG_LEN) #else // This is for librsync-1.0.0. RS_DEFAULT_STRONG_LEN was 8 in // librsync-0.9.7. rs_sig_begin(blocklen, 8, rshash_to_magic_number(get_e_rshash(cconfs[OPT_RSHASH]))) #endif )) { logp("could not start signature job.\n"); return -1; } //logp("sig begin: %s\n", p1b->protocol1->datapth.buf); if(!(p1b->protocol1->infb=rs_filebuf_new(asfd, NULL, p1b->protocol1->sigfzp, -1, blocklen, -1, get_cntr(cconfs[OPT_CNTR])))) { logp("could not rs_filebuf_new for infb.\n"); return -1; } if(!(p1b->protocol1->outfb=rs_filebuf_new(asfd, NULL, NULL, asfd->fd, ASYNC_BUF_LEN, -1, get_cntr(cconfs[OPT_CNTR])))) { logp("could not rs_filebuf_new for in_outfb.\n"); return -1; } // Flag the things that need to be sent (to the client) p1b->flags |= SBUFL_SEND_DATAPTH; p1b->flags |= SBUFL_SEND_STAT; p1b->flags |= SBUFL_SEND_PATH; //logp("sending sig for %s\n", p1b->path); //logp("(%s)\n", p1b->datapth); return 0; }
static int do_send_file(struct asfd *asfd, struct sbuf *sb, int patches, const char *best, struct cntr *cntr) { enum send_e ret=SEND_FATAL; struct BFILE bfd; uint64_t bytes=0; // Unused. bfile_init(&bfd, 0, cntr); if(bfd.open_for_send(&bfd, asfd, best, sb->winattr, 1 /* no O_NOATIME */, cntr, PROTO_1)) return SEND_FATAL; if(asfd->write(asfd, &sb->path)) ret=SEND_FATAL; else if(patches) { // If we did some patches, the resulting file // is not gzipped. Gzip it during the send. ret=send_whole_file_gzl( asfd, sb->protocol1->datapth.buf, /*quick_read*/1, &bytes, /*encpassword*/NULL, cntr, /*compression*/9, &bfd, /*extrameta*/NULL, /*elen*/0, /*key_deriv*/ENCRYPTION_UNSET, /*salt*/0 ); } else { // If it was encrypted, it may or may not have been compressed // before encryption. Send it as it as, and let the client // sort it out. if(sbuf_is_encrypted(sb)) { ret=send_whole_filel(asfd, #ifdef HAVE_WIN32 sb->path.cmd #endif sb->protocol1->datapth.buf, 1, &bytes, cntr, &bfd, NULL, 0); } // It might have been stored uncompressed. Gzip it during // the send. If the client knew what kind of file it would be // receiving, this step could disappear. else if(!dpth_protocol1_is_compressed(sb->compression, sb->protocol1->datapth.buf)) { ret=send_whole_file_gzl( asfd, sb->protocol1->datapth.buf, /*quick_read*/1, &bytes, /*encpassword*/NULL, cntr, /*compression*/9, &bfd, /*extrameta*/NULL, /*elen*/0, /*key_deriv*/ENCRYPTION_UNSET, /*salt*/0 ); } else { // If we did not do some patches, the resulting // file might already be gzipped. Send it as it is. ret=send_whole_filel(asfd, #ifdef HAVE_WIN32 sb->path.cmd #endif sb->protocol1->datapth.buf, 1, &bytes, cntr, &bfd, NULL, 0); } } bfd.close(&bfd, asfd); switch(ret) { case SEND_OK: case SEND_ERROR: // Carry on. return 0; case SEND_FATAL: default: return -1; } }