Ejemplo n.º 1
0
// 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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
Archivo: blk.c Proyecto: vanElden/burp
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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
// 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;
}
Ejemplo n.º 6
0
/* 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;
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
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;
}
Ejemplo n.º 9
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;
}
Ejemplo n.º 10
0
/* 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);
}
Ejemplo n.º 11
0
Archivo: manio.c Proyecto: jkniiv/burp
// 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;
}
Ejemplo n.º 12
0
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;
	}
}
Ejemplo n.º 13
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);
   }
}
Ejemplo n.º 14
0
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;
	}
}
Ejemplo n.º 15
0
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;
}
Ejemplo n.º 16
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);
}
Ejemplo n.º 17
0
// 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;
}
Ejemplo n.º 18
0
/* 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;
}
Ejemplo n.º 19
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;
}
Ejemplo n.º 20
0
// 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;
}
Ejemplo n.º 21
0
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;
}
Ejemplo n.º 22
0
Archivo: rabin.c Proyecto: EmisFR/burp
// 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;
}
Ejemplo n.º 23
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(&copy);
			return 1;
		}

		// Got something.
		if(strcmp(csb->path.buf, copy))
		{
			// Found the next entry.
			free_w(&copy);
			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(&copy);
	return -1;
}
Ejemplo n.º 24
0
// 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);
}
Ejemplo n.º 25
0
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;
}
Ejemplo n.º 26
0
// 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;
}
Ejemplo n.º 27
0
// 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;
}
Ejemplo n.º 28
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;
}
Ejemplo n.º 29
0
void blks_generate_free(void)
{
	free_w(&gbuf);
	blk_free(&blk);
	win_free(&win);
}
Ejemplo n.º 30
0
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;
}