static int changed_non_file(struct sbuf *p1b, FILE *ucfp, char cmd, struct cntr *cntr) { // As new_non_file. if(sbuf_to_manifest(p1b, ucfp, NULL)) return -1; else do_filecounter_changed(cntr, cmd); free_sbuf(p1b); return 0; }
static int new_non_file(struct sbuf *p1b, FILE *ucfp, char cmd, struct cntr *cntr) { // Is something that does not need more data backed up. // Like a directory or a link or something like that. // Goes into the unchanged file, so that it does not end up out of // order with normal files, which has to wait around for their data // to turn up. if(sbuf_to_manifest(p1b, ucfp, NULL)) return -1; else do_filecounter(cntr, cmd, 0); free_sbuf(p1b); return 0; }
static int process_unchanged_file(struct sbuf *cb, FILE *ucfp, struct cntr *cntr) { if(sbuf_to_manifest(cb, ucfp, NULL)) { free_sbuf(cb); return -1; } else { do_filecounter_same(cntr, cb->cmd); } if(cb->endfile) do_filecounter_bytes(cntr, strtoull(cb->endfile, NULL, 10)); free_sbuf(cb); return 1; }
int manio_write_sbuf(struct manio *manio, struct sbuf *sb) { if(!manio->fzp && manio_open_next_fpath(manio)) return -1; return sbuf_to_manifest(sb, manio->fzp); }
// Combine the phase1 and phase2 files into a new manifest. int backup_phase3_server(const char *phase2data, const char *unchangeddata, const char *manifest, int recovery, int compress, const char *client, struct cntr *p1cntr, struct cntr *cntr, struct config *cconf) { int ars=0; int ret=0; int pcmp=0; FILE *ucfp=NULL; FILE *p2fp=NULL; FILE *mp=NULL; gzFile mzp=NULL; struct sbuf ucb; struct sbuf p2b; char *manifesttmp=NULL; logp("Begin phase3 (merge manifests)\n"); if(!(manifesttmp=get_tmp_filename(manifest))) return -1; if(!(ucfp=open_file(unchangeddata, "rb")) || !(p2fp=open_file(phase2data, "rb")) || (compress && !(mzp=gzopen_file(manifesttmp, comp_level(cconf)))) || (!compress && !(mp=open_file(manifesttmp, "wb")))) { close_fp(&ucfp); gzclose_fp(&mzp); close_fp(&p2fp); close_fp(&mp); free(manifesttmp); return -1; } init_sbuf(&ucb); init_sbuf(&p2b); while(ucfp || p2fp) { if(ucfp && !ucb.path && (ars=sbuf_fill(ucfp, NULL, &ucb, cntr))) { if(ars<0) { ret=-1; break; } // ars==1 means it ended ok. close_fp(&ucfp); } if(p2fp && !p2b.path && (ars=sbuf_fill(p2fp, NULL, &p2b, cntr))) { if(ars<0) { ret=-1; break; } // ars==1 means it ended ok. close_fp(&p2fp); // In recovery mode, only want to read to the last // entry in the phase 2 file. if(recovery) break; } if(ucb.path && !p2b.path) { write_status(client, STATUS_MERGING, ucb.path, p1cntr, cntr); if(sbuf_to_manifest(&ucb, mp, mzp)) { ret=-1; break; } free_sbuf(&ucb); } else if(!ucb.path && p2b.path) { write_status(client, STATUS_MERGING, p2b.path, p1cntr, cntr); if(sbuf_to_manifest(&p2b, mp, mzp)) { ret=-1; break; } free_sbuf(&p2b); } else if(!ucb.path && !p2b.path) { continue; } else if(!(pcmp=sbuf_pathcmp(&ucb, &p2b))) { // They were the same - write one and free both. write_status(client, STATUS_MERGING, p2b.path, p1cntr, cntr); if(sbuf_to_manifest(&p2b, mp, mzp)) { ret=-1; break; } free_sbuf(&p2b); free_sbuf(&ucb); } else if(pcmp<0) { write_status(client, STATUS_MERGING, ucb.path, p1cntr, cntr); if(sbuf_to_manifest(&ucb, mp, mzp)) { ret=-1; break; } free_sbuf(&ucb); } else { write_status(client, STATUS_MERGING, p2b.path, p1cntr, cntr); if(sbuf_to_manifest(&p2b, mp, mzp)) { ret=-1; break; } free_sbuf(&p2b); } } free_sbuf(&ucb); free_sbuf(&p2b); close_fp(&p2fp); close_fp(&ucfp); if(close_fp(&mp)) { logp("error closing %s in backup_phase3_server\n", manifesttmp); ret=-1; } if(gzclose_fp(&mzp)) { logp("error gzclosing %s in backup_phase3_server\n", manifesttmp); ret=-1; } if(!ret) { if(do_rename(manifesttmp, manifest)) ret=-1; else { unlink(phase2data); unlink(unchangeddata); } } free(manifesttmp); logp("End phase3 (merge manifests)\n"); return ret; }
static int maybe_delete_files_from_manifest(const char *manifesttmp, struct fdirs *fdirs, struct conf **cconfs) { int ars=0; int ret=-1; int pcmp=0; struct fzp *dfp=NULL; struct fzp *nmzp=NULL; struct fzp *omzp=NULL; struct sbuf *db=NULL; struct sbuf *mb=NULL; struct stat statp; if(lstat(fdirs->deletionsfile, &statp)) // No deletions, no problem. return 0; logp("Performing deletions on manifest\n"); if(!(manifesttmp=get_tmp_filename(fdirs->manifest))) goto end; if(!(dfp=fzp_open(fdirs->deletionsfile, "rb")) || !(omzp=fzp_gzopen(fdirs->manifest, "rb")) || !(nmzp=fzp_gzopen(manifesttmp, comp_level(get_int(cconfs[OPT_COMPRESSION])))) || !(db=sbuf_alloc(PROTO_1)) || !(mb=sbuf_alloc(PROTO_1))) goto end; while(omzp || dfp) { if(dfp && !db->path.buf && (ars=sbuf_fill_from_file(db, dfp, NULL, NULL))) { if(ars<0) goto end; // ars==1 means it ended ok. fzp_close(&dfp); } if(omzp && !mb->path.buf && (ars=sbuf_fill_from_file(mb, omzp, NULL, NULL))) { if(ars<0) goto end; // ars==1 means it ended ok. fzp_close(&omzp); } if(mb->path.buf && !db->path.buf) { if(sbuf_to_manifest(mb, nmzp)) goto end; sbuf_free_content(mb); } else if(!mb->path.buf && db->path.buf) { sbuf_free_content(db); } else if(!mb->path.buf && !db->path.buf) { continue; } else if(!(pcmp=sbuf_pathcmp(mb, db))) { // They were the same - do not write. sbuf_free_content(mb); sbuf_free_content(db); } else if(pcmp<0) { // Behind in manifest. Write. if(sbuf_to_manifest(mb, nmzp)) goto end; sbuf_free_content(mb); } else { // Behind in deletions file. Do not write. sbuf_free_content(db); } } ret=0; end: if(fzp_close(&nmzp)) { logp("error closing %s in %s\n", manifesttmp, __func__); ret=-1; } fzp_close(&dfp); fzp_close(&omzp); sbuf_free(&db); sbuf_free(&mb); if(!ret) { unlink(fdirs->deletionsfile); // The rename race condition is not a problem here, as long // as manifesttmp is the same path as that generated in the // atomic data jiggle. if(do_rename(manifesttmp, fdirs->manifest)) return -1; } if(manifesttmp) unlink(manifesttmp); return ret; }
static int forward_patch_and_reverse_diff( struct fdirs *fdirs, struct fzp **delfp, const char *deltabdir, const char *deltafdir, const char *deltafpath, const char *sigpath, const char *oldpath, const char *newpath, const char *datapth, const char *finpath, int hardlinked_current, struct sbuf *sb, struct conf **cconfs ) { int lrs; int ret=-1; char *infpath=NULL; // Got a forward patch to do. // First, need to gunzip the old file, otherwise the librsync patch // will take forever, because it will be doing seeks all over the // place, and gzseeks are slow. if(!(infpath=prepend_s(deltafdir, "inflate"))) { log_out_of_memory(__func__); goto end; } //logp("Fixing up: %s\n", datapth); if(inflate_or_link_oldfile(oldpath, infpath, sb->compression, cconfs)) { logp("error when inflating old file: %s\n", oldpath); goto end; } if((lrs=do_patch(NULL, infpath, deltafpath, newpath, sb->compression, sb->compression /* from manifest */))) { logp("WARNING: librsync error when patching %s: %d\n", oldpath, lrs); cntr_add(get_cntr(cconfs), CMD_WARNING, 1); // Try to carry on with the rest of the backup regardless. // Remove anything that got written. unlink(newpath); // First, note that we want to remove this entry from // the manifest. if(!*delfp && !(*delfp=fzp_open(fdirs->deletionsfile, "ab"))) { // Could not mark this file as deleted. Fatal. goto end; } if(sbuf_to_manifest(sb, *delfp)) goto end; if(fzp_flush(*delfp)) { logp("error fflushing deletions file in %s: %s\n", __func__, strerror(errno)); goto end; } ret=0; goto end; } // Need to generate a reverse diff, unless we are keeping a hardlinked // archive. if(!hardlinked_current) { if(gen_rev_delta(sigpath, deltabdir, oldpath, newpath, datapth, sb, cconfs)) goto end; } // Power interruptions should be recoverable. If it happens before this // point, the data jiggle for this file has to be done again. // Once finpath is in place, no more jiggle is required. // Use the fresh new file. // Rename race condition is of no consequence, because finpath will // just get recreated automatically. if(do_rename(newpath, finpath)) goto end; // Remove the forward delta, as it is no longer needed. There is a // reverse diff and the finished finished file is in place. //logp("Deleting delta.forward...\n"); unlink(deltafpath); // Remove the old file. If a power cut happens just before this, the // old file will hang around forever. // FIX THIS: maybe put in something to detect this. // ie, both a reverse delta and the old file exist. if(!hardlinked_current) { //logp("Deleting oldpath...\n"); unlink(oldpath); } ret=0; end: if(infpath) { unlink(infpath); free_w(&infpath); } return ret; }
static int jiggle(struct sdirs *sdirs, struct fdirs *fdirs, struct sbuf *sb, int hardlinked_current, const char *deltabdir, const char *deltafdir, const char *sigpath, struct fzp **delfp, struct conf **cconfs) { int ret=-1; struct stat statp; char *oldpath=NULL; char *newpath=NULL; char *finpath=NULL; char *deltafpath=NULL; const char *datapth=sb->protocol1->datapth.buf; // If the previous backup was a hardlinked_archive, there will not be // a currentdup directory - just directly use the file in the previous // backup. if(!(oldpath=prepend_s(hardlinked_current? sdirs->currentdata:fdirs->currentdupdata, datapth)) || !(newpath=prepend_s(fdirs->datadirtmp, datapth)) || !(finpath=prepend_s(fdirs->datadir, datapth)) || !(deltafpath=prepend_s(deltafdir, datapth))) goto end; if(!lstat(finpath, &statp) && S_ISREG(statp.st_mode)) { // Looks like an interrupted jiggle // did this file already. static int donemsg=0; if(!lstat(deltafpath, &statp) && S_ISREG(statp.st_mode)) { logp("deleting unneeded forward delta: %s\n", deltafpath); unlink(deltafpath); } if(!donemsg) { logp("skipping already present file: %s\n", finpath); logp("to save log space, skips of other already present files will not be logged\n"); donemsg++; } } else if(mkpath(&finpath, fdirs->datadir)) { logp("could not create path for: %s\n", finpath); goto end; } else if(mkpath(&newpath, fdirs->datadirtmp)) { logp("could not create path for: %s\n", newpath); goto end; } else if(!lstat(deltafpath, &statp) && S_ISREG(statp.st_mode)) { int lrs; char *infpath=NULL; // Got a forward patch to do. // First, need to gunzip the old file, // otherwise the librsync patch will take // forever, because it will be doing seeks // all over the place, and gzseeks are slow. if(!(infpath=prepend_s(deltafdir, "inflate"))) { log_out_of_memory(__func__); goto end; } //logp("Fixing up: %s\n", datapth); if(inflate_or_link_oldfile(oldpath, infpath, sb->compression, cconfs)) { logp("error when inflating old file: %s\n", oldpath); free_w(&infpath); goto end; } if((lrs=do_patch(NULL, infpath, deltafpath, newpath, sb->compression, sb->compression /* from manifest */))) { logp("WARNING: librsync error when patching %s: %d\n", oldpath, lrs); cntr_add(get_cntr(cconfs), CMD_WARNING, 1); // Try to carry on with the rest of the backup // regardless. //ret=-1; // Remove anything that got written. unlink(newpath); unlink(infpath); free_w(&infpath); // First, note that we want to remove this entry from // the manifest. if(!*delfp && !(*delfp=fzp_open(fdirs->deletionsfile, "ab"))) { // Could not mark this file as deleted. Fatal. goto end; } if(sbuf_to_manifest(sb, *delfp)) goto end; if(fzp_flush(*delfp)) { logp("error fflushing deletions file in %s: %s\n", __func__, strerror(errno)); goto end; } ret=0; goto end; } // Get rid of the inflated old file. unlink(infpath); free_w(&infpath); // Need to generate a reverse diff, unless we are keeping a // hardlinked archive. if(!hardlinked_current) { if(gen_rev_delta(sigpath, deltabdir, oldpath, newpath, datapth, sb, cconfs)) goto end; } // Power interruptions should be recoverable. If it happens // before this point, the data jiggle for this file has to be // done again. // Once finpath is in place, no more jiggle is required. // Use the fresh new file. // Rename race condition is of no consequence, because finpath // will just get recreated automatically. if(do_rename(newpath, finpath)) goto end; // Remove the forward delta, as it is no longer needed. There // is a reverse diff and the finished finished file is in place. //logp("Deleting delta.forward...\n"); unlink(deltafpath); // Remove the old file. If a power cut happens just before // this, the old file will hang around forever. // FIX THIS: maybe put in something to detect this. // ie, both a reverse delta and the old file exist. if(!hardlinked_current) { //logp("Deleting oldpath...\n"); unlink(oldpath); } } else if(!lstat(newpath, &statp) && S_ISREG(statp.st_mode)) { // Use the fresh new file. // This needs to happen after checking // for the forward delta, because the // patching stuff writes to newpath. // Rename race condition is of no consequence, because finpath // will just get recreated automatically. //logp("Using newly received file\n"); if(do_rename(newpath, finpath)) goto end; } else if(!lstat(oldpath, &statp) && S_ISREG(statp.st_mode)) { // Use the old unchanged file. // Hard link it first. //logp("Hard linking to old file: %s\n", datapth); if(do_link(oldpath, finpath, &statp, cconfs, 0 /* do not overwrite finpath (should never need to) */)) goto end; else { // If we are not keeping a hardlinked // archive, delete the old link. if(!hardlinked_current) { //logp("Unlinking old file: %s\n", oldpath); unlink(oldpath); } } } else { logp("could not find: %s\n", oldpath); goto end; } ret=0; end: free_w(&oldpath); free_w(&newpath); free_w(&finpath); free_w(&deltafpath); return ret; }
static int maybe_delete_files_from_manifest(const char *manifest, const char *deletionsfile, struct config *cconf, struct cntr *cntr) { int ars=0; int ret=0; int pcmp=0; FILE *dfp=NULL; struct sbuf db; struct sbuf mb; gzFile nmzp=NULL; gzFile omzp=NULL; char *manifesttmp=NULL; struct stat statp; if(lstat(deletionsfile, &statp)) { // No deletions, no problem. return 0; } logp("Performing deletions on manifest\n"); if(!(manifesttmp=get_tmp_filename(manifest))) { ret=-1; goto end; } if(!(dfp=open_file(deletionsfile, "rb")) || !(omzp=gzopen_file(manifest, "rb")) || !(nmzp=gzopen_file(manifesttmp, comp_level(cconf)))) { ret=-1; goto end; } init_sbuf(&db); init_sbuf(&mb); while(omzp || dfp) { if(dfp && !db.path && (ars=sbuf_fill(dfp, NULL, &db, cntr))) { if(ars<0) { ret=-1; break; } // ars==1 means it ended ok. close_fp(&dfp); } if(omzp && !mb.path && (ars=sbuf_fill(NULL, omzp, &mb, cntr))) { if(ars<0) { ret=-1; break; } // ars==1 means it ended ok. gzclose_fp(&omzp); } if(mb.path && !db.path) { if(sbuf_to_manifest(&mb, NULL, nmzp)) { ret=-1; break; } free_sbuf(&mb); } else if(!mb.path && db.path) { free_sbuf(&db); } else if(!mb.path && !db.path) { continue; } else if(!(pcmp=sbuf_pathcmp(&mb, &db))) { // They were the same - do not write. free_sbuf(&mb); free_sbuf(&db); } else if(pcmp<0) { // Behind in manifest. Write. if(sbuf_to_manifest(&mb, NULL, nmzp)) { ret=-1; break; } free_sbuf(&mb); } else { // Behind in deletions file. Do not write. free_sbuf(&db); } } end: if(gzclose_fp(&nmzp)) { logp("error closing %s in maybe_delete_files_from_manifest\n", manifesttmp); ret=-1; } close_fp(&dfp); gzclose_fp(&omzp); free_sbuf(&db); free_sbuf(&mb); if(!ret) { unlink(deletionsfile); if(do_rename(manifesttmp, manifest)) { free(manifesttmp); return -1; } } if(manifesttmp) { unlink(manifesttmp); free(manifesttmp); } return ret; }
static int jiggle(const char *datapth, const char *currentdata, const char *datadirtmp, const char *datadir, const char *deltabdir, const char *deltafdir, const char *sigpath, const char *endfile, const char *deletionsfile, FILE **delfp, struct sbuf *sb, int hardlinked, int compression, struct cntr *cntr, struct config *cconf) { int ret=0; struct stat statp; char *oldpath=NULL; char *newpath=NULL; char *finpath=NULL; char *deltafpath=NULL; if(!(oldpath=prepend_s(currentdata, datapth, strlen(datapth))) || !(newpath=prepend_s(datadirtmp, datapth, strlen(datapth))) || !(finpath=prepend_s(datadir, datapth, strlen(datapth))) || !(deltafpath=prepend_s(deltafdir, datapth, strlen(datapth)))) { log_out_of_memory(__FUNCTION__); ret=-1; goto cleanup; } else if(!lstat(finpath, &statp) && S_ISREG(statp.st_mode)) { // Looks like an interrupted jiggle // did this file already. static int donemsg=0; if(!lstat(deltafpath, &statp) && S_ISREG(statp.st_mode)) { logp("deleting unneeded forward delta: %s\n", deltafpath); unlink(deltafpath); } if(!donemsg) { logp("skipping already present file: %s\n", finpath); logp("to save log space, skips of other already present files will not be logged\n"); donemsg++; } } else if(mkpath(&finpath, datadir)) { logp("could not create path for: %s\n", finpath); ret=-1; goto cleanup; } else if(mkpath(&newpath, datadirtmp)) { logp("could not create path for: %s\n", newpath); ret=-1; goto cleanup; } else if(!lstat(deltafpath, &statp) && S_ISREG(statp.st_mode)) { int lrs; char *infpath=NULL; // Got a forward patch to do. // First, need to gunzip the old file, // otherwise the librsync patch will take // forever, because it will be doing seeks // all over the place, and gzseeks are slow. if(!(infpath=prepend_s(deltafdir, "inflate", strlen("inflate")))) { log_out_of_memory(__FUNCTION__); ret=-1; goto cleanup; } //logp("Fixing up: %s\n", datapth); if(inflate_or_link_oldfile(oldpath, infpath, compression, cconf)) { logp("error when inflating old file: %s\n", oldpath); ret=-1; free(infpath); goto cleanup; } if((lrs=do_patch(infpath, deltafpath, newpath, cconf->compression, compression /* from the manifest */, cntr, cconf))) { logp("WARNING: librsync error when patching %s: %d\n", oldpath, lrs); do_filecounter(cntr, CMD_WARNING, 1); // Try to carry on with the rest of the backup // regardless. //ret=-1; // Remove anything that got written. unlink(newpath); unlink(infpath); free(infpath); // First, note that we want to remove this entry from // the manifest. if(!*delfp && !(*delfp=open_file(deletionsfile, "ab"))) { // Could not mark this file as deleted. Fatal. ret=-1; goto cleanup; } if(sbuf_to_manifest(sb, *delfp, NULL)) ret=-1; if(fflush(*delfp)) { logp("error fflushing deletions file in jiggle: %s\n", strerror(errno)); ret=-1; } goto cleanup; } // Get rid of the inflated old file. unlink(infpath); free(infpath); // Need to generate a reverse diff, // unless we are keeping a hardlinked // archive. if(!hardlinked) { if(gen_rev_delta(sigpath, deltabdir, oldpath, newpath, datapth, endfile, compression, cntr, cconf)) { ret=-1; goto cleanup; } } // Power interruptions should be // recoverable. If it happens before // this point, the data jiggle for // this file has to be done again. // Once finpath is in place, no more // jiggle is required. // Use the fresh new file. if(do_rename(newpath, finpath)) { ret=-1; goto cleanup; } else { // Remove the forward delta, as it is // no longer needed. There is a // reverse diff and the finished // finished file is in place. //logp("Deleting delta.forward...\n"); unlink(deltafpath); // Remove the old file. If a power // cut happens just before this, // the old file will hang around // forever. // TODO: Put in something to // detect this. // ie, both a reverse delta and the // old file exist. if(!hardlinked) { //logp("Deleting oldpath...\n"); unlink(oldpath); } } } else if(!lstat(newpath, &statp) && S_ISREG(statp.st_mode)) { // Use the fresh new file. // This needs to happen after checking // for the forward delta, because the // patching stuff writes to newpath. //logp("Using newly received file\n"); if(do_rename(newpath, finpath)) { ret=-1; goto cleanup; } } else if(!lstat(oldpath, &statp) && S_ISREG(statp.st_mode)) { // Use the old unchanged file. // Hard link it first. //logp("Hard linking to old file: %s\n", datapth); if(do_link(oldpath, finpath, &statp, cconf, FALSE /* do not overwrite finpath (should never need to) */)) { ret=-1; goto cleanup; } else { // If we are not keeping a hardlinked // archive, delete the old link. if(!hardlinked) { //logp("Unlinking old file: %s\n", oldpath); unlink(oldpath); } } } else { logp("could not find: %s\n", oldpath); ret=-1; goto cleanup; } cleanup: if(oldpath) { free(oldpath); oldpath=NULL; } if(newpath) { free(newpath); newpath=NULL; } if(finpath) { free(finpath); finpath=NULL; } if(deltafpath) { free(deltafpath); deltafpath=NULL; } return ret; }
// returns 1 for finished ok. static int do_stuff_to_receive(struct sbuf *rb, FILE *p2fp, const char *datadirtmp, struct dpth *dpth, const char *working, char **last_requested, const char *deltmppath, struct cntr *cntr, struct config *cconf) { int ret=0; char rcmd; size_t rlen=0; size_t wlen=0; char *rbuf=NULL; // This also attempts to write anything in the write buffer. if(async_rw(&rcmd, &rbuf, &rlen, '\0', NULL, &wlen)) { logp("error in async_rw\n"); return -1; } if(rbuf) { if(rcmd==CMD_WARNING) { logp("WARNING: %s\n", rbuf); do_filecounter(cntr, rcmd, 0); } else if(rb->fp || rb->zp) { // Currently writing a file (or meta data) if(rcmd==CMD_APPEND) { int app; //logp("rlen: %d\n", rlen); if((rb->zp && (app=gzwrite(rb->zp, rbuf, rlen))<=0) || (rb->fp && (app=fwrite(rbuf, 1, rlen, rb->fp))<=0)) { logp("error when appending: %d\n", app); async_write_str(CMD_ERROR, "write failed"); ret=-1; } do_filecounter_recvbytes(cntr, rlen); } else if(rcmd==CMD_END_FILE) { // Finished the file. // Write it to the phase2 file, and free the // buffers. if(close_fp(&(rb->fp))) { logp("error closing delta for %s in receive\n", rb->path); ret=-1; } if(gzclose_fp(&(rb->zp))) { logp("error gzclosing delta for %s in receive\n", rb->path); ret=-1; } rb->endfile=rbuf; rb->elen=rlen; rbuf=NULL; if(!ret && rb->receivedelta && finish_delta(rb, working, deltmppath)) ret=-1; else if(!ret) { if(sbuf_to_manifest(rb, p2fp, NULL)) ret=-1; else { char cmd=rb->cmd; if(rb->receivedelta) do_filecounter_changed(cntr, cmd); else do_filecounter(cntr, cmd, 0); if(*last_requested && !strcmp(rb->path, *last_requested)) { free(*last_requested); *last_requested=NULL; } } } if(!ret) { char *cp=NULL; cp=strchr(rb->endfile, ':'); if(rb->endfile) do_filecounter_bytes(cntr, strtoull(rb->endfile, NULL, 10)); if(cp) { // checksum stuff goes here } } free_sbuf(rb); } else { logp("unexpected cmd from client while writing file: %c %s\n", rcmd, rbuf); ret=-1; } } // Otherwise, expecting to be told of a file to save. else if(rcmd==CMD_DATAPTH) { rb->datapth=rbuf; rbuf=NULL; } else if(rcmd==CMD_STAT) { rb->statbuf=rbuf; rb->slen=rlen; rbuf=NULL; } else if(filedata(rcmd)) { rb->cmd=rcmd; rb->plen=rlen; rb->path=rbuf; rbuf=NULL; if(rb->datapth) { // Receiving a delta. if(start_to_receive_delta(rb, working, deltmppath, cconf)) { logp("error in start_to_receive_delta\n"); ret=-1; } } else { // Receiving a whole new file. if(start_to_receive_new_file(rb, datadirtmp, dpth, cntr, cconf)) { logp("error in start_to_receive_new_file\n"); ret=-1; } } } else if(rcmd==CMD_GEN && !strcmp(rbuf, "okbackupphase2end")) { ret=1; //logp("got okbackupphase2end\n"); } else if(rcmd==CMD_INTERRUPT) { // Interrupt - forget about the last requested file // if it matches. Otherwise, we can get stuck on the // select in the async stuff, waiting for something // that will never arrive. if(*last_requested && !strcmp(rbuf, *last_requested)) { free(*last_requested); *last_requested=NULL; } } else { logp("unexpected cmd from client while expecting a file: %c %s\n", rcmd, rbuf); ret=-1; } if(rbuf) { free(rbuf); rbuf=NULL; } } //logp("returning: %d\n", ret); return ret; }