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; }
/* * State of reading a block and trying to generate its sum. */ static rs_result rs_sig_s_generate(rs_job_t *job) { rs_result result; size_t len; void *block; /* must get a whole block, otherwise try again */ len = job->block_len; result = rs_scoop_read(job, len, &block); /* unless we're near eof, in which case we'll accept * whatever's in there */ if ((result == RS_BLOCKED && rs_job_input_is_ending(job))) { result = rs_scoop_read_rest(job, &len, &block); } else if (result == RS_INPUT_ENDED) { return RS_DONE; } else if (result != RS_DONE) { rs_trace("generate stopped: %s", rs_strerror(result)); return result; } rs_trace("got %ld byte block", (long) len); return rs_sig_do_block(job, block, len); }
int main(int argc, char *argv[]) { FILE *basis_file; FILE *delta_file; rs_result ret; FILE *new_file; rs_stats_t stats; if(argc != 4) { fprintf(stderr, "invalid argument(s)\n"); exit(1); } basis_file = fopen(argv[1], "rb"); delta_file = fopen(argv[2], "rb"); new_file = fopen(argv[3], "wb"); ret = rs_patch_file(basis_file, delta_file, new_file, &stats); fclose(basis_file); fclose(delta_file); fclose(new_file); if(ret != RS_DONE) { puts(rs_strerror(ret)); exit(1); } rs_log_stats(&stats); return 0; }
static ERL_NIF_TERM format_error(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { unsigned len; int res; if (!enif_get_atom_length(env, argv[0], &len, ERL_NIF_LATIN1)) return enif_make_badarg(env); char *atom = malloc(len+1); if (!enif_get_atom(env, argv[0], atom, len+1, ERL_NIF_LATIN1)) { free(atom); return enif_make_badarg(env); } if (!strcmp("done", atom)) res = RS_DONE; else if (!strcmp("blocked", atom)) res = RS_BLOCKED; else if (!strcmp("running", atom)) res = RS_RUNNING; else if (!strcmp("test_skipped", atom)) res = RS_TEST_SKIPPED; else if (!strcmp("io_error", atom)) res = RS_IO_ERROR; else if (!strcmp("syntax_error", atom)) res = RS_SYNTAX_ERROR; else if (!strcmp("mem_error", atom)) res = RS_MEM_ERROR; else if (!strcmp("input_ended", atom)) res = RS_INPUT_ENDED; else if (!strcmp("bad_magic", atom)) res = RS_BAD_MAGIC; else if (!strcmp("unimplemented", atom)) res = RS_UNIMPLEMENTED; else if (!strcmp("corrupt", atom)) res = RS_CORRUPT; else if (!strcmp("internal_error", atom)) res = RS_INTERNAL_ERROR; else if (!strcmp("param_error", atom)) res = RS_PARAM_ERROR; else res = -1; free(atom); return enif_make_string(env, rs_strerror(res), ERL_NIF_LATIN1); }
// Also used by restore.c. // FIX THIS: This stuff is very similar to make_rev_delta, can maybe share // some code. int do_patch(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; if((result=rs_patch_gzfile(dstp, delfzp, upfzp))!=RS_DONE) { logp("rs_patch_gzfile returned %d %s\n", result, rs_strerror(result)); } 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; }
int main(const int argc, const char *argv[]) { poptContext opcon; rs_result result; opcon = poptGetContext(PROGRAM, argc, argv, opts, 0); rdiff_options(opcon); result = rdiff_action(opcon); if (result != RS_DONE) rs_log(RS_LOG_ERR|RS_LOG_NONAME, "%s", rs_strerror(result)); return result; }
/** * Called when we're executing a COPY command and waiting for all the * data to be retrieved from the callback. */ static rs_result rs_patch_s_copying(rs_job_t *job) { rs_result result; size_t desired_len, len; void *ptr; rs_buffers_t *buffs = job->stream; /* copy only as much as will fit in the output buffer, so that we * don't have to block or store the input. */ desired_len = len = (buffs->avail_out < job->basis_len) ? buffs->avail_out : job->basis_len; if (!len) return RS_BLOCKED; rs_trace("copy " PRINTF_FORMAT_U64 " bytes from basis at offset " PRINTF_FORMAT_U64 "", PRINTF_CAST_U64(len), PRINTF_CAST_U64(job->basis_pos)); ptr = buffs->next_out; result = (job->copy_cb)(job->copy_arg, job->basis_pos, &len, &ptr); if (result != RS_DONE) return result; else rs_trace("copy callback returned %s", rs_strerror(result)); rs_trace("got " PRINTF_FORMAT_U64 " bytes back from basis callback", PRINTF_CAST_U64(len)); if (len > desired_len) { rs_trace("warning: copy_cb returned more than the requested length."); len = desired_len; } /* copy back to out buffer only if the callback has used its own buffer */ if (ptr != buffs->next_out) memcpy(buffs->next_out, ptr, len); buffs->next_out += len; buffs->avail_out -= len; job->basis_pos += len; job->basis_len -= len; if (!job->basis_len) { /* Done! */ job->statefn = rs_patch_s_cmdbyte; } return RS_RUNNING; }
/** * Called when we're executing a COPY command and waiting for all the * data to be retrieved from the callback. */ static rs_result rs_patch_s_copying(rs_job_t *job) { rs_result result; size_t len; void *buf, *ptr; rs_buffers_t *buffs = job->stream; len = job->basis_len; /* copy only as much as will fit in the output buffer, so that we * don't have to block or store the input. */ if (len > buffs->avail_out) len = buffs->avail_out; if (!len) return RS_BLOCKED; rs_trace("copy " PRINTF_FORMAT_U64 " bytes from basis at offset " PRINTF_FORMAT_U64 "", PRINTF_CAST_U64(len), PRINTF_CAST_U64(job->basis_pos)); ptr = buf = rs_alloc(len, "basis buffer"); result = (job->copy_cb)(job->copy_arg, job->basis_pos, &len, &ptr); if (result != RS_DONE) return result; else rs_trace("copy callback returned %s", rs_strerror(result)); rs_trace("got " PRINTF_FORMAT_U64 " bytes back from basis callback", PRINTF_CAST_U64(len)); memcpy(buffs->next_out, ptr, len); buffs->next_out += len; buffs->avail_out -= len; job->basis_pos += len; job->basis_len -= len; free(buf); if (!job->basis_len) { /* Done! */ job->statefn = rs_patch_s_cmdbyte; } return RS_RUNNING; }
static rs_result rs_job_complete(rs_job_t *job, rs_result result) { rs_job_check(job); job->statefn = rs_job_s_complete; job->final_result = result; if (result != RS_DONE) { rs_error("%s job failed: %s", job->job_name, rs_strerror(result)); } else { rs_trace("%s job complete", job->job_name); } if (result == RS_DONE && !rs_tube_is_idle(job)) /* Processing is finished, but there is still some data * waiting to get into the output buffer. */ return RS_BLOCKED; else return result; }
static int make_rev_sig(const char *dst, const char *sig, const char *endfile, int compression, struct conf **confs) { int ret=-1; rs_result result; 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"))) goto end; if((result=rs_sig_gzfile(dstfzp, sigp, get_librsync_block_len(endfile), PROTO1_RS_STRONG_LEN, confs)!=RS_DONE)) { logp("rs_sig_gzfile returned %d %s\n", result, rs_strerror(result)); 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; }
void send_file_delta(const char* new_file_path, const char *sig_file_path, SSL *ssl) { FILE *sig_file; FILE *new_file; FILE *delta_file; size_t result = 0; const size_t max_buffer_size = 1024; char delta_buffer[max_buffer_size]; uint64_t delta_length = 0; rs_result ret; rs_signature_t *sumset; rs_stats_t stats; sig_file = fopen(sig_file_path,"rb"); if(sig_file == NULL) { fprintf(stderr, "failed to open signature file '%s'\n", sig_file_path); exit(1); } new_file = fopen(new_file_path,"rb"); if(new_file == NULL) { fclose(sig_file); fprintf(stderr, "failed to open file '%s'\n", new_file_path); exit(1); } delta_file = tmpfile(); if(delta_file == NULL) { fclose(sig_file); fclose(new_file); fprintf(stderr, "failed to create temporary file\n"); exit(1); } ret = rs_loadsig_file(sig_file, &sumset, &stats); if(ret != RS_DONE) { puts(rs_strerror(ret)); exit(1); } rs_log_stats(&stats); if(rs_build_hash_table(sumset) != RS_DONE) { puts(rs_strerror(ret)); exit(1); } if(rs_delta_file(sumset, new_file, delta_file, &stats) != RS_DONE) { puts(rs_strerror(ret)); exit(1); } fflush(delta_file); do { struct stat buf; if(fstat(fileno(delta_file), &buf) < 0) { perror("fstat"); exit(1); } delta_length = (uint64_t)buf.st_size; }while(0); rewind(delta_file); delta_length = hton64(delta_length); ssl_write_wrapper(ssl, new_file_path, strlen(new_file_path) + 1); ssl_write_wrapper(ssl, &delta_length, 8); while(!feof(delta_file)) { result = fread(delta_buffer, 1, max_buffer_size, delta_file); if(result > 0) ssl_write_wrapper(ssl, delta_buffer, result); } rs_log_stats(&stats); rs_free_sumset(sumset); fclose(sig_file); fclose(new_file); fclose(delta_file); }