Exemple #1
0
static struct slist *do_build_manifest(struct manio *manio,
	enum protocol protocol, int entries, int with_data_files)
{
	struct sbuf *sb;
	struct slist *slist=NULL;

	slist=build_slist(protocol, entries, with_data_files);

	for(sb=slist->head; sb; sb=sb->next)
	{
		fail_unless(!manio_write_sbuf(manio, sb));
		if(protocol==PROTO_2)
		{
			struct blk *blk=NULL;
			for(blk=sb->protocol2->bstart;
				blk && blk!=sb->protocol2->bend; blk=blk->next)
			{
				fail_unless(!manio_write_sig_and_path(manio,
					blk));
			}
			if(sbuf_is_filedata(sb) || sbuf_is_vssdata(sb))
			{
				struct iobuf endfile;
				iobuf_from_str(&endfile,
					CMD_END_FILE, (char *)"0:0");
				fail_unless(!iobuf_send_msg_fzp(&endfile,
					manio->fzp));
			}
			hack_protocol2_attr(&sb->attr);
		}
	}

	return slist;
}
Exemple #2
0
int restore_sbuf_protocol1(struct asfd *asfd, struct sbuf *sb, struct bu *bu,
	enum action act, struct sdirs *sdirs,
	enum cntr_status cntr_status, struct conf **cconfs)
{
	if((sb->protocol1->datapth.buf
		&& asfd->write(asfd, &(sb->protocol1->datapth)))
	  || asfd->write(asfd, &sb->attr))
		return -1;
	else if(sbuf_is_filedata(sb)
	  || sbuf_is_vssdata(sb))
	{
		if(!sb->protocol1->datapth.buf)
		{
			logw(asfd, get_cntr(cconfs),
				"Got filedata entry with no datapth: %c:%s\n",
					sb->path.cmd, sb->path.buf);
			return 0;
		}
		return restore_file(asfd, bu, sb, act, sdirs, cconfs);
	}
	else
	{
		if(asfd->write(asfd, &sb->path))
			return -1;
		// If it is a link, send what
		// it points to.
		else if(sbuf_is_link(sb)
		  && asfd->write(asfd, &sb->link)) return -1;
		cntr_add(get_cntr(cconfs), sb->path.cmd, 0);
	}
	return 0;
}
Exemple #3
0
static void set_sbuf_protocol1(struct sbuf *sb)
{
	if(sbuf_is_filedata(sb) || sbuf_is_vssdata(sb))
	{
		char *endfile=gen_endfile_str();
		iobuf_free_content(&sb->endfile);
		sb->endfile.cmd=CMD_END_FILE;
		sb->endfile.len=strlen(endfile);
		fail_unless((sb->endfile.buf
			=strdup_w(endfile, __func__))!=NULL);
	}

	if(sbuf_is_filedata(sb) || sbuf_is_vssdata(sb))
	{
		char *datapth;
		fail_unless((datapth=prepend_s(TREE_DIR, sb->path.buf))!=NULL);
		iobuf_free_content(&sb->protocol1->datapth);
		iobuf_from_str(&sb->protocol1->datapth, CMD_DATAPTH, datapth);
	}
}
Exemple #4
0
static int process_new(struct sdirs *sdirs, struct conf **cconfs,
	struct sbuf *p1b, struct manio *ucmanio)
{
	if(!p1b->path.buf) return 0;
	if(sbuf_is_filedata(p1b)
	  || sbuf_is_vssdata(p1b))
	{
		//logp("need to process new file: %s\n", p1b->path);
		// Flag the things that need to be sent (to the client)
		p1b->flags |= SBUF_SEND_STAT;
		p1b->flags |= SBUF_SEND_PATH;
		return 0;
	}
	return new_non_file(p1b, ucmanio, cconfs);
}
Exemple #5
0
void build_manifest_phase2_from_slist(const char *path,
	struct slist *slist, enum protocol protocol, int short_write)
{
	struct sbuf *sb;
	struct manio *manio=NULL;

	for(sb=slist->head; sb; sb=sb->next)
		set_sbuf(slist, sb, 0 /* with_data_files */);

	fail_unless((manio=manio_open_phase2(path, "wb", protocol))!=NULL);

