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; }
static enum parse_ret parse_cmd(struct sbuf *sb, struct asfd *asfd, struct iobuf *rbuf, struct blk *blk, struct cntr *cntr) { switch(rbuf->cmd) { case CMD_ATTRIBS: if(sb->protocol2) sbuf_free_content(sb); else { if(sb->protocol1->datapth.buf) // protocol 1 phase 2+ file data // starts with datapth. iobuf_free_content(&sb->attr); else // protocol 1 phase 1 or non file data // starts with attribs sbuf_free_content(sb); } iobuf_move(&sb->attr, rbuf); attribs_decode(sb); return PARSE_RET_NEED_MORE; case CMD_FILE: case CMD_DIRECTORY: case CMD_SOFT_LINK: case CMD_HARD_LINK: case CMD_SPECIAL: // Stuff not currently supported in burp-2, but OK // to find in burp-1. case CMD_ENC_FILE: case CMD_METADATA: case CMD_ENC_METADATA: case CMD_EFS_FILE: case CMD_VSS: case CMD_ENC_VSS: case CMD_VSS_T: case CMD_ENC_VSS_T: if(!sb->attr.buf) { log_and_send(asfd, "read cmd with no attribs"); return PARSE_RET_ERROR; } if(sb->flags & SBUF_NEED_LINK) { if(cmd_is_link(rbuf->cmd)) { iobuf_free_content(&sb->link); iobuf_move(&sb->link, rbuf); sb->flags &= ~SBUF_NEED_LINK; return PARSE_RET_COMPLETE; } else { log_and_send(asfd, "got non-link after link in manifest"); return PARSE_RET_NEED_MORE; } } else { iobuf_free_content(&sb->path); iobuf_move(&sb->path, rbuf); if(cmd_is_link(rbuf->cmd)) { sb->flags |= SBUF_NEED_LINK; return PARSE_RET_NEED_MORE; } else if(sb->protocol1 && sb->protocol1->datapth.buf) { // Protocol1 client restore reads // CMD_APPEND and CMD_END_FILE in the // calling function, so pretend it is // complete if we have the hack flag. if(sb->flags & SBUF_CLIENT_RESTORE_HACK) return PARSE_RET_COMPLETE; return PARSE_RET_NEED_MORE; } return PARSE_RET_COMPLETE; } #ifndef HAVE_WIN32 case CMD_SIG: // Fill in the sig/block, if the caller provided // a pointer for one. Server only. if(!blk) return PARSE_RET_NEED_MORE; // Just fill in the sig details. if(blk_set_from_iobuf_sig_and_savepath(blk, rbuf)) return PARSE_RET_ERROR; blk->got_save_path=1; iobuf_free_content(rbuf); return PARSE_RET_COMPLETE; #endif case CMD_DATA: // Need to write the block to disk. // Client only. if(!blk) return PARSE_RET_NEED_MORE; blk->data=rbuf->buf; blk->length=rbuf->len; rbuf->buf=NULL; return PARSE_RET_COMPLETE; case CMD_MESSAGE: case CMD_WARNING: log_recvd(rbuf, cntr, 1); return PARSE_RET_NEED_MORE; case CMD_GEN: if(!strcmp(rbuf->buf, "restoreend") || !strcmp(rbuf->buf, "phase1end") || !strcmp(rbuf->buf, "backupphase2") // Think these are protocol1 things. || !strcmp(rbuf->buf, "backupend") || !strcmp(rbuf->buf, "estimateend")) return PARSE_RET_FINISHED; iobuf_log_unexpected(rbuf, __func__); return PARSE_RET_ERROR; case CMD_FINGERPRINT: if(blk && blk_set_from_iobuf_fingerprint(blk, rbuf)) return PARSE_RET_ERROR; // Fall through. case CMD_MANIFEST: iobuf_free_content(&sb->path); iobuf_move(&sb->path, rbuf); return PARSE_RET_COMPLETE; case CMD_ERROR: logp("got error: %s\n", rbuf->buf); return PARSE_RET_ERROR; case CMD_DATAPTH: if(!sb->protocol1) { iobuf_log_unexpected(rbuf, __func__); return PARSE_RET_ERROR; } if(sb->flags & SBUF_CLIENT_RESTORE_HACK) { sbuf_free_content(sb); sb->flags |= SBUF_CLIENT_RESTORE_HACK; } else sbuf_free_content(sb); iobuf_move(&sb->protocol1->datapth, rbuf); return PARSE_RET_NEED_MORE; case CMD_END_FILE: iobuf_free_content(&sb->endfile); iobuf_move(&sb->endfile, rbuf); if(sb->protocol1) { if(!sb->attr.buf || !sb->protocol1->datapth.buf || (!sbuf_is_filedata(sb) && !sbuf_is_vssdata(sb))) { logp("got unexpected cmd_endfile"); return PARSE_RET_ERROR; } } return PARSE_RET_COMPLETE; default: iobuf_log_unexpected(rbuf, __func__); return PARSE_RET_ERROR; } logp("Fell out of switch unexpectedly in %s()\n", __func__); return PARSE_RET_ERROR; }
// 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; }