static int full_match(struct file *o, struct file *n, struct fzp **ofp, struct fzp **nfp) { size_t ogot; size_t ngot; unsigned int i=0; static char obuf[FULL_CHUNK]; static char nbuf[FULL_CHUNK]; if(*ofp) fzp_seek(*ofp, 0, SEEK_SET); else if(!(*ofp=fzp_open(o->path, "rb"))) { // Blank this entry so that it can be ignored from // now on. free_w(&o->path); return 0; } if(*nfp) fzp_seek(*nfp, 0, SEEK_SET); else if(!(*nfp=fzp_open(n->path, "rb"))) return 0; while(1) { ogot=fzp_read(*ofp, obuf, FULL_CHUNK); ngot=fzp_read(*nfp, nbuf, FULL_CHUNK); if(ogot!=ngot) return 0; for(i=0; i<ogot; i++) if(obuf[i]!=nbuf[i]) return 0; if(ogot<FULL_CHUNK) break; } return 1; }
static int incexc_matches(const char *fullrealwork, const char *incexc) { int ret=0; int got=0; struct fzp *fzp=NULL; char buf[4096]=""; const char *inc=NULL; char *old_incexc_path=NULL; if(!(old_incexc_path=prepend_s(fullrealwork, "incexc"))) return -1; if(!(fzp=fzp_open(old_incexc_path, "rb"))) { // Assume that no incexc file could be found because the client // was on an old version. Assume resume is OK and return 1. ret=1; goto end; } inc=incexc; while((got=fzp_read(fzp, buf, sizeof(buf)))>0) { if(strlen(inc)<(size_t)got) break; if(strncmp(buf, inc, got)) break; inc+=got; } if(inc && strlen(inc)) ret=0; else ret=1; end: fzp_close(&fzp); free_w(&old_incexc_path); return ret; }
static int duplicate_file(const char *oldpath, const char *newpath) { int ret=-1; size_t s=0; size_t t=0; struct fzp *op=NULL; struct fzp *np=NULL; char buf[DUP_CHUNK]=""; if(!(op=fzp_open(oldpath, "rb")) || !(np=fzp_open(newpath, "wb"))) goto end; while((s=fzp_read(op, buf, DUP_CHUNK))>0) { t=fzp_write(np, buf, s); if(t!=s) { logp("could not write all bytes: %lu!=%lu\n", (unsigned long)s, (unsigned long)t); goto end; } } ret=0; end: fzp_close(&np); fzp_close(&op); if(ret) logp("could not duplicate %s to %s\n", oldpath, newpath); 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; }
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); }
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 fzp_read_ensure(struct fzp *fzp, void *ptr, size_t nmemb, const char *func) { static int f; static int r; static size_t got; static int pass; for(r=0, got=0, pass=0; got!=nmemb; pass++) { r=fzp_read(fzp, ((char *)ptr)+got, nmemb-got); if(r>0) { got+=r; continue; } if(r<0) { pass_msg(nmemb, got, pass); logp("Error in %s, called from %s: %s\n", __func__, func, strerror(errno)); return -1; } f=fzp_eof(fzp); if(!f) continue; // Not yet end of file, keep trying. if(f>0) { // End of file. if(!got) return 1; pass_msg(nmemb, got, pass); logp("Error in %s, called from %s: %u bytes, eof\n", __func__, func, got); return -1; } else { pass_msg(nmemb, got, pass); logp("Error in %s by fzp_feof, called from %s: %s\n", __func__, func, strerror(errno)); return -1; } } return 0; }
static int get_part_cksum(struct file *f, struct fzp **fzp) { MD5_CTX md5; int got=0; static char buf[PART_CHUNK]; unsigned char checksum[MD5_DIGEST_LENGTH+1]; if(*fzp) fzp_seek(*fzp, 0, SEEK_SET); else if(!(*fzp=fzp_open(f->path, "rb"))) { f->part_cksum=0; return 0; } if(!MD5_Init(&md5)) { logp("MD5_Init() failed\n"); return -1; } got=fzp_read(*fzp, buf, PART_CHUNK); if(!MD5_Update(&md5, buf, got)) { logp("MD5_Update() failed\n"); return -1; } if(!MD5_Final(checksum, &md5)) { logp("MD5_Final() failed\n"); return -1; } memcpy(&(f->part_cksum), checksum, sizeof(unsigned)); // Try for a bit of efficiency - no need to calculate the full checksum // again if we already read the whole file. if(got<PART_CHUNK) f->full_cksum=f->part_cksum; return 0; }
static int get_full_cksum(struct file *f, struct fzp **fzp) { size_t s=0; MD5_CTX md5; static char buf[FULL_CHUNK]; unsigned char checksum[MD5_DIGEST_LENGTH+1]; if(*fzp) fzp_seek(*fzp, 0, SEEK_SET); else if(!(*fzp=fzp_open(f->path, "rb"))) { f->full_cksum=0; return 0; } if(!MD5_Init(&md5)) { logp("MD5_Init() failed\n"); return -1; } while((s=fzp_read(*fzp, buf, FULL_CHUNK))>0) { if(!MD5_Update(&md5, buf, s)) { logp("MD5_Update() failed\n"); return -1; } if(s<FULL_CHUNK) break; } if(!MD5_Final(checksum, &md5)) { logp("MD5_Final() failed\n"); return -1; } memcpy(&(f->full_cksum), checksum, sizeof(unsigned)); return 0; }
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; }
/* * If the stream has no more data available, read some from F into * BUF, and let the stream use that. On return, SEEN_EOF is true if * the end of file has passed into the stream. */ rs_result rs_infilebuf_fill(rs_job_t *job, rs_buffers_t *buf, void *opaque) { int len=0; rs_filebuf_t *fb=(rs_filebuf_t *) opaque; struct cntr *cntr; int fd=fb->fd; cntr=fb->cntr; //logp("rs_infilebuf_fill\n"); /* This is only allowed if either the buf has no input buffer * yet, or that buffer could possibly be BUF. */ if(buf->next_in) { //logp("infilebuf avail_in %d buf_len %d\n", // buf->avail_in, fb->buf_len); if(buf->avail_in > fb->buf_len) { logp("buf->avail_in > fb->buf_len (%d > %d) in %s\n", buf->avail_in, fb->buf_len, __func__); return RS_IO_ERROR; } if(buf->next_in < fb->buf) { logp("buf->next_in < fb->buf in %s\n", __func__); return RS_IO_ERROR; } if(buf->next_in > fb->buf + fb->buf_len) { logp("buf->next_in > fb->buf + fb->buf_len in %s\n", __func__); return RS_IO_ERROR; } } else { if(buf->avail_in) { logp("buf->avail_in is %d in %s\n", buf->avail_in, __func__); return RS_IO_ERROR; } } if(buf->eof_in) return RS_DONE; if(buf->avail_in) /* Still some data remaining. Perhaps we should read anyhow? */ return RS_DONE; if(fd>=0) { static struct iobuf *rbuf=NULL; rbuf=fb->asfd->rbuf; if(fb->asfd->read(fb->asfd)) return RS_IO_ERROR; if(rbuf->cmd==CMD_APPEND) { //logp("got '%c' in fd infilebuf: %d\n", // CMD_APPEND, rbuf->len); memcpy(fb->buf, rbuf->buf, rbuf->len); len=rbuf->len; iobuf_free_content(rbuf); } else if(rbuf->cmd==CMD_END_FILE) { iobuf_free_content(rbuf); //logp("got %c in fd infilebuf\n", CMD_END_FILE); buf->eof_in=1; return RS_DONE; } else if(rbuf->cmd==CMD_WARNING) { logp("WARNING: %s\n", rbuf->buf); cntr_add(cntr, rbuf->cmd, 0); iobuf_free_content(rbuf); return RS_DONE; } else { iobuf_log_unexpected(rbuf, __func__); iobuf_free_content(rbuf); return RS_IO_ERROR; } } else if(fb->bfd) { if(fb->do_known_byte_count) { if(fb->data_len>0) { len=fb->bfd->read(fb->bfd, fb->buf, min(fb->buf_len, fb->data_len)); fb->data_len-=len; } else { // We have already read as much data as the VSS // header told us to, so set len=0 in order to // finish up. len=0; } } else len=fb->bfd->read(fb->bfd, fb->buf, fb->buf_len); if(len==0) { //logp("bread: eof\n"); buf->eof_in=1; return RS_DONE; } else if(len<0) { logp("rs_infilebuf_fill: error in bread\n"); return RS_IO_ERROR; } //logp("bread: ok: %d\n", len); fb->bytes+=len; if(!MD5_Update(&(fb->md5), fb->buf, len)) { logp("rs_infilebuf_fill: MD5_Update() failed\n"); return RS_IO_ERROR; } } else if(fb->fzp) { if((len=fzp_read(fb->fzp, fb->buf, fb->buf_len))<=0) { // This will happen if file size is a multiple of // input block len. if(fzp_eof(fb->fzp)) { buf->eof_in=1; return RS_DONE; } else { logp("rs_infilebuf_fill: got return %d when trying to read\n", len); return RS_IO_ERROR; } } fb->bytes+=len; if(!MD5_Update(&(fb->md5), fb->buf, len)) { logp("rs_infilebuf_fill: MD5_Update() failed\n"); return RS_IO_ERROR; } } buf->avail_in = len; buf->next_in = fb->buf; return RS_DONE; }