	for(sb=slist->head; sb; sb=sb->next)
	{
		fail_unless(!manio_write_sbuf(manio, sb));
		if(protocol==PROTO_2)
		{
			struct blk *blk=NULL;
			for(blk=sb->protocol2->bstart;
				blk && blk!=sb->protocol2->bend; blk=blk->next)
			{
				fail_unless(!manio_write_sig_and_path(manio,
					blk));
			}
			if(sbuf_is_filedata(sb) || sbuf_is_vssdata(sb))
			{
				struct iobuf endfile;
				iobuf_from_str(&endfile,
					CMD_END_FILE, (char *)"0:0");
				fail_unless(!iobuf_send_msg_fzp(&endfile,
					manio->fzp));
			}
			hack_protocol2_attr(&sb->attr);
		}
	}

	if(short_write)
	{
		man_off_t *pos;
		fail_unless((pos=manio_tell(manio))!=NULL);
		if(pos->offset>=short_write) pos->offset-=short_write;
		fail_unless(!manio_close_and_truncate(&manio,
			pos, 0 /* compression */));
		man_off_t_free(&pos);
	}
	fail_unless(!manio_close(&manio));
}
Exemple #6
0
static void set_sbuf_protocol2(struct slist *slist, struct sbuf *sb,
	int with_data_files)
{
	struct blk *tail=NULL;
	struct blist *blist=slist->blist;
	if(sbuf_is_filedata(sb) || sbuf_is_vssdata(sb))
	{
		if(blist->tail) tail=blist->tail;
		build_blks(blist, prng_next()%50, with_data_files);
		if(tail)
			sb->protocol2->bstart=tail->next;
		else
			sb->protocol2->bstart=blist->head; // first one

		if(sb->protocol2->bstart)
			sb->protocol2->bend=slist->blist->tail;
	}
}
Exemple #7
0
static
#endif
int get_last_good_entry(struct manio *manio, struct iobuf *result,
                        struct cntr *cntr, struct dpth *dpth, enum protocol protocol,
                        man_off_t **pos)
{
    int ars=0;
    int got_vss_start=0;
    struct sbuf *sb=NULL;
    struct iobuf lastpath;

    if(!(sb=sbuf_alloc(protocol)))
        goto error;

    iobuf_init(&lastpath);

    man_off_t_free(pos);
    if(!(*pos=manio_tell(manio)))
    {
        logp("Could not manio_tell first pos in %s(): %s\n",
             __func__, strerror(errno));
        goto error;
    }

    while(1)
    {
        if(sb->path.buf && !got_vss_start)
        {
            iobuf_free_content(&lastpath);
            iobuf_move(&lastpath, &sb->path);
            if(!sbuf_is_filedata(sb)
                    && !sbuf_is_vssdata(sb))
            {
                iobuf_free_content(result);
                iobuf_move(result, &lastpath);

                man_off_t_free(pos);
                if(!(*pos=manio_tell(manio)))
                {
                    logp("Could not manio_tell pos in %s(): %s\n",
                         __func__, strerror(errno));
                    goto error;
                }
            }
        }
        if(sb->endfile.buf && !got_vss_start)
        {
            iobuf_free_content(result);
            iobuf_move(result, &lastpath);

            man_off_t_free(pos);
            if(!(*pos=manio_tell(manio)))
            {
                logp("Could not manio_tell pos in %s(): %s\n",
                     __func__, strerror(errno));
                goto error;
            }
        }

        sbuf_free_content(sb);
        ars=manio_read(manio, sb);
        if(dpth && set_higher_datapth(sb, dpth)) goto error;

        switch(ars)
        {
        case 0:
            break;
        case 1:
            iobuf_free_content(&lastpath);
            sbuf_free(&sb);
            return 0;
        default:
            if(result->buf)
                logp("Error after %s in %s()\n",
                     result->buf, __func__);
            // Treat error in changed manio as
            // OK - could have been a short write.
            iobuf_free_content(&lastpath);
            sbuf_free(&sb);
            return 0;
        }

        // Some hacks for split_vss.
        switch(sb->path.cmd)
        {
        case CMD_VSS:
        case CMD_ENC_VSS:
            got_vss_start=1;
            break;
        case CMD_VSS_T:
        case CMD_ENC_VSS_T:
            got_vss_start=0;
            break;
        case CMD_FILE:
        case CMD_ENC_FILE:
            if(S_ISDIR(sb->statp.st_mode))
                got_vss_start=0;
            break;
        default:
            break;
        }

        if(cntr)
        {
            // FIX THIS: cannot distinguish between new and
            // changed files.
            cntr_add_changed(cntr, sb->path.cmd);
            if(sb->endfile.buf)
            {
                uint64_t e=strtoull(sb->endfile.buf, NULL, 10);
                cntr_add_bytes(cntr, e);
            }
        }
    }

error:
    iobuf_free_content(&lastpath);
    sbuf_free(&sb);
    man_off_t_free(pos);
    return -1;
}
Exemple #8
0
static int maybe_do_delta_stuff(struct asfd *asfd,
	struct sdirs *sdirs, struct sbuf *cb, struct sbuf *p1b,
	struct manio *ucmanio, struct conf **cconfs)
{
	int oldcompressed=0;
	int compression=p1b->compression;

