// 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 fzp *dstp=NULL; struct fzp *delfzp=NULL; struct fzp *upfzp=NULL; rs_result result=RS_IO_ERROR; if(!(dstp=fzp_open(dst, "rb"))) goto end; if(!(delfzp=fzp_gzopen(del, "rb"))) goto end; if(gzupd) upfzp=fzp_gzopen(upd, comp_level(compression)); else upfzp=fzp_open(upd, "wb"); if(!upfzp) goto end; result=rs_patch_gzfile(dstp, delfzp, upfzp); end: fzp_close(&dstp); fzp_close(&delfzp); if(fzp_close(&upfzp)) { logp("error closing %s in %s\n", upd, __func__); result=RS_IO_ERROR; } return result; }
static struct fzp *open_backup_log(struct bu *bu, const char *logfile) { char *path=NULL; struct fzp *fzp=NULL; char logfilereal[32]=""; if(!strcmp(logfile, "backup")) snprintf(logfilereal, sizeof(logfilereal), "log"); else if(!strcmp(logfile, "restore")) snprintf(logfilereal, sizeof(logfilereal), "restorelog"); else if(!strcmp(logfile, "verify")) snprintf(logfilereal, sizeof(logfilereal), "verifylog"); else if(!strcmp(logfile, "backup_stats")) snprintf(logfilereal, sizeof(logfilereal), "backup_stats"); else if(!strcmp(logfile, "restore_stats")) snprintf(logfilereal, sizeof(logfilereal), "restore_stats"); else if(!strcmp(logfile, "verify_stats")) snprintf(logfilereal, sizeof(logfilereal), "verify_stats"); if(!(path=prepend_s(bu->path, logfilereal))) goto end; if(!(fzp=fzp_gzopen(path, "rb"))) { if(astrcat(&path, ".gz", __func__) || !(fzp=fzp_gzopen(path, "rb"))) goto end; } end: free_w(&path); return fzp; }
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 bcompress(const char *src, const char *dst, int compression) { int res; int got; struct fzp *sfzp=NULL; struct fzp *dfzp=NULL; char buf[ZCHUNK]; if(!(sfzp=fzp_open(src, "rb")) || !(dfzp=fzp_gzopen(dst, comp_level(compression)))) goto error; while((got=fzp_read(sfzp, buf, sizeof(buf)))>0) { res=fzp_write(dfzp, buf, got); if(res!=got) { logp("compressing %s - read %d but wrote %d\n", src, got, res); goto error; } } fzp_close(&sfzp); return fzp_close(&dfzp); error: fzp_close(&sfzp); fzp_close(&dfzp); return -1; }
int run_bsigs(int argc, char *argv[]) { int ret=1; fzp *fzp=NULL; struct iobuf rbuf; struct blk blk; memset(&rbuf, 0, sizeof(struct iobuf)); if(argc!=2) return usage(); path=argv[1]; if(!(fzp=fzp_gzopen(path, "rb"))) goto end; while(1) { iobuf_free_content(&rbuf); switch(iobuf_fill_from_fzp(&rbuf, fzp)) { case 1: ret=0; // Finished OK. case -1: goto end; // Error. } if(parse_cmd(&rbuf, &blk)) goto end; } end: iobuf_free_content(&rbuf); fzp_close(&fzp); return ret; }
static int manio_open_next_fpath(struct manio *manio) { static struct stat statp; free_w(&manio->offset->fpath); if(!(manio->offset->fpath=get_next_fpath(manio, manio->offset))) return -1; if(!strcmp(manio->mode, MANIO_MODE_READ) && lstat(manio->offset->fpath, &statp)) return 0; if(build_path_w(manio->offset->fpath)) return -1; switch(manio->phase) { case 2: if(!(manio->fzp=fzp_open(manio->offset->fpath, manio->mode))) return -1; return 0; case 1: case 3: default: if(!(manio->fzp=fzp_gzopen(manio->offset->fpath, manio->mode))) return -1; return 0; } }
static void check_dindex(int i) { int ret; struct fzp *fzp; const char *p; struct iobuf rbuf; int lines=0; struct blk blk; uint64_t last_savepath=0; p=get_extra_path(i, "dindex"); memset(&rbuf, 0, sizeof(rbuf)); fail_unless((fzp=fzp_gzopen(p, "rb"))!=NULL); while(!(ret=iobuf_fill_from_fzp(&rbuf, fzp))) { lines++; switch(rbuf.cmd) { case CMD_SAVE_PATH: blk_set_from_iobuf_savepath(&blk, &rbuf); fail_unless(blk.savepath>last_savepath); last_savepath=blk.savepath; break; default: fail_unless(0==1); break; } iobuf_free_content(&rbuf); } fail_unless(ret==1); fail_unless(lines>500); fail_unless(!fzp_close(&fzp)); }
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; }
int manio_seek(struct manio *manio, man_off_t *offset) { fzp_close(&manio->fzp); man_off_t_memcpy(&manio->offset, offset); if(!(manio->fzp=fzp_gzopen(manio->offset.fpath, manio->mode))) return -1; return fzp_seek(manio->fzp, manio->offset.offset, SEEK_SET); }
static void assert_file_content(const char *path, const char *content) { size_t got; struct fzp *fp; size_t len=strlen(content); char buf[256]=""; fail_unless((fp=fzp_gzopen(path, "rb"))!=NULL); got=fzp_read(fp, buf, len); fail_unless(len==got); fail_unless(!strcmp(buf, content)); fzp_close(&fp); }
// Open the previous (current) manifest. // If the split_vss setting changed between the previous backup and the new // backup, do not open the previous manifest. This will have the effect of // making the client back up everything fresh. Need to do this, otherwise // toggling split_vss on and off will result in backups that do not work. static int open_previous_manifest(struct fzp **cmanfp, struct sdirs *sdirs, const char *incexc, struct conf **cconfs) { struct stat statp; if(!lstat(sdirs->cmanifest, &statp) && !vss_opts_changed(sdirs, cconfs, incexc) && !(*cmanfp=fzp_gzopen(sdirs->cmanifest, "rb"))) { logp("could not open old manifest %s\n", sdirs->cmanifest); return -1; } return 0; }
int manio_seek(struct manio *manio, man_off_t *offset) { fzp_close(&manio->fzp); if(!(manio->fzp=fzp_gzopen(offset->fpath, manio->mode)) || fzp_seek(manio->fzp, offset->offset, SEEK_SET)) return -1; man_off_t_free_content(manio->offset); if(!(manio->offset->fpath=strdup_w(offset->fpath, __func__))) return -1; manio->offset->offset=offset->offset; manio->offset->fcount=offset->fcount; return 0; }
int zlib_inflate(struct asfd *asfd, const char *source_path, const char *dest_path, struct conf **confs) { int ret=-1; size_t b=0; uint8_t in[ZCHUNK]; struct fzp *src=NULL; struct fzp *dst=NULL; if(!(src=fzp_gzopen(source_path, "rb"))) { logw(asfd, confs, "could not gzopen %s in %s: %s\n", source_path, __func__, strerror(errno)); goto end; } if(!(dst=fzp_open(dest_path, "wb"))) { logw(asfd, confs, "could not open %s in %s: %s\n", dest_path, __func__, strerror(errno)); goto end; } while((b=fzp_read(src, in, ZCHUNK))>0) { if(fzp_write(dst, in, b)!=b) { logw(asfd, confs, "error when writing to %s\n", dest_path); goto end; } } if(!fzp_eof(src)) { logw(asfd, confs, "error while reading %s in %s\n", source_path, __func__); goto end; } if(fzp_close(&dst)) { logw(asfd, confs, "error when closing %s in %s: %s\n", dest_path, __func__, strerror(errno)); goto end; } ret=0; end: fzp_close(&src); fzp_close(&dst); return ret; }
END_TEST #define FULL_CHUNK 4096 static void do_assert_files_equal(const char *opath, const char *npath, int compressed) { size_t ogot; size_t ngot; unsigned int i=0; struct fzp *ofp; struct fzp *nfp; static char obuf[FULL_CHUNK]; static char nbuf[FULL_CHUNK]; if(compressed) { fail_unless((ofp=fzp_gzopen(opath, "rb"))!=NULL); fail_unless((nfp=fzp_gzopen(npath, "rb"))!=NULL); } else { fail_unless((ofp=fzp_open(opath, "rb"))!=NULL); fail_unless((nfp=fzp_open(npath, "rb"))!=NULL); } while(1) { ogot=fzp_read(ofp, obuf, FULL_CHUNK); ngot=fzp_read(nfp, nbuf, FULL_CHUNK); fail_unless(ogot==ngot); for(i=0; i<ogot; i++) fail_unless(obuf[i]==nbuf[i]); if(ogot<FULL_CHUNK) break; } fzp_close(&ofp); fzp_close(&nfp); }
int manio_open_next_fpath(struct manio *manio) { static struct stat statp; if(!(manio->offset.fpath=get_next_fpath(manio))) return -1; if(!strcmp(manio->mode, MANIO_MODE_READ) && lstat(manio->offset.fpath, &statp)) return 0; if(build_path_w(manio->offset.fpath) || !(manio->fzp=fzp_gzopen(manio->offset.fpath, manio->mode))) return -1; return 0; }
static int setup_cntr(struct asfd *asfd, const char *manifest, regex_t *regex, int srestore, enum action act, char status, struct conf **cconfs) { int ars=0; int ret=-1; struct fzp *fzp=NULL; struct sbuf *sb=NULL; struct cntr *cntr=get_cntr(cconfs); // FIX THIS: this is only trying to work for protocol1. if(get_protocol(cconfs)!=PROTO_1) return 0; if(!(sb=sbuf_alloc(PROTO_1))) goto end; if(!(fzp=fzp_gzopen(manifest, "rb"))) { log_and_send(asfd, "could not open manifest"); goto end; } while(1) { if((ars=sbuf_fill_from_file(sb, fzp, NULL, NULL))) { if(ars<0) goto end; // ars==1 means end ok break; } else { if(want_to_restore(srestore, sb, regex, cconfs)) { cntr_add_phase1(cntr, sb->path.cmd, 0); if(sb->endfile.buf) cntr_add_val(cntr, CMD_BYTES_ESTIMATED, strtoull(sb->endfile.buf, NULL, 10), 0); } } sbuf_free_content(sb); } ret=0; end: sbuf_free(&sb); fzp_close(&fzp); return ret; }
static int start_to_receive_delta(struct sdirs *sdirs, struct conf **cconfs, struct sbuf *rb) { if(rb->compression) { if(!(rb->protocol1->fzp=fzp_gzopen(sdirs->deltmppath, comp_level(rb->compression)))) return -1; } else { if(!(rb->protocol1->fzp=fzp_open(sdirs->deltmppath, "wb"))) return -1; } rb->flags |= SBUF_RECV_DELTA; return 0; }
static int start_to_receive_delta(struct sdirs *sdirs, struct conf **cconfs, struct sbuf *rb) { if(get_int(cconfs[OPT_COMPRESSION])) { if(!(rb->protocol1->fzp=fzp_gzopen(sdirs->deltmppath, comp_level(cconfs)))) return -1; } else { if(!(rb->protocol1->fzp=fzp_open(sdirs->deltmppath, "wb"))) return -1; } rb->flags |= SBUFL_RECV_DELTA; return 0; }
static void check_hooks(int i, int fcount) { int ret; struct fzp *fzp; const char *p; struct iobuf rbuf; struct blk blk; int lines=0; uint64_t last_fingerprint=0; char manifest_line[64]=""; p=get_extra_path(i, "hooks"); memset(&rbuf, 0, sizeof(rbuf)); snprintf(manifest_line, sizeof(manifest_line), "%s/%08X", RMANIFEST_RELATIVE, i); fail_unless((fzp=fzp_gzopen(p, "rb"))!=NULL); while(!(ret=iobuf_fill_from_fzp(&rbuf, fzp))) { lines++; switch(rbuf.cmd) { case CMD_MANIFEST: fail_unless(lines==1); ck_assert_str_eq(manifest_line, rbuf.buf); break; case CMD_FINGERPRINT: blk_set_from_iobuf_fingerprint(&blk, &rbuf); fail_unless(blk.fingerprint>last_fingerprint); last_fingerprint=blk.fingerprint; break; default: fail_unless(0==1); break; } iobuf_free_content(&rbuf); } fail_unless(ret==1); if(i<fcount-1) fail_unless(lines>200); else fail_unless(lines>10); // Last file will have fewer entries. fail_unless(!fzp_close(&fzp)); }
static int sort_and_write_dindex(struct manio *manio) { int i; int ret=-1; struct fzp *fzp=NULL; char msg[32]=""; char *path=NULL; struct iobuf wbuf; struct blk blk; int dindex_count=manio->dindex_count; uint64_t *dindex_sort=manio->dindex_sort; if(!dindex_sort) return 0; snprintf(msg, sizeof(msg), "%08"PRIX64, manio->offset->fcount-1); if(!(path=prepend_s(manio->dindex_dir, msg)) || build_path_w(path) || !(fzp=fzp_gzopen(path, MANIO_MODE_WRITE))) goto end; qsort(dindex_sort, dindex_count, sizeof(uint64_t), uint64_t_sort); for(i=0; i<dindex_count; i++) { // Do not bother with duplicates. if(i && dindex_sort[i]==dindex_sort[i-1]) continue; blk.savepath=dindex_sort[i]; blk_to_iobuf_savepath(&blk, &wbuf); if(iobuf_send_msg_fzp(&wbuf, fzp)) return -1; } if(fzp_close(&fzp)) { logp("Error closing %s in %s: %s\n", path, __func__, strerror(errno)); goto end; } manio->dindex_count=0; ret=0; end: fzp_close(&fzp); free_w(&path); return ret; }
void build_sparse_index(const char *path, int manifests, int fingerprints) { struct fzp *fzp; fail_unless(!build_path_w(path)); fail_unless((fzp=fzp_gzopen(path, "wb"))!=NULL); for(int m=0; m<manifests; m++) { char mpath[256]; snprintf(mpath, sizeof(mpath), "some/manifest/%d", m); fzp_printf(fzp, "%c%04lX%s\n", CMD_MANIFEST, strlen(mpath), mpath); for(int f=0; f<fingerprints; f++) fail_unless(!to_fzp_fingerprint(fzp, prng_next64())); } fail_unless(!fzp_close(&fzp)); }
static int sort_and_write_hooks(struct manio *manio) { int i; int ret=-1; struct fzp *fzp=NULL; char msg[32]=""; char *path=NULL; int hook_count=manio->hook_count; uint64_t *hook_sort=manio->hook_sort; if(!hook_sort) return 0; snprintf(msg, sizeof(msg), "%08"PRIX64, manio->offset->fcount-1); if(!(path=prepend_s(manio->hook_dir, msg)) || build_path_w(path) || !(fzp=fzp_gzopen(path, MANIO_MODE_WRITE))) goto end; qsort(hook_sort, hook_count, sizeof(uint64_t), uint64_t_sort); if(write_hook_header(fzp, manio->rmanifest, msg)) goto end; for(i=0; i<hook_count; i++) { // Do not bother with duplicates. if(i && hook_sort[i]==hook_sort[i-1]) continue; if(to_fzp_fingerprint(fzp, hook_sort[i])) goto end; } if(fzp_close(&fzp)) { logp("Error closing %s in %s: %s\n", path, __func__, strerror(errno)); goto end; } if(manio_write_fcount(manio)) goto end; manio->hook_count=0; ret=0; end: fzp_close(&fzp); free_w(&path); return ret; }
static int sort_and_write_hooks(struct manio *manio) { int i; int ret=-1; struct fzp *fzp=NULL; char comp[32]=""; char *path=NULL; int hook_count=manio->hook_count; char **hook_sort=manio->hook_sort; if(!hook_sort) return 0; snprintf(comp, sizeof(comp), "%08"PRIX64, manio->offset.fcount-1); if(!(path=prepend_s(manio->hook_dir, comp)) || build_path_w(path) || !(fzp=fzp_gzopen(path, manio->mode))) goto end; qsort(hook_sort, hook_count, sizeof(char *), strsort); if(write_hook_header(manio, fzp, comp)) goto end; for(i=0; i<hook_count; i++) { // Do not bother with duplicates. if(i && !strcmp(hook_sort[i], hook_sort[i-1])) continue; fzp_printf(fzp, "%c%04X%s\n", CMD_FINGERPRINT, (unsigned int)strlen(hook_sort[i]), hook_sort[i]); } if(fzp_close(&fzp)) { logp("Error closing %s in %s: %s\n", path, __func__, strerror(errno)); goto end; } if(manio_write_fcount(manio)) goto end; manio->hook_count=0; ret=0; end: fzp_close(&fzp); free_w(&path); return ret; }
END_TEST START_TEST(test_protocol1_verify_file_gzip_read_failure) { struct asfd *asfd; struct cntr *cntr; struct sbuf *sb; const char *path="somepath"; const char *datapth="/datapth"; const char *endfile="0:0"; const char *best=BASE "/existent"; const char *plain_text="some plain text"; size_t s; struct fzp *fzp; s=strlen(plain_text); clean(); cntr=setup_cntr(); sb=setup_sbuf(path, datapth, endfile, 1/*compression*/); // Make a corrupt gzipped file. build_path_w(best); fail_unless((fzp=fzp_gzopen(best, "wb"))!=NULL); fail_unless(fzp_write(fzp, plain_text, s)==s); fail_unless(!fzp_close(&fzp)); fail_unless((fzp=fzp_open(best, "r+b"))!=NULL); fail_unless(!fzp_seek(fzp, 10, SEEK_SET)); fail_unless(fzp_write(fzp, "aa", 2)==2); fail_unless(!fzp_close(&fzp)); asfd=asfd_mock_setup(&areads, &awrites); setup_error_while_reading(asfd, best); // Returns 0 so that the parent process continues. fail_unless(!verify_file(asfd, sb, 0 /*patches*/, best, cntr)); fail_unless(cntr->ent[CMD_WARNING]->count==1); tear_down(&sb, &cntr, NULL, &asfd); }
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; }
/* Merge two files of sorted dindexes into each other. */ int merge_dindexes(const char *dst, const char *srca, const char *srcb) { int ret=-1; struct sbuf *asb=NULL; struct sbuf *bsb=NULL; struct fzp *azp=NULL; struct fzp *bzp=NULL; struct fzp *dzp=NULL; uint64_t *anew=NULL; uint64_t *bnew=NULL; if(!(asb=sbuf_alloc(PROTO_2)) || (srcb && !(bsb=sbuf_alloc(PROTO_2)))) goto end; if(build_path_w(dst)) goto end; if((srca && !(azp=fzp_gzopen(srca, "rb"))) || (srcb && !(bzp=fzp_gzopen(srcb, "rb"))) || !(dzp=fzp_gzopen(dst, "wb"))) goto end; while(azp || bzp || anew || bnew) { if(azp && asb && !anew) { switch(get_next_dindex(&anew, asb, azp)) { case -1: goto end; case 1: fzp_close(&azp); // Finished OK. } } if(bzp && bsb && !bnew) { switch(get_next_dindex(&bnew, bsb, bzp)) { case -1: goto end; case 1: fzp_close(&bzp); // Finished OK. } } if(anew && !bnew) { if(gzprintf_dindex(dzp, anew)) goto end; free_v((void **)&anew); } else if(!anew && bnew) { if(gzprintf_dindex(dzp, bnew)) goto end; free_v((void **)&bnew); } else if(!anew && !bnew) { continue; } else if(*anew==*bnew) { // They were the same - write the new one. if(gzprintf_dindex(dzp, bnew)) goto end; free_v((void **)&anew); free_v((void **)&bnew); } else if(*anew<*bnew) { if(gzprintf_dindex(dzp, anew)) goto end; free_v((void **)&anew); } else { if(gzprintf_dindex(dzp, bnew)) goto end; free_v((void **)&bnew); } } if(fzp_close(&dzp)) { logp("Error closing %s in %s\n", tmpfile, __func__); goto end; } ret=0; end: fzp_close(&azp); fzp_close(&bzp); fzp_close(&dzp); sbuf_free(&asb); sbuf_free(&bsb); free_v((void **)&anew); free_v((void **)&bnew); return ret; }
static #endif int merge_sparse_indexes(const char *dst, const char *srca, const char *srcb) { int fcmp; int ret=-1; struct sbuf *asb=NULL; struct sbuf *bsb=NULL; uint64_t *afingerprints=NULL; uint64_t *bfingerprints=NULL; size_t aflen=0; size_t bflen=0; struct fzp *azp=NULL; struct fzp *bzp=NULL; struct fzp *dzp=NULL; struct hooks *anew=NULL; struct hooks *bnew=NULL; char *apath=NULL; char *bpath=NULL; if(!(asb=sbuf_alloc(PROTO_2)) || (srcb && !(bsb=sbuf_alloc(PROTO_2)))) goto end; if(build_path_w(dst)) goto end; if((srca && !(azp=fzp_gzopen(srca, "rb"))) || (srcb && !(bzp=fzp_gzopen(srcb, "rb"))) || !(dzp=fzp_gzopen(dst, "wb"))) goto end; while(azp || bzp || anew || bnew) { if(azp && asb && !anew) { switch(get_next_set_of_hooks(&anew, asb, azp, &apath, &afingerprints, &aflen)) { case -1: goto end; case 1: fzp_close(&azp); // Finished OK. } } if(bzp && bsb && !bnew) { switch(get_next_set_of_hooks(&bnew, bsb, bzp, &bpath, &bfingerprints, &bflen)) { case -1: goto end; case 1: fzp_close(&bzp); // Finished OK. } } if(anew && !bnew) { if(gzprintf_hooks(dzp, anew)) goto end; hooks_free(&anew); } else if(!anew && bnew) { if(gzprintf_hooks(dzp, bnew)) goto end; hooks_free(&bnew); } else if(!anew && !bnew) { continue; } else if(!(fcmp=hookscmp(anew, bnew))) { // They were the same - write the new one. if(gzprintf_hooks(dzp, bnew)) goto end; hooks_free(&anew); hooks_free(&bnew); } else if(fcmp<0) { if(gzprintf_hooks(dzp, anew)) goto end; hooks_free(&anew); } else { if(gzprintf_hooks(dzp, bnew)) goto end; hooks_free(&bnew); } } if(fzp_close(&dzp)) { logp("Error closing %s in %s\n", tmpfile, __func__); goto end; } ret=0; end: fzp_close(&azp); fzp_close(&bzp); fzp_close(&dzp); sbuf_free(&asb); sbuf_free(&bsb); hooks_free(&anew); hooks_free(&bnew); free_v((void **)&afingerprints); free_v((void **)&bfingerprints); free_w(&apath); free_w(&bpath); return ret; }
/* Need to make all the stuff that this does atomic so that existing backups never get broken, even if somebody turns the power off on the server. */ static int atomic_data_jiggle(struct sdirs *sdirs, struct fdirs *fdirs, int hardlinked_current, struct conf **cconfs) { int ret=-1; char *datapth=NULL; char *tmpman=NULL; struct stat statp; char *deltabdir=NULL; char *deltafdir=NULL; char *sigpath=NULL; struct fzp *zp=NULL; struct sbuf *sb=NULL; struct fzp *delfp=NULL; logp("Doing the atomic data jiggle...\n"); if(!(tmpman=get_tmp_filename(fdirs->manifest))) goto error; if(lstat(fdirs->manifest, &statp)) { // Manifest does not exist - maybe the server was killed before // it could be renamed. logp("%s did not exist - trying %s\n", fdirs->manifest, tmpman); // Rename race condition is of no consequence, because manifest // already does not exist. do_rename(tmpman, fdirs->manifest); } if(!(zp=fzp_gzopen(fdirs->manifest, "rb"))) goto error; if(!(deltabdir=prepend_s(fdirs->currentdup, "deltas.reverse")) || !(deltafdir=prepend_s(sdirs->finishing, "deltas.forward")) || !(sigpath=prepend_s(fdirs->currentdup, "sig.tmp")) || !(sb=sbuf_alloc(PROTO_1))) { log_out_of_memory(__func__); goto error; } mkdir(fdirs->datadir, 0777); while(1) { switch(sbuf_fill_from_file(sb, zp, NULL, NULL)) { case 0: break; case 1: goto end; default: goto error; } if(sb->protocol1->datapth.buf) { if(write_status(CNTR_STATUS_SHUFFLING, sb->protocol1->datapth.buf, get_cntr(cconfs)) || jiggle(sdirs, fdirs, sb, hardlinked_current, deltabdir, deltafdir, sigpath, &delfp, cconfs)) goto error; } sbuf_free_content(sb); } end: if(fzp_close(&delfp)) { logp("error closing %s in atomic_data_jiggle\n", fdirs->deletionsfile); goto error; } if(maybe_delete_files_from_manifest(tmpman, fdirs, cconfs)) goto error; // Remove the temporary data directory, we have probably removed // useful files from it. recursive_delete_dirs_only(deltafdir); ret=0; error: fzp_close(&zp); fzp_close(&delfp); sbuf_free(&sb); free_w(&deltabdir); free_w(&deltafdir); free_w(&sigpath); free_w(&datapth); free_w(&tmpman); return ret; }
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; }
// This deals with reading in the sparse index, as well as actual candidate // manifests. enum cand_ret candidate_load(struct candidate *candidate, const char *path, struct scores *scores) { enum cand_ret ret=CAND_RET_PERM; struct fzp *fzp=NULL; struct sbuf *sb=NULL; struct blk *blk=NULL; if(!(sb=sbuf_alloc(PROTO_2)) || !(blk=blk_alloc())) { ret=CAND_RET_PERM; goto error; } if(!(fzp=fzp_gzopen(path, "rb"))) { ret=CAND_RET_TEMP; goto error; } while(fzp) { sbuf_free_content(sb); switch(sbuf_fill_from_file(sb, fzp, blk, NULL)) { case 1: goto end; case -1: logp("Error reading %s in %s, pos %d\n", path, __func__, fzp_tell(fzp)); ret=CAND_RET_TEMP; goto error; } if(blk_fingerprint_is_hook(blk)) { if(sparse_add_candidate(&blk->fingerprint, candidate)) { ret=CAND_RET_PERM; goto error; } } else if(sb->path.cmd==CMD_MANIFEST) { if(!(candidate=candidates_add_new())) { ret=CAND_RET_PERM; goto error; } candidate->path=sb->path.buf; sb->path.buf=NULL; } blk->fingerprint=0; } end: if(scores_grow(scores, candidates_len)) { ret=CAND_RET_PERM; goto error; } candidates_set_score_pointers(candidates, candidates_len, scores); scores_reset(scores); //logp("Now have %d candidates\n", (int)candidates_len); ret=CAND_RET_OK; error: fzp_close(&fzp); sbuf_free(&sb); blk_free(&blk); return ret; }