// 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; }
int blk_verify_fingerprint(uint64_t fingerprint, char *data, size_t length) { win_reset(); memcpy(gbuf, data, length); gbuf_end=gbuf+length; gcp=gbuf; blk_free(&blk); if(!blk && !(blk=blk_alloc())) return -1; blk->length=0; blk->fingerprint=0; // FIX THIS: blk_read should return 1 when it has a block. // But, if the block is too small (because the end of the file // happened), it returns 0, and blks_generate treats it as having found // a final block. // So, here the return of blk_read is ignored and we look at the // position of gcp instead. blk_read(); //printf("%d %d\n", blk->length, length); //printf("%016"PRIX64" %016"PRIX64" ", // blk->fingerprint, fingerprint); //printf("%s\n", blk->fingerprint==fingerprint?"yes":"no"); if(gcp==gbuf_end && blk->fingerprint==fingerprint) return 1; return 0; }
struct blk *blk_alloc_with_data(uint32_t max_data_length) { struct blk *blk=NULL; if(!(blk=blk_alloc())) return NULL; if((blk->data=(char *) calloc_w(1, sizeof(char)*max_data_length, __func__))) return blk; blk_free(&blk); return NULL; }
static ssize_t ext2_pread(struct inode *i, void *buf, size_t len, off_t off) { size_t first_block, last_block, num_blk, x; struct buffer *bh; ssize_t copied; if ( off + len > i->i_size ) len = i->i_size - off; first_block = off / i->i_sb->s_blocksize; last_block = (off + len) / i->i_sb->s_blocksize; num_blk = last_block - first_block; dprintk("EXT2: pread %lu @ %lu: blocks %lu - %lu\n", len, off, first_block, last_block); BUG_ON(last_block >= EXT2_NDIR_BLOCKS); for(copied = 0, x = first_block; x <= last_block; x++) { size_t clen, coff; bh = blk_read(i->i_sb->s_dev, i->u.ext2.block[x]); if ( NULL == bh ) return copied; coff = off & (i->i_sb->s_blocksize - 1); clen = (coff + len > i->i_sb->s_blocksize) ? i->i_sb->s_blocksize - coff : len; dprintk("EXT2: got block %lu, copy %lu bytes at %lu\n", i->u.ext2.block[x], clen, coff); if ( copy_to_user(buf, bh->b_buf + coff, clen) < 0 ) { blk_free(bh); return -1; /* EFAULT */ } copied += clen; len -= clen; off += clen; blk_free(bh); } return copied; }
// When a backup is ongoing, use this to add newly complete candidates. int candidate_add_fresh(const char *path, struct conf *conf) { int ars; int ret=-1; gzFile zp=NULL; const char *cp=NULL; struct sbuf *sb=NULL; struct candidate *candidate=NULL; struct blk *blk=NULL; if(!(candidate=candidates_add_new())) goto end; cp=path+strlen(conf->directory); while(cp && *cp=='/') cp++; if(!(candidate->path=strdup(cp))) { log_out_of_memory(__func__); goto end; } if(!(sb=sbuf_alloc(conf)) || !(blk=blk_alloc()) || !(zp=gzopen_file(path, "rb"))) goto end; while(zp) { if((ars=sbuf_fill_from_gzfile(sb, NULL /* struct async */, zp, blk, NULL, conf))<0) goto end; else if(ars>0) { // Reached the end. break; } if(!*(blk->weak)) continue; if(is_hook(blk->weak)) { if(sparse_add_candidate(blk->weak, candidate)) goto end; } *blk->weak='\0'; } if(scores_grow(scores, candidates_len)) goto end; candidates_set_score_pointers(candidates, candidates_len, scores); scores_reset(scores); //printf("HERE: %d candidates\n", (int)candidates_len); ret=0; end: gzclose_fp(&zp); sbuf_free(sb); blk_free(blk); return ret; }
/* Lookup a name in an inode */ static struct inode *ext2_lookup(struct inode *i, const char *n, size_t nlen) { struct ext2_dir_entry_2 *dir; struct buffer *bh; ino_t inum; int x, y; char *j; y = EXT2_NDIR_BLOCKS < i->i_blocks ? EXT2_NDIR_BLOCKS : i->i_blocks; for(x = 0; x < y; x++) { /* pre-allocation ?? */ if ( i->u.ext2.block[x] == 0 ) continue; /* Read the block */ bh = blk_read(i->i_sb->s_dev, i->u.ext2.block[x]); if ( NULL == bh ) return NULL; /* Search for the item */ for(j = bh->b_buf; j < (bh->b_buf + bh->b_len); ) { dir = (struct ext2_dir_entry_2 *)j; dprintk("EXT2: dentry: %.*s\n", dir->name_len, dir->name); if ( (dir->name_len == nlen) && !memcmp(dir->name, n, nlen) ) { inum = dir->inode; blk_free(bh); return iget(i->i_sb, inum); } j += dir->rec_len; } blk_free(bh); } return NULL; }
static int write_to_dpth(struct dpth *dpth, const char *savepathstr) { int ret; struct iobuf wbuf; struct blk *blk=blk_alloc(); savepathstr_to_bytes(savepathstr, blk->savepath); wbuf.buf=strdup_w("abc", __FUNCTION__); wbuf.len=3; ret=dpth_protocol2_fwrite(dpth, &wbuf, blk); free_w(&wbuf.buf); blk_free(&blk); return ret; }
static int results_to_fd(struct asfd *asfd) { static struct iobuf wbuf; struct blk *b; struct blk *l; if(!asfd->blist->last_index) return 0; // Need to start writing the results down the fd. for(b=asfd->blist->head; b && b!=asfd->blist->blk_to_dedup; b=l) { if(b->got==BLK_GOT) { // Need to write to fd. blk_to_iobuf_index_and_savepath(b, &wbuf); switch(asfd->append_all_to_write_buffer(asfd, &wbuf)) { case APPEND_OK: break; case APPEND_BLOCKED: asfd->blist->head=b; return 0; // Try again later. default: return -1; } } else { // If the last in the sequence is BLK_NOT_GOT, // Send a 'wrap_up' message. if(!b->next || b->next==asfd->blist->blk_to_dedup) { blk_to_iobuf_wrap_up(b, &wbuf); switch(asfd->append_all_to_write_buffer(asfd, &wbuf)) { case APPEND_OK: break; case APPEND_BLOCKED: asfd->blist->head=b; return 0; // Try again later. default: return -1; } } } l=b->next; blk_free(&b); } asfd->blist->head=b; if(!b) asfd->blist->tail=NULL; return 0; }
static void blist_adjust_head(struct blist *blist, struct sbuf *sb) { struct blk *b; while(blist->head!=sb->protocol2->bstart) { b=blist->head->next; if(blist->head==blist->blk_from_champ_chooser) blist->blk_from_champ_chooser=b; blk_free(&blist->head); blist->head=b; } if(!blist->head) blist->tail=NULL; }
/* Companion function to f_trunc(). */ void freeblk(uint16_t dev, blkno_t blk, uint8_t level) { blkno_t *buf; int8_t j; if(!blk) return; if(level){ buf = (blkno_t *)bread(dev, blk, 0); for(j=255; j >= 0; --j) freeblk(dev, buf[j], level-1); brelse((char *)buf); } blk_free(dev, blk); }
// Return -1 on error, 0 on OK, 1 for srcmanio finished. int manio_copy_entry(struct asfd *asfd, struct sbuf **csb, struct sbuf *sb, struct blk **blk, struct manio *srcmanio, struct manio *dstmanio, struct conf *conf) { static int ars; static char *copy=NULL; // Use the most recent stat for the new manifest. if(dstmanio && manio_write_sbuf(dstmanio, sb)) goto error; if(!(copy=strdup((*csb)->path.buf))) { log_out_of_memory(__func__); goto error; } while(1) { if((ars=manio_sbuf_fill(srcmanio, asfd, *csb, *blk, NULL, conf))<0) goto error; else if(ars>0) { // Finished. sbuf_free(*csb); *csb=NULL; blk_free(*blk); *blk=NULL; free(copy); return 1; } // Got something. if(strcmp((*csb)->path.buf, copy)) { // Found the next entry. free(copy); return 0; } // Should have the next signature. // Write it to the destination manifest. if(dstmanio && manio_write_sig_and_path(dstmanio, *blk)) goto error; } error: if(copy) free(copy); return -1; }
static int restore_sbuf(struct asfd *asfd, struct sbuf *sb, enum action act, enum cstat_status status, struct conf *conf, int *need_data) { //logp("%s: %s\n", act==ACTION_RESTORE?"restore":"verify", sb->path.buf); if(write_status(status, sb->path.buf, conf)) return -1; if(asfd->write(asfd, &sb->attr) || asfd->write(asfd, &sb->path)) return -1; if(sbuf_is_link(sb) && asfd->write(asfd, &sb->link)) return -1; if(sb->burp2->bstart) { // This will restore directory data on Windows. struct blk *b=NULL; struct blk *n=NULL; b=sb->burp2->bstart; while(b) { struct iobuf wbuf; iobuf_set(&wbuf, CMD_DATA, b->data, b->length); if(asfd->write(asfd, &wbuf)) return -1; n=b->next; blk_free(&b); b=n; } sb->burp2->bstart=sb->burp2->bend=NULL; } switch(sb->path.cmd) { case CMD_FILE: case CMD_ENC_FILE: case CMD_METADATA: case CMD_ENC_METADATA: case CMD_EFS_FILE: *need_data=1; return 0; default: cntr_add(conf->cntr, sb->path.cmd, 0); return 0; } }
void list_free(List* list) { ListElem* p; ListElem* q; assert(list_is_valid(list)); list->refc--; if (list->refc == 0) { SID_del(list); for(p = list->anchor.next; p != &list->anchor; p = q) { q = p->next; switch(list->type) { case LIST_ELEM : elem_free(p->data.elem); break; case LIST_TUPLE : tuple_free(p->data.tuple); break; case LIST_ENTRY : entry_free(p->data.entry); break; case LIST_IDXELEM : break; case LIST_LIST : list_free(p->data.list); break; default : abort(); } blk_free(p, sizeof(*p)); } free(list); } }
static void free_stuff(struct slist *slist, struct blist *blist) { struct blk *blk; blk=blist->head; while(blk && blk!=blist->last_sent) { if(blk==slist->head->burp2->bstart) slist->head->burp2->bstart=NULL; if(blk==slist->head->burp2->bend) { struct sbuf *sb; sb=slist->head; sb->burp2->bend=NULL; if(!(slist->head=slist->head->next)) slist->tail=NULL; sbuf_free(&sb); } blk=blk->next; blk_free(&blist->head); blist->head=blk; } }
int restore_sbuf_protocol2(struct asfd *asfd, struct sbuf *sb, enum action act, struct cntr *cntr, struct sbuf *need_data) { if(asfd->write(asfd, &sb->attr) || asfd->write(asfd, &sb->path)) return -1; if(sbuf_is_link(sb) && asfd->write(asfd, &sb->link)) return -1; if(sb->protocol2->bstart) { // This will restore directory data on Windows. struct blk *b=NULL; struct blk *n=NULL; b=sb->protocol2->bstart; while(b) { if(send_data(asfd, b, act, need_data, cntr)) return -1; n=b->next; blk_free(&b); b=n; } sb->protocol2->bstart=sb->protocol2->bend=NULL; } if(sbuf_is_filedata(sb)) { if(need_data) { iobuf_copy(&need_data->path, &sb->path); sb->path.buf=NULL; } } else cntr_add(cntr, sb->path.cmd, 0); return 0; }
void hash_free(Hash* hash) { HElem* he; HElem* hq; unsigned int i; assert(hash_is_valid(hash)); if (verbose >= VERB_CHATTER) hash_statist(stderr, hash); SID_del(hash); for(i = 0; i < hash->size; i++) { for(he = hash->bucket[i]; he != NULL; he = hq) { hq = he->next; blk_free(he, sizeof(*he)); } } free(hash->bucket); free(hash); }
// This deals with reading in the sparse index, as well as actual candidate // manifests. enum cand_ret candidate_load(struct candidate *candidate, const char *path, struct scores *scores) { enum cand_ret ret=CAND_RET_PERM; struct fzp *fzp=NULL; struct sbuf *sb=NULL; struct blk *blk=NULL; if(!(sb=sbuf_alloc(PROTO_2)) || !(blk=blk_alloc())) { ret=CAND_RET_PERM; goto error; } if(!(fzp=fzp_gzopen(path, "rb"))) { ret=CAND_RET_TEMP; goto error; } while(fzp) { sbuf_free_content(sb); switch(sbuf_fill_from_file(sb, fzp, blk, NULL)) { case 1: goto end; case -1: logp("Error reading %s in %s, pos %d\n", path, __func__, fzp_tell(fzp)); ret=CAND_RET_TEMP; goto error; } if(blk_fingerprint_is_hook(blk)) { if(sparse_add_candidate(&blk->fingerprint, candidate)) { ret=CAND_RET_PERM; goto error; } } else if(sb->path.cmd==CMD_MANIFEST) { if(!(candidate=candidates_add_new())) { ret=CAND_RET_PERM; goto error; } candidate->path=sb->path.buf; sb->path.buf=NULL; } blk->fingerprint=0; } end: if(scores_grow(scores, candidates_len)) { ret=CAND_RET_PERM; goto error; } candidates_set_score_pointers(candidates, candidates_len, scores); scores_reset(scores); //logp("Now have %d candidates\n", (int)candidates_len); ret=CAND_RET_OK; error: fzp_close(&fzp); sbuf_free(&sb); blk_free(&blk); return ret; }
/* Fill in an inode structure for iget */ static int ext2_read_inode(struct inode *i) { unsigned long block_group; unsigned long group_desc, desc; unsigned long offset, block; struct ext2_group_desc *gdp; struct ext2_inode *raw_inode; struct buffer *b; /* 1. Check inode number */ if ( i->i_ino > i->i_sb->u.ext2.s_es->s_inodes_count ) { printk("EXT2: bad inode %lu\n", i->i_ino); return -1; } /* 2. Calculate block group number */ block_group = (i->i_ino - 1) / i->i_sb->u.ext2.s_inodes_per_group; if ( block_group >= i->i_sb->u.ext2.s_groups_count ) { printk("EXT2: Bad group %lu\n", block_group); return -1; } /* 3. Obtain block group descriptor */ group_desc = block_group / i->i_sb->u.ext2.s_desc_per_block; desc = block_group % i->i_sb->u.ext2.s_desc_per_block; b = i->i_sb->u.ext2.s_group_desc[group_desc]; gdp = (struct ext2_group_desc *)b->b_buf; /* 4. Obtain correct block from inode table */ block = gdp[desc].bg_inode_table + ((i->i_ino - 1) / i->i_sb->u.ext2.s_inodes_per_block); if ( !(b=blk_read(i->i_sb->s_dev, block)) ) { printk("EXT2: Unable to read inode block - inode=%lu, block=%lu\n", i->i_ino, block); return -1; } /* 5. Obtain the inode pointer */ offset = (i->i_ino - 1) * i->i_sb->u.ext2.s_es->s_inode_size; offset &= (i->i_sb->s_blocksize - 1); raw_inode = (struct ext2_inode *)(b->b_buf + offset); /* 6. Copy the inode */ dprintk("Inode %lu mode %o\n", i->i_ino, raw_inode->i_mode); switch(raw_inode->i_mode & S_IFMT) { case S_IFDIR: i->i_iop = &ext2_dir_iop; break; case S_IFREG: i->i_iop = &ext2_reg_iop; break; default: printk("EXT2: Unsupported file type: 0%o\n", raw_inode->i_mode); blk_free(b); return -1; } i->i_mode = raw_inode->i_mode; i->i_uid = raw_inode->i_uid; i->i_gid = raw_inode->i_gid; i->i_size = raw_inode->i_size; i->i_nlink = raw_inode->i_links_count; i->i_blocks = raw_inode->i_blocks; for(block = 0; block < EXT2_N_BLOCKS; block++) { i->u.ext2.block[block] = raw_inode->i_block[block]; } /* Finish up */ blk_free(b); return 0; }
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; }
// Combine the phase1 and phase2 files into a new manifest. int backup_phase3_server_all(struct sdirs *sdirs, struct conf **confs) { int ret=-1; int pcmp=0; struct blk *blk=NULL; struct sbuf *usb=NULL; struct sbuf *csb=NULL; char *manifesttmp=NULL; struct manio *newmanio=NULL; struct manio *chmanio=NULL; struct manio *unmanio=NULL; enum protocol protocol=get_protocol(confs); struct cntr *cntr=get_cntr(confs); const char *rmanifest_relative=NULL; logp("Begin phase3 (merge manifests)\n"); if(protocol==PROTO_2) rmanifest_relative=get_rmanifest_relative(sdirs, confs); if(!(manifesttmp=get_tmp_filename(sdirs->manifest)) || !(newmanio=manio_open_phase3(manifesttmp, comp_level(get_int(confs[OPT_COMPRESSION])), protocol, rmanifest_relative)) || !(chmanio=manio_open_phase2(sdirs->changed, "rb", protocol)) || !(unmanio=manio_open_phase2(sdirs->unchanged, "rb", protocol)) || !(usb=sbuf_alloc(protocol)) || !(csb=sbuf_alloc(protocol))) goto end; while(chmanio || unmanio) { if(!blk && !(blk=blk_alloc())) goto end; if(unmanio && !usb->path.buf) { switch(manio_read(unmanio, usb)) { case -1: goto end; case 1: manio_close(&unmanio); } } if(chmanio && !csb->path.buf) { switch(manio_read(chmanio, csb)) { case -1: goto end; case 1: manio_close(&chmanio); } } if(usb->path.buf && !csb->path.buf) { if(write_status(CNTR_STATUS_MERGING, usb->path.buf, cntr)) goto end; switch(manio_copy_entry( usb, usb, &blk, unmanio, newmanio)) { case -1: goto end; case 1: manio_close(&unmanio); } } else if(!usb->path.buf && csb->path.buf) { if(write_status(CNTR_STATUS_MERGING, csb->path.buf, cntr)) goto end; switch(manio_copy_entry( csb, csb, &blk, chmanio, newmanio)) { case -1: goto end; case 1: manio_close(&chmanio); } } else if(!usb->path.buf && !csb->path.buf) { continue; } else if(!(pcmp=sbuf_pathcmp(usb, csb))) { // They were the same - write one. if(write_status(CNTR_STATUS_MERGING, csb->path.buf, cntr)) goto end; switch(manio_copy_entry( csb, csb, &blk, chmanio, newmanio)) { case -1: goto end; case 1: manio_close(&chmanio); } } else if(pcmp<0) { if(write_status(CNTR_STATUS_MERGING, usb->path.buf, cntr)) goto end; switch(manio_copy_entry( usb, usb, &blk, unmanio, newmanio)) { case -1: goto end; case 1: manio_close(&unmanio); } } else { if(write_status(CNTR_STATUS_MERGING, csb->path.buf, cntr)) goto end; switch(manio_copy_entry( csb, csb, &blk, chmanio, newmanio)) { case -1: goto end; case 1: manio_close(&chmanio); } } } // Flush to disk. if(manio_close(&newmanio)) { logp("error gzclosing %s in backup_phase3_server\n", manifesttmp); goto end; } // Rename race condition should be of no consequence here, as the // manifest should just get recreated automatically. if(do_rename(manifesttmp, sdirs->manifest)) goto end; else { recursive_delete(sdirs->changed); recursive_delete(sdirs->unchanged); } logp("End phase3 (merge manifests)\n"); ret=0; end: manio_close(&newmanio); manio_close(&chmanio); manio_close(&unmanio); sbuf_free(&csb); sbuf_free(&usb); blk_free(&blk); free_w(&manifesttmp); return ret; }
static int ext2_get_super(struct super *sb) { struct ext2_super_block *s; struct buffer *bh; int db_count, i; /* Set blocksize for the device */ if ( blk_set_blocksize(sb->s_dev, EXT2_MIN_BLOCK_SIZE) ) { printk("EXT2: Unable to set blocksize %d\n", EXT2_MIN_BLOCK_SIZE); return -1; } /* Read in the super block */ bh = blk_read(sb->s_dev, 1); if ( NULL == bh ) { printk("EXT2: %s: unable to read super\n", sb->s_dev->name); return -1; } s = (struct ext2_super_block *)bh->b_buf; /* Check the super block */ if ( s->s_magic != EXT2_SUPER_MAGIC ) { printk("EXT2: Bad voodoo magic on superblock!\n"); goto err; } if ( s->s_log_block_size ) { printk("EXT2: only 1KB blocksize supported\n"); goto err; } /* Fill in the superblock structures */ sb->s_blocksize = EXT2_MIN_BLOCK_SIZE; sb->s_ops = &ext2_superops; /* Fill in custom structures */ sb->u.ext2.s_sbh = bh; sb->u.ext2.s_es = s; sb->u.ext2.s_inodes_per_block = sb->s_blocksize / s->s_inode_size; sb->u.ext2.s_blocks_per_group = s->s_blocks_per_group; sb->u.ext2.s_inodes_per_group = s->s_inodes_per_group; sb->u.ext2.s_itb_per_group = s->s_inodes_per_group / sb->u.ext2.s_inodes_per_block; sb->u.ext2.s_desc_per_block = sb->s_blocksize / sizeof(struct ext2_group_desc); sb->u.ext2.s_groups_count = (s->s_blocks_count - s->s_first_data_block + (sb->u.ext2.s_blocks_per_group-1)) / sb->u.ext2.s_blocks_per_group; /* Read in the group descriptors */ db_count = (sb->u.ext2.s_groups_count + sb->u.ext2.s_desc_per_block - 1) / sb->u.ext2.s_desc_per_block; sb->u.ext2.s_group_desc = kmalloc(db_count * sizeof(struct buffer *)); for(i = 0; i < db_count; i++) { int j; sb->u.ext2.s_group_desc[i] = blk_read(sb->s_dev, i + 2); if ( !sb->u.ext2.s_group_desc[i] ) { printk("EXT2: unable to read group descriptors\n"); for(j = 0; j < i; j++) blk_free(sb->u.ext2.s_group_desc[i]); goto err; } } /* Lookup root inode */ sb->s_root = iget(sb, EXT2_ROOT_INO); if ( NULL == sb->s_root ) { printk("EXT2: get root inode failed\n"); goto err; } return 0; err: blk_free(bh); return -1; }
// The client uses this. // Return 0 for OK. 1 for OK, and file ended, -1 for error. int blks_generate(struct asfd *asfd, struct conf **confs, struct sbuf *sb, struct blist *blist, int just_opened) { static ssize_t bytes; first=just_opened; if(!blk && !(blk=blk_alloc_with_data(rconf.blk_max))) return -1; if(gcp<gbuf_end) { // Could have got a fill before buf ran out - // need to resume from the same place in that case. if(blk_read_to_list(sb, blist)) return 0; // Got a block. // Did not get a block. Carry on and read more. } while((bytes=rabin_read(sb, gbuf, rconf.blk_max))) { gcp=gbuf; gbuf_end=gbuf+bytes; sb->protocol2->bytes_read+=bytes; if(blk_read_to_list(sb, blist)) return 0; // Got a block // Did not get a block. Maybe should try again? // If there are async timeouts, look at this! return 0; } // Getting here means there is no more to read from the file. // Make sure to deal with anything left over. if(!sb->protocol2->bytes_read) { // Empty file, set up an empty block so that the server // can skip over it. if(!(sb->protocol2->bstart=blk_alloc())) return -1; sb->protocol2->bsighead=blk; blist_add_blk(blist, blk); blk=NULL; } else if(blk) { if(blk->length) { if(first) { sb->protocol2->bstart=blk; first=0; } if(!sb->protocol2->bsighead) { sb->protocol2->bsighead=blk; } blist_add_blk(blist, blk); } else blk_free(&blk); blk=NULL; } if(blist->tail) sb->protocol2->bend=blist->tail; 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; }
// 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); }
static int sbuf_needs_data(struct sbuf *sb, struct asfd *asfd, struct asfd *chfd, struct manios *manios, struct slist *slist, int end_flags) { int ret=-1; struct blk *blk; static struct iobuf wbuf; struct blist *blist=slist->blist; if(!(sb->flags & SBUF_HEADER_WRITTEN_TO_MANIFEST)) { if(manio_write_sbuf(manios->changed, sb)) goto end; sb->flags |= SBUF_HEADER_WRITTEN_TO_MANIFEST; } while((blk=sb->protocol2->bstart) && blk->got==BLK_GOT && (blk->next || end_flags&END_BACKUP)) { if(blk->got_save_path && !blk_is_zero_length(blk)) { if(breaking && breakcount--==0) { breakpoint(breaking, __func__); goto end; } if(manio_write_sig_and_path(manios->changed, blk)) goto end; if(manios->changed->sig_count==0) { // Have finished a manifest file. Want to start // using it as a dedup candidate now. iobuf_from_str(&wbuf, CMD_MANIFEST, manios->changed->offset->fpath); if(chfd->write(chfd, &wbuf)) goto end; if(!blk->requested) { // Also let the client know, so that it // can free memory if there was a long // consecutive number of unrequested // blocks. get_wbuf_from_index(&wbuf, blk->index); if(asfd->write(asfd, &wbuf)) goto end; } } } if(blk==sb->protocol2->bend) { slist->head=sb->next; if(!(blist->head=sb->protocol2->bstart)) blist->tail=NULL; sanity_before_sbuf_free(slist, sb); if(write_endfile(sb, manios)) return -1; sbuf_free(&sb); return 1; } if(sb->protocol2->bsighead==sb->protocol2->bstart) sb->protocol2->bsighead=blk->next; sb->protocol2->bstart=blk->next; if(blk==blist->blk_from_champ_chooser) blist->blk_from_champ_chooser=blk->next; blk_free(&blk); } if(!blk && sb && !sb->protocol2->bend && (end_flags&END_BACKUP)) { // Write endfile for the very last file. if(write_endfile(sb, manios)) return -1; } ret=0; end: if(!(blist->head=sb->protocol2->bstart)) blist->tail=NULL; return ret; }
// This is basically backup_phase3_server() from protocol1. It used to merge the // unchanged and changed data into a single file. Now it splits the manifests // into several files. int backup_phase3_server_protocol2(struct sdirs *sdirs, struct conf **confs) { int ret=1; int pcmp=0; char *hooksdir=NULL; char *dindexdir=NULL; char *manifesttmp=NULL; struct sbuf *usb=NULL; struct sbuf *csb=NULL; struct blk *blk=NULL; int finished_ch=0; int finished_un=0; struct manio *newmanio=NULL; struct manio *chmanio=NULL; struct manio *unmanio=NULL; uint64_t fcount=0; logp("Start phase3\n"); if(!(manifesttmp=get_tmp_filename(sdirs->rmanifest)) || !(newmanio=manio_alloc()) || !(chmanio=manio_alloc()) || !(unmanio=manio_alloc()) || !(hooksdir=prepend_s(manifesttmp, "hooks")) || !(dindexdir=prepend_s(manifesttmp, "dindex")) || manio_init_write(newmanio, manifesttmp) || manio_init_write_hooks(newmanio, get_string(confs[OPT_DIRECTORY]), hooksdir, sdirs->rmanifest) || manio_init_write_dindex(newmanio, dindexdir) || manio_init_read(chmanio, sdirs->changed) || manio_init_read(unmanio, sdirs->unchanged) || !(usb=sbuf_alloc(confs)) || !(csb=sbuf_alloc(confs))) goto end; while(!finished_ch || !finished_un) { if(!blk && !(blk=blk_alloc())) goto end; if(!finished_un && usb && !usb->path.buf) { switch(manio_sbuf_fill(unmanio, NULL /* no async */, usb, NULL, NULL, confs)) { case -1: goto end; case 1: finished_un++; } } if(!finished_ch && csb && !csb->path.buf) { switch(manio_sbuf_fill(chmanio, NULL /* no async */, csb, NULL, NULL, confs)) { case -1: goto end; case 1: finished_ch++; } } if((usb && usb->path.buf) && (!csb || !csb->path.buf)) { switch(manio_copy_entry(NULL /* no async */, &usb, usb, &blk, unmanio, newmanio, confs)) { case -1: goto end; case 1: finished_un++; } } else if((!usb || !usb->path.buf) && (csb && csb->path.buf)) { switch(manio_copy_entry(NULL /* no async */, &csb, csb, &blk, chmanio, newmanio, confs)) { case -1: goto end; case 1: finished_ch++; } } else if((!usb || !usb->path.buf) && (!csb || !(csb->path.buf))) { continue; } else if(!(pcmp=sbuf_pathcmp(usb, csb))) { // They were the same - write one. switch(manio_copy_entry(NULL /* no async */, &csb, csb, &blk, chmanio, newmanio, confs)) { case -1: goto end; case 1: finished_ch++; } } else if(pcmp<0) { switch(manio_copy_entry(NULL /* no async */, &usb, usb, &blk, unmanio, newmanio, confs)) { case -1: goto end; case 1: finished_un++; } } else { switch(manio_copy_entry(NULL /* no async */, &csb, csb, &blk, chmanio, newmanio, confs)) { case -1: goto end; case 1: finished_ch++; } } } fcount=newmanio->fcount; // Flush to disk and set up for reading. if(manio_free(&newmanio) || !(newmanio=manio_alloc()) || manio_init_read(newmanio, sdirs->rmanifest)) goto end; // Rename race condition should be of no consequence here, as the // manifest should just get recreated automatically. if(do_rename(manifesttmp, sdirs->rmanifest)) goto end; else { recursive_delete(sdirs->changed, NULL, 1); recursive_delete(sdirs->unchanged, NULL, 1); } if(sparse_generation(newmanio, fcount, sdirs, confs)) goto end; ret=0; logp("End phase3\n"); end: manio_free(&newmanio); manio_free(&chmanio); manio_free(&unmanio); sbuf_free(&csb); sbuf_free(&usb); blk_free(&blk); free_w(&hooksdir); free_w(&dindexdir); free_w(&manifesttmp); return ret; }
// Return -1 for error, 0 for entry not changed, 1 for entry changed (or new). static int entry_changed(struct asfd *asfd, struct sbuf *sb, struct manio *cmanio, struct manio *unmanio, struct conf *conf) { static int finished=0; static struct sbuf *csb=NULL; static struct blk *blk=NULL; if(finished) return 1; if(!csb && !(csb=sbuf_alloc(conf))) return -1; if(csb->path.buf) { // Already have an entry. } else { // Need to read another. if(!blk && !(blk=blk_alloc())) return -1; switch(manio_sbuf_fill(cmanio, asfd, csb, blk, NULL, conf)) { 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(asfd, csb, sb, cmanio, unmanio, &blk, conf); case 1: return 1; case -1: // Behind - need to read more data from the old // manifest. switch(manio_sbuf_fill(cmanio, asfd, csb, blk, NULL, conf)) { case -1: return -1; case 1: { // Reached the end. sbuf_free(&csb); blk_free(&blk); return 1; } } // Got something, go back around the loop. } } return 0; }
static int write_to_changed_file(struct asfd *asfd, struct asfd *chfd, struct manio *chmanio, struct slist *slist, struct blist *blist, struct dpth *dpth, int backup_end, struct conf *conf) { struct sbuf *sb; static struct iobuf *wbuf=NULL; if(!slist) return 0; if(!wbuf && !(wbuf=iobuf_alloc())) return -1; while((sb=slist->head)) { if(sb->flags & SBUF_NEED_DATA) { int hack=0; // Need data... struct blk *blk; if(!(sb->flags & SBUF_HEADER_WRITTEN_TO_MANIFEST)) { if(manio_write_sbuf(chmanio, sb)) return -1; sb->flags |= SBUF_HEADER_WRITTEN_TO_MANIFEST; } while((blk=sb->burp2->bstart) && blk->got==BLK_GOT && (blk->next || backup_end)) { if(*(blk->save_path)) { if(manio_write_sig_and_path(chmanio, blk)) return -1; if(chmanio->sig_count==0) { // Have finished a manifest // file. Want to start using // it as a dedup candidate // now. iobuf_from_str(wbuf, CMD_MANIFEST, chmanio->fpath); printf("send manifest path\n"); if(chfd->write(chfd, wbuf)) return -1; if(!blk->requested) { // Also let the client know, // so that it can free memory // if there was a long // consecutive number of // unrequested blocks. get_wbuf_from_wrap_up(wbuf, blk->index); if(asfd->write(asfd, wbuf)) return -1; } } } /* else { // This gets hit if there is a zero // length file. printf("!!!!!!!!!!!!! no data; %s\n", sb->path); exit(1); } */ if(blk==sb->burp2->bend) { slist->head=sb->next; if(!(blist->head=sb->burp2->bstart)) blist->tail=NULL; sanity_before_sbuf_free(slist, sb); sbuf_free(&sb); hack=1; break; } if(sb->burp2->bsighead==sb->burp2->bstart) sb->burp2->bsighead=blk->next; sb->burp2->bstart=blk->next; if(blk==blist->blk_from_champ_chooser) blist->blk_from_champ_chooser=blk->next; //printf("freeing blk %d\n", blk->index); blk_free(&blk); } if(hack) continue; if(!(blist->head=sb->burp2->bstart)) blist->tail=NULL; break; } else { // No change, can go straight in. if(manio_write_sbuf(chmanio, sb)) return -1; // Move along. slist->head=sb->next; sanity_before_sbuf_free(slist, sb); sbuf_free(&sb); } } return 0; }
void blks_generate_free(void) { free_w(&gbuf); blk_free(&blk); win_free(&win); }
int do_restore_client(struct asfd *asfd, struct conf **confs, enum action act, int vss_restore) { int ret=-1; char msg[512]=""; struct sbuf *sb=NULL; struct blk *blk=NULL; BFILE *bfd=NULL; char *fullpath=NULL; char *style=NULL; char *datpath=NULL; struct cntr *cntr=get_cntr(confs); enum protocol protocol=get_protocol(confs); int strip=get_int(confs[OPT_STRIP]); int overwrite=get_int(confs[OPT_OVERWRITE]); const char *backup=get_string(confs[OPT_BACKUP]); const char *regex=get_string(confs[OPT_REGEX]); const char *restore_prefix=get_string(confs[OPT_RESTOREPREFIX]); const char *encryption_password=get_string(confs[OPT_ENCRYPTION_PASSWORD]); if(!(bfd=bfile_alloc())) goto end; bfile_init(bfd, 0, cntr); snprintf(msg, sizeof(msg), "%s %s:%s", act_str(act), backup?backup:"", regex?regex:""); logp("doing %s\n", msg); if(asfd->write_str(asfd, CMD_GEN, msg) || asfd_read_expect(asfd, CMD_GEN, "ok")) goto error; logp("doing %s confirmed\n", act_str(act)); #if defined(HAVE_WIN32) if(act==ACTION_RESTORE) win32_enable_backup_privileges(); #endif if(!(style=get_restore_style(asfd, confs))) goto error; if(!strcmp(style, RESTORE_SPOOL)) { if(restore_spool(asfd, confs, &datpath)) goto error; } else logp("Streaming restore direct\n"); logf("\n"); if(get_int(confs[OPT_SEND_CLIENT_CNTR]) && cntr_recv(asfd, confs)) goto error; if(!(sb=sbuf_alloc(protocol)) || (protocol==PROTO_2 && !(blk=blk_alloc()))) { log_and_send_oom(asfd, __func__); goto error; } while(1) { sbuf_free_content(sb); if(protocol==PROTO_1) sb->flags |= SBUF_CLIENT_RESTORE_HACK; switch(sbuf_fill_from_net(sb, asfd, blk, datpath, cntr)) { case 0: break; case 1: if(asfd->write_str(asfd, CMD_GEN, "restoreend ok")) goto error; goto end; // It was OK. default: case -1: goto error; } if(protocol==PROTO_2) { if(blk->data) { int wret=0; if(act==ACTION_VERIFY) cntr_add(cntr, CMD_DATA, 1); else wret=write_data(asfd, bfd, blk); if(!datpath) blk_free_content(blk); blk->data=NULL; if(wret) goto error; continue; } else if(sb->endfile.buf) { continue; } } switch(sb->path.cmd) { case CMD_DIRECTORY: case CMD_FILE: case CMD_ENC_FILE: case CMD_SOFT_LINK: case CMD_HARD_LINK: case CMD_SPECIAL: case CMD_METADATA: case CMD_ENC_METADATA: case CMD_VSS: case CMD_ENC_VSS: case CMD_VSS_T: case CMD_ENC_VSS_T: case CMD_EFS_FILE: if(strip) { int s; s=strip_path_components(asfd, sb, strip, cntr, protocol); if(s<0) goto error; if(s==0) { // Too many components stripped // - carry on. continue; } // It is OK, sb.path is now stripped. } free_w(&fullpath); if(!(fullpath=prepend_s(restore_prefix, sb->path.buf))) { log_and_send_oom(asfd, __func__); goto error; } if(act==ACTION_RESTORE) { strip_invalid_characters(&fullpath); if(!overwrite_ok(sb, overwrite, #ifdef HAVE_WIN32 bfd, #endif fullpath)) { char msg[512]=""; // Something exists at that path. snprintf(msg, sizeof(msg), "Path exists: %s\n", fullpath); if(restore_interrupt(asfd, sb, msg, cntr, protocol)) goto error; continue; } } break; case CMD_MESSAGE: case CMD_WARNING: log_recvd(&sb->path, cntr, 1); logf("\n"); continue; default: break; } switch(sb->path.cmd) { // These are the same in both protocol1 and protocol2. case CMD_DIRECTORY: if(restore_dir(asfd, sb, fullpath, act, cntr, protocol)) goto error; continue; case CMD_SOFT_LINK: case CMD_HARD_LINK: if(restore_link(asfd, sb, fullpath, act, cntr, protocol, restore_prefix)) goto error; continue; case CMD_SPECIAL: if(restore_special(asfd, sb, fullpath, act, cntr, protocol)) goto error; continue; default: break; } if(protocol==PROTO_2) { if(restore_switch_protocol2(asfd, sb, fullpath, act, bfd, vss_restore, cntr)) goto error; } else { if(restore_switch_protocol1(asfd, sb, fullpath, act, bfd, vss_restore, cntr, encryption_password)) goto error; } } end: ret=0; error: // It is possible for a fd to still be open. bfd->close(bfd, asfd); bfile_free(&bfd); cntr_print_end(cntr); cntr_print(cntr, act); if(!ret) logp("%s finished\n", act_str(act)); else logp("ret: %d\n", ret); sbuf_free(&sb); free_w(&style); if(datpath) { recursive_delete(datpath); free_w(&datpath); } free_w(&fullpath); blk_free(&blk); return ret; }