	// If the file type changed, I think it is time to back it up again
	// (for example, EFS changing to normal file, or back again).
	if(cb->path.cmd!=p1b->path.cmd)
		return process_new_file(sdirs, cconfs, cb, p1b, ucmanio);

	// mtime is the actual file data.
	// ctime is the attributes or meta data.
	if(cb->statp.st_mtime==p1b->statp.st_mtime
	  && cb->statp.st_ctime==p1b->statp.st_ctime)
	{
		// got an unchanged file
		//logp("got unchanged file: %s %c %c\n",
		//	cb->path.buf, cb->path.cmd, p1b->path.cmd);
		return process_unchanged_file(p1b, cb, ucmanio, cconfs);
	}

	if(cb->statp.st_mtime==p1b->statp.st_mtime
	  && cb->statp.st_ctime!=p1b->statp.st_ctime)
	{
		// File data stayed the same, but attributes or meta data
		// changed. We already have the attributes, but may need to get
		// extra meta data.
		// FIX THIS horrible mess.
		if(cb->path.cmd==CMD_ENC_METADATA
		  || p1b->path.cmd==CMD_ENC_METADATA
		  || cb->path.cmd==CMD_EFS_FILE
		  || p1b->path.cmd==CMD_EFS_FILE
		// FIX THIS: make unencrypted metadata use the librsync
		  || cb->path.cmd==CMD_METADATA
		  || p1b->path.cmd==CMD_METADATA
		  || sbuf_is_vssdata(cb)
		  || sbuf_is_vssdata(p1b))
			return process_new_file(sdirs,
				cconfs, cb, p1b, ucmanio);
		// On Windows, we have to back up the whole file if ctime
		// changed, otherwise things like permission changes do not get
		// noticed. So, in that case, fall through to the changed stuff
		// below.
		// Non-Windows clients finish here.
		else if(!get_int(cconfs[OPT_CLIENT_IS_WINDOWS]))
			return process_unchanged_file(p1b,
				cb, ucmanio, cconfs);
	}

	// Got a changed file.
	//logp("got changed file: %s\n", p1b->path.buf);

	// If either old or new is encrypted, or librsync is off, we need to
	// get a new file.
	// FIX THIS horrible mess.
	if(!get_int(cconfs[OPT_LIBRSYNC])
	// FIX THIS: make unencrypted metadata use the librsync
	  || cb->path.cmd==CMD_METADATA
	  || p1b->path.cmd==CMD_METADATA
	  || sbuf_is_encrypted(cb)
	  || sbuf_is_encrypted(p1b)
	  || sbuf_is_vssdata(cb)
	  || sbuf_is_vssdata(p1b))
		return process_new_file(sdirs, cconfs, cb, p1b, ucmanio);

	// Get new files if they have switched between compression on or off.
	if(cb->protocol1->datapth.buf
	  && dpth_protocol1_is_compressed(cb->compression,
	    cb->protocol1->datapth.buf))
		oldcompressed=1;
	if( ( oldcompressed && !compression)
	 || (!oldcompressed &&  compression))
		return process_new_file(sdirs, cconfs, cb, p1b, ucmanio);

	// Otherwise, do the delta stuff (if possible).
	if(sbuf_is_filedata(p1b)
	  || sbuf_is_vssdata(p1b))
	{
		if(process_changed_file(asfd, sdirs, cconfs, cb, p1b,
			sdirs->currentdata)) return -1;
	}
	else
	{
		if(changed_non_file(p1b, ucmanio, p1b->path.cmd, cconfs))
			return -1;
	}
	sbuf_free_content(cb);
	return 1;
}
Exemple #9
0
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;
}
Exemple #10
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;
}
Exemple #11
0
// 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;
}