// Return -1 for error, 0 for entry not changed, 1 for entry changed (or new). static int entry_changed(struct sbuf *sb, struct manios *manios, struct asfd *chfd, struct sbuf **csb) { static int finished=0; static struct blk *blk=NULL; if(finished) return 1; if((*csb)->path.buf) { // Already have an entry. } else { // Need to read another. if(!blk && !(blk=blk_alloc())) return -1; switch(manio_read_with_blk(manios->current, *csb, blk, NULL)) { case 1: // Reached the end. sbuf_free(csb); blk_free(&blk); finished=1; return 1; case -1: return -1; } if(!(*csb)->path.buf) { logp("Should have a path at this point, but do not, in %s\n", __func__); return -1; } // Got an entry. } while(1) { switch(sbuf_pathcmp(*csb, sb)) { case 0: return found_in_current_manifest(*csb, sb, manios, &blk, chfd); case 1: return 1; case -1: // Behind - need to read more data from the old // manifest. switch(manio_read_with_blk(manios->current, *csb, blk, NULL)) { case 1: // Reached the end. sbuf_free(csb); blk_free(&blk); return 1; case -1: return -1; } // Got something, go back around the loop. } } return 0; }
// 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_read(struct manio *manio, struct sbuf *sb) { return manio_read_with_blk(manio, sb, NULL, NULL); }
// FIX THIS: Far too complicated. static void read_manifest(struct sbuf **sb_expected, struct manio *manio, int start, int finish, enum protocol protocol, int phase) { int i=start; struct sbuf *rb=NULL; struct blk *blk=NULL; struct blk *blk_expected=NULL; struct blk *blk_expected_end=NULL; fail_unless((rb=sbuf_alloc(protocol))!=NULL); fail_unless((blk=blk_alloc())!=NULL); if(protocol==PROTO_2) { blk_expected=(*sb_expected)->protocol2->bstart; blk_expected_end=(*sb_expected)->protocol2->bend; } while(1) { switch(manio_read_with_blk(manio, rb, blk, NULL)) { case 0: break; case 1: goto end; default: fail_unless(0); } if(protocol==PROTO_2) { if(rb->endfile.buf) { sbuf_free_content(rb); if(i==finish) { fail_unless(!blk_expected); break; } continue; } if(blk->got_save_path) { assert_blk(blk_expected, blk); blk->got_save_path=0; // Need to suck up all the sigs before exiting. if(i==finish && blk_expected->next==blk_expected_end) break; blk_expected=blk_expected->next; continue; } } assert_sbuf(*sb_expected, rb, protocol); sbuf_free_content(rb); if(protocol==PROTO_2) { blk_expected=(*sb_expected)->protocol2->bstart; blk_expected_end=(*sb_expected)->protocol2->bend; } i++; if(i==finish) { if(protocol==PROTO_1 || phase==1 || !sbuf_is_filedata(*sb_expected)) { *sb_expected=(*sb_expected)->next; break; } } *sb_expected=(*sb_expected)->next; } end: sbuf_free(&rb); blk_free(&blk); }
/* This function reads the manifest to determine whether it may be more efficient to just copy the data files across and unpack them on the other side. If it thinks it is, it will then do it. Return -1 on error, 1 if it copied the data across, 0 if it did not. */ int maybe_restore_spool(struct asfd *asfd, const char *manifest, struct sdirs *sdirs, struct bu *bu, int srestore, regex_t *regex, struct conf **confs, struct slist *slist, enum action act, enum cntr_status cntr_status) { int ars; int ret=-1; struct sbuf *sb=NULL; struct blk *blk=NULL; struct manio *manio=NULL; uint64_t blkcount=0; uint64_t datcount=0; struct hash_weak *tmpw; struct hash_weak *hash_weak; uint64_t estimate_blks; uint64_t estimate_dats; uint64_t estimate_one_dat; struct sbuf *need_data=NULL; int last_ent_was_dir=0; char sig[128]=""; const char *restore_spool=get_string(confs[OPT_RESTORE_SPOOL]); // If the client has no restore_spool directory, we have to fall back // to the stream style restore. if(!restore_spool) return 0; if(!(manio=manio_open(manifest, "rb", PROTO_2)) || !(need_data=sbuf_alloc(PROTO_2)) || !(sb=sbuf_alloc(PROTO_2)) || !(blk=blk_alloc())) goto end; while(1) { if((ars=manio_read_with_blk(manio, sb, blk, NULL))<0) { logp("Error from manio_read_async() in %s\n", __func__); goto end; // Error; } else if(ars>0) break; // Finished OK. if(!blk->got_save_path) { sbuf_free_content(sb); continue; } if(want_to_restore(srestore, sb, regex, confs)) { blkcount++; if(!hash_weak_find((uint64_t)blk->savepath)) { if(!hash_weak_add((uint64_t)blk->savepath)) goto end; datcount++; } } sbuf_free_content(sb); } // FIX THIS: should read rabin_avg of a struct rconf. estimate_blks=blkcount*RABIN_AVG; estimate_one_dat=DATA_FILE_SIG_MAX*RABIN_AVG; estimate_dats=datcount*estimate_one_dat; printf("%"PRIu64 " blocks = %"PRIu64 " bytes in stream approx\n", blkcount, estimate_blks); printf("%"PRIu64 " data files = %"PRIu64 " bytes approx\n", datcount, estimate_dats); if(estimate_blks < estimate_one_dat) { printf("Stream is less than the size of a data file.\n"); printf("Use restore stream\n"); return 0; } else if(estimate_dats >= 90*(estimate_blks/100)) { printf("Stream is more than 90%% size of data files.\n"); printf("Use restore stream\n"); return 0; } else { printf("Data files are less than 90%% size of stream.\n"); printf("Use data files\n"); } printf("Client is using restore_spool: %s\n", restore_spool); if(asfd->write_str(asfd, CMD_GEN, "restore_spool") || asfd_read_expect(asfd, CMD_GEN, "restore_spool_ok")) goto end; // Send each of the data files that we found to the client. HASH_ITER(hh, hash_table, hash_weak, tmpw) { char msg[32]; char path[32]; char *fdatpath=NULL; snprintf(path, sizeof(path), "%014"PRIX64, hash_weak->weak); path[4]='/'; path[9]='/'; snprintf(msg, sizeof(msg), "dat=%s", path); printf("got: %s\n", msg); if(asfd->write_str(asfd, CMD_GEN, msg)) goto end; if(!(fdatpath=prepend_s(sdirs->data, path))) goto end; if(send_a_file(asfd, fdatpath, get_cntr(confs))) { free_w(&fdatpath); goto end; } free_w(&fdatpath); }
static int restore_stream(struct asfd *asfd, struct sdirs *sdirs, struct slist *slist, struct bu *bu, const char *manifest, regex_t *regex, int srestore, struct conf **cconfs, enum action act, enum cntr_status cntr_status) { int ret=-1; int last_ent_was_dir=0; struct sbuf *sb=NULL; struct iobuf *rbuf=asfd->rbuf; struct manio *manio=NULL; struct blk *blk=NULL; struct sbuf *need_data=NULL; enum protocol protocol=get_protocol(cconfs); struct cntr *cntr=get_cntr(cconfs); if(protocol==PROTO_2) { if(asfd->write_str(asfd, CMD_GEN, "restore_stream") || asfd->read_expect(asfd, CMD_GEN, "restore_stream_ok") || !(blk=blk_alloc())) goto end; } if(!(manio=manio_open(manifest, "rb", protocol)) || !(need_data=sbuf_alloc(protocol)) || !(sb=sbuf_alloc(protocol))) goto end; while(1) { iobuf_free_content(rbuf); if(asfd->as->read_quick(asfd->as)) { logp("read quick error\n"); goto end; } if(rbuf->buf) switch(rbuf->cmd) { case CMD_MESSAGE: case CMD_WARNING: { log_recvd(rbuf, cntr, 0); continue; } case CMD_INTERRUPT: // Client wanted to interrupt the // sending of a file. But if we are // here, we have already moved on. // Ignore. continue; default: iobuf_log_unexpected(rbuf, __func__); goto end; } switch(manio_read_with_blk(manio, sb, need_data->path.buf?blk:NULL, sdirs)) { case 0: break; // Keep going. case 1: ret=0; goto end; // Finished OK. default: goto end; // Error; } if(protocol==PROTO_2) { if(sb->endfile.buf) { sbuf_free_content(sb); continue; } if(blk->data) { if(protocol2_extra_restore_stream_bits(asfd, blk, slist, act, need_data, last_ent_was_dir, cntr)) goto end; continue; } sbuf_free_content(need_data); } if(want_to_restore(srestore, sb, regex, cconfs)) { if(restore_ent(asfd, &sb, slist, bu, act, sdirs, cntr_status, cconfs, need_data, &last_ent_was_dir, manifest)) goto end; } else if(sbuf_is_filedata(sb) || sbuf_is_vssdata(sb)) { // Add it to the list of filedata that was not // restored. struct f_link **bucket=NULL; if(!linkhash_search(&sb->statp, &bucket) && linkhash_add(sb->path.buf, &sb->statp, bucket)) goto end; } sbuf_free_content(sb); } end: blk_free(&blk); sbuf_free(&sb); sbuf_free(&need_data); iobuf_free_content(rbuf); manio_close(&manio); return ret; }
// Used when restoring a hard link that we have not restored the destination // for. Read through the manifest from the beginning and substitute the path // and data to the new location. static int hard_link_substitution(struct asfd *asfd, struct sbuf *sb, struct f_link *lp, struct bu *bu, enum action act, struct sdirs *sdirs, enum cntr_status cntr_status, struct conf **cconfs, const char *manifest, struct slist *slist) { int ret=-1; struct sbuf *need_data=NULL; int last_ent_was_dir=0; struct sbuf *hb=NULL; struct manio *manio=NULL; struct blk *blk=NULL; int pcmp; enum protocol protocol=get_protocol(cconfs); struct cntr *cntr=get_cntr(cconfs); if(!(manio=manio_open(manifest, "rb", protocol)) || !(need_data=sbuf_alloc(protocol)) || !(hb=sbuf_alloc(protocol))) goto end; if(protocol==PROTO_2) { if(!(blk=blk_alloc())) goto end; } while(1) { switch(manio_read_with_blk(manio, hb, need_data->path.buf?blk:NULL, sdirs)) { case 0: break; // Keep going. case 1: ret=0; goto end; // Finished OK. default: goto end; // Error; } if(protocol==PROTO_2) { if(hb->endfile.buf) { sbuf_free_content(hb); continue; } if(blk->data) { if(protocol2_extra_restore_stream_bits(asfd, blk, slist, act, need_data, last_ent_was_dir, cntr)) goto end; continue; } sbuf_free_content(need_data); } pcmp=pathcmp(lp->name, hb->path.buf); if(!pcmp && (sbuf_is_filedata(hb) || sbuf_is_vssdata(hb))) { // Copy the path from sb to hb. free_w(&hb->path.buf); if(!(hb->path.buf=strdup_w(sb->path.buf, __func__))) goto end; // Should now be able to restore the original data // to the new location. ret=restore_sbuf(asfd, hb, bu, act, sdirs, cntr_status, cconfs, need_data, manifest, slist); // May still need to get protocol2 data. if(!ret && need_data->path.buf) continue; break; } sbuf_free_content(hb); // Break out once we have gone past the entry that we are // interested in. if(pcmp<0) break; } end: blk_free(&blk); sbuf_free(&hb); manio_close(&manio); return ret; }