static int manio_open_last_fpath(struct manio *manio) { int max=-1; if(is_single_file(manio)) return manio_open_next_fpath(manio); if(get_highest_entry(manio->manifest, &max, 8)) return -1; if(max<0) max=0; manio->offset->fcount=(uint64_t)max; return manio_open_next_fpath(manio); }
// Return -1 for error, 0 for stuff read OK, 1 for end of files. int manio_read_with_blk(struct manio *manio, struct sbuf *sb, struct blk *blk, struct sdirs *sdirs) { while(1) { if(!manio->fzp) { if(manio_open_next_fpath(manio)) goto error; if(!manio->fzp) return 1; // No more files to read. } switch(sbuf_fill_from_file(sb, manio->fzp, blk, sdirs?sdirs->data:NULL)) { case 0: return 0; // Got something. case 1: break; // Keep going. default: goto error; // Error. } // Reached the end of the current file. // Maybe there is another file to continue with. if(sort_and_write_hooks_and_dindex(manio) || fzp_close(&manio->fzp)) goto error; if(is_single_file(manio)) return 1; } error: return -1; }
static struct manio *do_manio_open(const char *manifest, const char *mode, enum protocol protocol, int phase) { struct manio *manio=NULL; if(!(manio=manio_alloc()) || !(manio->manifest=strdup_w(manifest, __func__)) || !(manio->mode=strdup_w(mode, __func__)) || !(manio->offset=man_off_t_alloc())) goto error; manio->protocol=protocol; manio->phase=phase; if(!strcmp(manio->mode, MANIO_MODE_APPEND)) { if(manio->phase!=2) { logp("manio append mode only works for phase 2.\n"); logp("%s has phase: %s\n", manio->manifest, manio->phase); goto error; } if(manio_open_last_fpath(manio)) goto error; } else { if(manio_open_next_fpath(manio)) goto error; } return manio; error: manio_close(&manio); return NULL; }
static int write_sig_msg(struct manio *manio, struct blk *blk) { struct iobuf wbuf; if(!manio->fzp && manio_open_next_fpath(manio)) return -1; blk_to_iobuf_sig_and_savepath(blk, &wbuf); if(iobuf_send_msg_fzp(&wbuf, manio->fzp)) return -1; return check_sig_count(manio, blk); }
static int reset_sig_count_and_close(struct manio *manio) { if(sort_and_write_hooks_and_dindex(manio)) return -1; if(fzp_close(&manio->fzp)) return -1; manio->sig_count=0; if(manio_open_next_fpath(manio)) return -1; return 0; }
// Return -1 for error, 0 for stuff read OK, 1 for end of files. static int do_manio_sbuf_fill(struct manio *manio, struct asfd *asfd, struct sbuf *sb, struct blk *blk, struct sdirs *sdirs, struct conf **confs, int phase1) { int ars; while(1) { if(!manio->fzp) { if(manio_open_next_fpath(manio)) goto error; if(!manio->fzp) return 1; // No more files to read. } if(manio->protocol==PROTO_2 || phase1) { ars=sbuf_fill(sb, asfd, manio->fzp, blk, sdirs?sdirs->data:NULL, confs); } else { ars=sbufl_fill(sb, asfd, manio->fzp, confs); } switch(ars) { case 0: return 0; // Got something. case 1: break; // Keep going. default: goto error; // Error. } // Reached the end of the current file. // Maybe there is another file to continue with. if(manio_close(manio)) goto error; // If in protocol1 mode, there is only one file, so end. if(manio->protocol==PROTO_1) return 1; } error: manio_close(manio); return -1; }
// Return -1 on error, 0 on OK, 1 for srcmanio finished. int manio_copy_entry(struct sbuf *csb, struct sbuf *sb, struct blk **blk, struct manio *srcmanio, struct manio *dstmanio) { static int ars; static char *copy=NULL; // Use the most recent stat for the new manifest. if(dstmanio) { if(manio_write_sbuf(dstmanio, sb)) goto error; if(dstmanio->protocol==PROTO_1) { sbuf_free_content(csb); return 0; } } if(!(copy=strdup_w(csb->path.buf, __func__))) goto error; while(1) { if((ars=manio_read_with_blk(srcmanio, csb, *blk, NULL))<0) goto error; else if(ars>0) { // Finished. sbuf_free_content(csb); blk_free(blk); free_w(©); return 1; } // Got something. if(strcmp(csb->path.buf, copy)) { // Found the next entry. free_w(©); return 0; } if(dstmanio) { if(!dstmanio->fzp && manio_open_next_fpath(dstmanio)) return -1; if(csb->endfile.buf) { if(iobuf_send_msg_fzp(&csb->endfile, dstmanio->fzp)) goto error; } else { // Should have the next signature. // Write it to the destination manifest. if(manio_write_sig_and_path(dstmanio, *blk)) goto error; } } } error: free_w(©); 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); }
int backup_phase2_server_protocol1(struct async *as, struct sdirs *sdirs, const char *incexc, int resume, struct conf **cconfs) { int ret=0; struct manio *p1manio=NULL; struct dpth *dpth=NULL; char *deltmppath=NULL; char *last_requested=NULL; // Where to write changed data. // Data is not getting written to a compressed file. // This is important for recovery if the power goes. struct fzp *chfp=NULL; struct fzp *ucfp=NULL; // unchanged data struct fzp *cmanfp=NULL; // previous (current) manifest. struct sbuf *cb=NULL; // file list in current manifest struct sbuf *p1b=NULL; // file list from client struct sbuf *rb=NULL; // receiving file from client struct asfd *asfd=as->asfd; int breaking=0; int breakcount=0; if(get_int(cconfs[OPT_BREAKPOINT])>=2000 && get_int(cconfs[OPT_BREAKPOINT])<3000) { breaking=get_int(cconfs[OPT_BREAKPOINT]); breakcount=breaking-2000; } logp("Begin phase2 (receive file data)\n"); if(!(dpth=dpth_alloc()) || dpth_protocol1_init(dpth, sdirs->currentdata, get_int(cconfs[OPT_MAX_STORAGE_SUBDIRS]))) goto error; if(open_previous_manifest(&cmanfp, sdirs, incexc, cconfs)) goto error; if(get_int(cconfs[OPT_DIRECTORY_TREE])) { // Need to make sure we do not try to create a path that is // too long. if(build_path_w(sdirs->treepath)) goto error; treepathlen=strlen(sdirs->treepath); init_fs_max(sdirs->treepath); } if(!(p1manio=manio_alloc()) || manio_init_read(p1manio, sdirs->phase1data) || !(cb=sbuf_alloc(cconfs)) || !(p1b=sbuf_alloc(cconfs)) || !(rb=sbuf_alloc(cconfs))) goto error; manio_set_protocol(p1manio, PROTO_1); if(resume && do_resume(p1manio, sdirs, dpth, cconfs)) goto error; // Unchanged and changed should now be truncated correctly, we just // have to open them for appending. if(!(ucfp=fzp_open(sdirs->unchanged, "a+b")) || !(chfp=fzp_open(sdirs->changed, "a+b"))) goto error; if(manio_closed(p1manio) && manio_open_next_fpath(p1manio)) goto error; while(1) { if(breaking) { if(breakcount--==0) return breakpoint(cconfs, __func__); } //printf("in loop, %s %s %c\n", // cmanfp?"got cmanfp":"no cmanfp", // rb->path.buf?:"no rb->path", // rb->path.buf?'X':rb->path.cmd); if(write_status(CNTR_STATUS_BACKUP, rb->path.buf?rb->path.buf:p1b->path.buf, cconfs)) goto error; if(last_requested || manio_closed(p1manio) || asfd->writebuflen) { switch(do_stuff_to_receive(asfd, sdirs, cconfs, rb, chfp, dpth, &last_requested)) { case 0: break; case 1: goto end; // Finished ok. case -1: goto error; } } switch(do_stuff_to_send(asfd, p1b, &last_requested)) { case 0: break; case 1: continue; case -1: goto error; } if(manio_closed(p1manio)) continue; sbuf_free_content(p1b); switch(manio_sbuf_fill_phase1(p1manio, asfd, p1b, NULL, sdirs, cconfs)) { case 0: break; case 1: manio_close(p1manio); if(asfd->write_str(asfd, CMD_GEN, "backupphase2end")) goto error; break; case -1: goto error; } if(!cmanfp) { // No old manifest, need to ask for a new file. if(process_new(sdirs, cconfs, p1b, ucfp)) goto error; continue; } // Have an old manifest, look for it there. // Might already have it, or be ahead in the old // manifest. if(cb->path.buf) switch(maybe_process_file(asfd, sdirs, cb, p1b, ucfp, cconfs)) { case 0: break; case 1: continue; case -1: goto error; } while(cmanfp) { sbuf_free_content(cb); switch(sbufl_fill(cb, asfd, cmanfp, cconfs)) { case 0: break; case 1: fzp_close(&cmanfp); if(process_new(sdirs, cconfs, p1b, ucfp)) goto error; continue; case -1: goto error; } switch(maybe_process_file(asfd, sdirs, cb, p1b, ucfp, cconfs)) { case 0: continue; case 1: break; case -1: goto error; } break; } } error: ret=-1; end: if(fzp_close(&chfp)) { logp("error closing %s in %s\n", sdirs->changed, __func__); ret=-1; } if(fzp_close(&ucfp)) { logp("error closing %s in %s\n", sdirs->unchanged, __func__); ret=-1; } free_w(&deltmppath); sbuf_free(&cb); sbuf_free(&p1b); sbuf_free(&rb); manio_free(&p1manio); fzp_close(&cmanfp); dpth_free(&dpth); if(!ret) unlink(sdirs->phase1data); logp("End phase2 (receive file data)\n"); return ret; }
static int write_sig_msg(struct manio *manio, const char *msg) { if(!manio->fzp && manio_open_next_fpath(manio)) return -1; if(send_msg_fzp(manio->fzp, CMD_SIG, msg, strlen(msg))) return -1; return check_sig_count(manio, msg); }