Beispiel #1
0
static
#endif
int forward_before_entry(struct manio *manio, struct iobuf *target,
                         struct cntr *cntr, struct dpth *dpth, enum protocol protocol,
                         man_off_t **pos)
{
    int ars=0;
    struct sbuf *sb=NULL;

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

    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->endfile.buf
                || (sb->path.buf && !sbuf_is_filedata(sb)))
        {
            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:
            sbuf_free(&sb);
            return 0;
        default:
            logp("Error in %s(), but continuing\n",
                 __func__);
            // Treat error in unchanged manio as
            // OK - could have been a short write.
            sbuf_free(&sb);
            return 0;
        }

        if(iobuf_pathcmp(target, &sb->path)<=0)
        {
            sbuf_free(&sb);
            return 0;
        }

        if(cntr)
        {
            cntr_add_same(cntr, sb->path.cmd);
            if(sb->endfile.buf)
            {
                uint64_t e=strtoull(sb->endfile.buf, NULL, 10);
                cntr_add_bytes(cntr, e);
            }
        }
    }

error:
    sbuf_free(&sb);
    man_off_t_free(pos);
    return -1;
}
Beispiel #2
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;
}
Beispiel #3
0
static int do_recursive_delete(const char *d, const char *file, uint8_t delfiles, int32_t name_max)
{
	int ret=RECDEL_ERROR;
	DIR *dirp=NULL;
	struct dirent *entry=NULL;
	struct dirent *result;
	struct stat statp;
	char *directory=NULL;
	char *fullpath=NULL;

	if(!file)
	{
		if(!(directory=prepend_s(d, ""))) goto end;
	}
	else if(!(directory=prepend_s(d, file)))
	{
		log_out_of_memory(__func__);
		goto end;
	}

	if(lstat(directory, &statp))
	{
		// path does not exist.
		ret=RECDEL_OK;
		goto end;
	}

	if(!(dirp=opendir(directory)))
	{
		logp("opendir %s: %s\n", directory, strerror(errno));
		goto end;
	}

	if(!(entry=(struct dirent *)
		malloc_w(sizeof(struct dirent)+name_max+100, __func__)))
			goto end;

	while(1)
	{
		if(readdir_r(dirp, entry, &result) || !result)
		{
			// Got to the end of the directory.
			ret=RECDEL_OK;
			break;
		}

		if(entry->d_ino==0
		  || !strcmp(entry->d_name, ".")
		  || !strcmp(entry->d_name, ".."))
			continue;
		free_w(&fullpath);
		if(!(fullpath=prepend_s(directory, entry->d_name)))
			goto end;

		if(is_dir(fullpath, entry))
		{
			int r;
			if((r=do_recursive_delete(directory, entry->d_name,
				delfiles, name_max))==RECDEL_ERROR)
					goto end;
			// do not overwrite ret with OK if it previously
			// had ENTRIES_REMAINING
			if(r==RECDEL_ENTRIES_REMAINING) ret=r;
		}
		else if(delfiles)
		{
			if(unlink(fullpath))
			{
				logp("unlink %s: %s\n",
					fullpath, strerror(errno));
				ret=RECDEL_ENTRIES_REMAINING;
			}
		}
		else
		{
			ret=RECDEL_ENTRIES_REMAINING;
		}
	}

	if(ret==RECDEL_OK && rmdir(directory))
	{
		logp("rmdir %s: %s\n", directory, strerror(errno));
		ret=RECDEL_ERROR;
	}
end:
	if(dirp) closedir(dirp);
	free_w(&fullpath);
	free_w(&directory);
	free_v((void **)&entry);
	return ret;
}
Beispiel #4
0
int mkpath(char **rpath, const char *limit)
{
	int ret=-1;
	char *cp=NULL;
	struct stat buf;
#ifdef HAVE_WIN32
	int windows_stupidity=0;
#endif
	if((cp=strrchr(*rpath, '/')))
	{
		*cp='\0';
#ifdef HAVE_WIN32
		if(strlen(*rpath)==2 && (*rpath)[1]==':')
		{
			(*rpath)[1]='\0';
			windows_stupidity++;
		}
#endif
		if(!**rpath)
		{
			// We are down to the root, which is OK.
		}
		else if(lstat(*rpath, &buf))
		{
			// does not exist - recurse further down, then come
			// back and try to mkdir it.
			if(mkpath(rpath, limit)) goto end;

			// Require that the user has set up the required paths
			// on the server correctly. I have seen problems with
			// part of the path being a temporary symlink that
			// gets replaced by burp with a proper directory.
			// Allow it to create the actual directory specified,
			// though.

			// That is, if limit is:
			// /var/spool/burp
			// and /var/spool exists, the directory will be
			// created.
			// If only /var exists, the directory will not be
			// created.

			// Caller can give limit=NULL to create the whole
			// path with no limit, as in a restore.
			if(limit && pathcmp(*rpath, limit)<0)
			{
				logp("will not mkdir %s\n", *rpath);
				goto end;
			}
			if(mkdir(*rpath, 0777))
			{
				logp("could not mkdir %s: %s\n", *rpath, strerror(errno));
				goto end;
			}
		}
		else if(S_ISDIR(buf.st_mode))
		{
			// Is a directory - can put the slash back and return.
		}
		else if(S_ISLNK(buf.st_mode))
		{
			// to help with the 'current' symlink
		}
		else
		{
			// something funny going on
			logp("warning: wanted '%s' to be a directory\n",
				*rpath);
		}
	}

	ret=0;
end:
#ifdef HAVE_WIN32
	if(windows_stupidity) (*rpath)[1]=':';
#endif
	if(cp) *cp='/';
	return ret;
}
Beispiel #5
0
static int restore_file_or_get_meta(struct asfd *asfd, BFILE *bfd,
                                    struct sbuf *sb, const char *fname, enum action act,
                                    const char *encpassword, char **metadata, size_t *metalen,
                                    int vss_restore, struct conf *conf)
{
    int ret=0;
    char *rpath=NULL;
    FILE *fp=NULL;

    if(act==ACTION_VERIFY)
    {
        cntr_add(conf->cntr, sb->path.cmd, 1);
        return 0;
    }

    if(build_path(fname, "", &rpath, NULL))
    {
        char msg[256]="";
        // failed - do a warning
        snprintf(msg, sizeof(msg), "build path failed: %s", fname);
        if(restore_interrupt(asfd, sb, msg, conf))
            ret=-1;
        goto end;
    }

#ifndef HAVE_WIN32
    // We always want to open the file if it is on Windows. Otherwise,
    // only open it if we are not doing metadata.
    if(!metadata)
    {
#endif
        if(open_for_restore(asfd, bfd, &fp,
                            rpath, sb, vss_restore, conf))
        {
            ret=-1;
            goto end;
        }
#ifndef HAVE_WIN32
    }
#endif

    if(!ret)
    {
        int enccompressed=0;
        unsigned long long rcvdbytes=0;
        unsigned long long sentbytes=0;

        enccompressed=dpthl_is_compressed(sb->compression, sb->burp1->datapth.buf);
        /*
        		printf("%s \n", fname);
        		if(encpassword && !enccompressed)
        			printf("encrypted and not compressed\n");
        		else if(!encpassword && enccompressed)
        			printf("not encrypted and compressed\n");
        		else if(!encpassword && !enccompressed)
        			printf("not encrypted and not compressed\n");
        		else if(encpassword && enccompressed)
        			printf("encrypted and compressed\n");
        */

        if(metadata)
        {
            ret=transfer_gzfile_inl(asfd, sb, fname, NULL, NULL,
                                    &rcvdbytes, &sentbytes,
                                    encpassword, enccompressed,
                                    conf->cntr, metadata);
            *metalen=sentbytes;
            // skip setting cntr, as we do not actually
            // restore until a bit later
            goto end;
        }
        else
        {
            int c=0;
#ifdef HAVE_WIN32
            ret=transfer_gzfile_inl(asfd, sb, fname, bfd, NULL,
                                    &rcvdbytes, &sentbytes,
                                    encpassword, enccompressed, conf->cntr, NULL);
            //c=bclose(bfd);
#else
            ret=transfer_gzfile_inl(asfd, sb, fname, NULL, fp,
                                    &rcvdbytes, &sentbytes,
                                    encpassword, enccompressed, conf->cntr, NULL);
            c=close_fp(&fp);
#endif
            if(c)
            {
                logp("error closing %s in restore_file_or_get_meta\n", fname);
                ret=-1;
            }
            if(!ret) attribs_set(asfd, rpath,
                                     &(sb->statp), sb->winattr, conf);
        }
        if(ret)
        {
            char msg[256]="";
            snprintf(msg, sizeof(msg),
                     "Could not transfer file in: %s",
                     rpath);
            if(restore_interrupt(asfd, sb, msg, conf))
                ret=-1;
            goto end;
        }
    }
    if(!ret) cntr_add(conf->cntr, sb->path.cmd, 1);
end:
    if(rpath) free(rpath);
    return ret;
}
Beispiel #6
0
int recursive_delete(const char *d, const char *file, bool delfiles)
{
	int n=-1;
	int ret=RECDEL_OK;
	struct dirent **dir;
	struct stat statp;
	char *directory=NULL;

	if(!file)
	{
		if(!(directory=prepend_s(d, "", 0))) return RECDEL_ERROR;
	}
	else if(!(directory=prepend_s(d, file, strlen(file))))
	{
		log_out_of_memory(__FUNCTION__);
		return RECDEL_ERROR;
	}

	if(lstat(directory, &statp))
	{
		// path does not exist.
		free(directory);
		return RECDEL_OK;
	}

	if((n=scandir(directory, &dir, 0, 0))<0)
	{
		logp("scandir %s: %s\n", directory, strerror(errno));
		free(directory);
		return RECDEL_ERROR;
	}
	while(n--)
	{
		char *fullpath=NULL;
		if(dir[n]->d_ino==0
		  || !strcmp(dir[n]->d_name, ".")
		  || !strcmp(dir[n]->d_name, ".."))
			{ free(dir[n]); continue; }
		if(!(fullpath=prepend_s(directory,
			dir[n]->d_name, strlen(dir[n]->d_name))))
				break;

		if(is_dir(fullpath))
		{
			int r;
			if((r=recursive_delete(directory,
				dir[n]->d_name, delfiles))==RECDEL_ERROR)
			{
				free(fullpath);
				break;
			}
			// do not overwrite ret with OK if it previously
			// had ENTRIES_REMAINING
			if(r==RECDEL_ENTRIES_REMAINING) ret=r;
		}
		else if(delfiles)
		{
			if(unlink(fullpath))
			{
				logp("unlink %s: %s\n",
					fullpath, strerror(errno));
				ret=RECDEL_ENTRIES_REMAINING;
			}
		}
		else
		{
			ret=RECDEL_ENTRIES_REMAINING;
		}
		free(fullpath);
		free(dir[n]);
	}
	if(n>0)
	{
		ret=RECDEL_ERROR;
		for(; n>0; n--) free(dir[n]);
	}
	free(dir);

	if(ret==RECDEL_OK && rmdir(directory))
	{
		logp("rmdir %s: %s\n", directory, strerror(errno));
		ret=RECDEL_ERROR;
	}
	free(directory);
	return ret;
}
Beispiel #7
0
static int load_signature_and_send_delta(struct asfd *asfd,
	BFILE *bfd, FILE *in,
	unsigned long long *bytes, unsigned long long *sentbytes,
	struct conf *conf, size_t datalen)
{
	rs_job_t *job;
	rs_result r;
	rs_signature_t *sumset=NULL;
	unsigned char checksum[MD5_DIGEST_LENGTH+1];
	rs_filebuf_t *infb=NULL;
	rs_filebuf_t *outfb=NULL;
	rs_buffers_t rsbuf;
	memset(&rsbuf, 0, sizeof(rsbuf));

	if(load_signature(asfd, &sumset, conf)) return -1;

	if(!(job=rs_delta_begin(sumset)))
	{
		logp("could not start delta job.\n");
		rs_free_sumset(sumset);
		return RS_IO_ERROR;
	}

	if(!(infb=rs_filebuf_new(asfd, bfd,
		in, NULL, -1, ASYNC_BUF_LEN, datalen, conf->cntr))
	  || !(outfb=rs_filebuf_new(asfd, NULL, NULL,
		NULL, asfd->fd, ASYNC_BUF_LEN, -1, conf->cntr)))
	{
		logp("could not rs_filebuf_new for delta\n");
		if(infb) rs_filebuf_free(infb);
		return -1;
	}

	while(1)
	{
		rs_result delresult;
		delresult=rs_async(job, &rsbuf, infb, outfb);
		if(delresult==RS_DONE)
		{
			r=delresult;
			break;
		}
		else if(delresult==RS_BLOCKED || delresult==RS_RUNNING)
		{
			// Keep going
		}
		else
		{
			logp("error in rs_async for delta: %d\n", delresult);
			r=delresult;
			break;
		}
		// FIX ME: get it to read stuff (errors, for example) here too.
		if(asfd->as->rw(asfd->as)) return -1;
	}

	if(r!=RS_DONE)
		logp("delta loop returned: %d\n", r);

	if(r==RS_DONE)
	{
		*bytes=infb->bytes;
		*sentbytes=outfb->bytes;
		if(!MD5_Final(checksum, &(infb->md5)))
		{
			logp("MD5_Final() failed\n");
			r=RS_IO_ERROR;
		}
	}
	rs_filebuf_free(infb);
	rs_filebuf_free(outfb);
	rs_job_free(job);
	rs_free_sumset(sumset);

	if(r==RS_DONE && write_endfile(asfd, *bytes, checksum))
		return -1;

	return r;
}
Beispiel #8
0
/*
 * The buf is already using BUF for an output buffer, and probably
 * contains some buffered output now.  Write this out to F, and reset
 * the buffer cursor.
 */
rs_result rs_outfilebuf_drain(rs_job_t *job, rs_buffers_t *buf, void *opaque)
{
	rs_filebuf_t *fb=(rs_filebuf_t *)opaque;
	int fd=fb->fd;
	size_t wlen;

	//logp("in rs_outfilebuf_drain\n");

	/* This is only allowed if either the buf has no output buffer
	 * yet, or that buffer could possibly be BUF. */
	if(!buf->next_out)
	{
		if(buf->avail_out)
		{
			logp("buf->avail_out is %d in %s\n",
				buf->avail_out, __func__);
			return RS_IO_ERROR;
		}
		buf->next_out = fb->buf;
		buf->avail_out = fb->buf_len;
		return RS_DONE;
	}

	if(buf->avail_out > fb->buf_len)
	{
		logp("buf->avail_out > fb->buf_len (%d > %d) in %s\n",
			buf->avail_out, fb->buf_len, __func__);
		return RS_IO_ERROR;
	}
	if(buf->next_out < fb->buf)
	{
		logp("buf->next_out < fb->buf (%p < %p) in %s\n",
			buf->next_out, fb->buf, __func__);
		return RS_IO_ERROR;
	}
	if(buf->next_out > fb->buf + fb->buf_len)
	{
		logp("buf->next_out > fb->buf + fb->buf_len in %s\n",
			__func__);
		return RS_IO_ERROR;
	}

	if((wlen=buf->next_out-fb->buf)>0)
	{
		//logp("wlen: %d\n", wlen);
		if(fd>0)
		{
			size_t w=wlen;
			static struct iobuf *wbuf=NULL;
			if(!wbuf && !(wbuf=iobuf_alloc())) return RS_IO_ERROR;
			wbuf->cmd=CMD_APPEND;
			wbuf->buf=fb->buf;
			wbuf->len=wlen;
			switch(fb->asfd->append_all_to_write_buffer(
				fb->asfd, wbuf))
			{
				case APPEND_OK: break;
				case APPEND_BLOCKED: return RS_BLOCKED;
				case APPEND_ERROR:
				default: return RS_IO_ERROR;
			}
			fb->bytes+=w;
		}
		else
		{
			size_t result=0;
			result=fzp_write(fb->fzp, fb->buf, wlen);
			if(wlen!=result)
			{
				logp("error draining buf to file: %s",
						strerror(errno));
				return RS_IO_ERROR;
			}
		}
	}

	buf->next_out = fb->buf;
	buf->avail_out = fb->buf_len;

	return RS_DONE;
}
Beispiel #9
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;
}
Beispiel #10
0
static int deal_with_data(struct asfd *asfd, struct sbuf *sb,
	BFILE *bfd, size_t *datalen, struct conf *conf)
{
	int ret=-1;
	int forget=0;
	FILE *fp=NULL;
	size_t elen=0;
	char *extrameta=NULL;
	unsigned long long bytes=0;

	sb->compression=conf->compression;

	iobuf_copy(&sb->path, asfd->rbuf);
	iobuf_init(asfd->rbuf);

#ifdef HAVE_WIN32
	if(win32_lstat(sb->path.buf, &sb->statp, &sb->winattr))
#else
	if(lstat(sb->path.buf, &sb->statp))
#endif
	{
		logw(asfd, conf, "Path has vanished: %s", sb->path.buf);
		if(forget_file(asfd, sb, conf)) goto error;
		goto end;
	}

	if(size_checks(asfd, sb, conf)) forget++;

	if(!forget)
	{
		sb->compression=in_exclude_comp(conf->excom,
			sb->path.buf, conf->compression);
		if(attribs_encode(sb)) goto error;
		else if(open_file_for_sendl(asfd,
#ifdef HAVE_WIN32
			bfd, NULL,
#else
			NULL, &fp,
#endif
			sb->path.buf, sb->winattr, datalen, conf->atime, conf))
				forget++;
	}

	if(forget)
	{
		if(forget_file(asfd, sb, conf)) goto error;
		goto end;
	}

	if(sb->path.cmd==CMD_METADATA
	  || sb->path.cmd==CMD_ENC_METADATA
	  || sb->path.cmd==CMD_VSS
	  || sb->path.cmd==CMD_ENC_VSS
#ifdef HAVE_WIN32
	  || conf->strip_vss
#endif
	  )
	{
		if(get_extrameta(asfd,
#ifdef HAVE_WIN32
			bfd,
#endif
			sb->path.buf, &sb->statp, &extrameta, &elen,
			sb->winattr, conf, datalen))
		{
			logw(asfd, conf, "Meta data error for %s", sb->path.buf);
			goto end;
		}
		if(extrameta)
		{
#ifdef HAVE_WIN32
			if(conf->strip_vss)
			{
				free(extrameta);
				extrameta=NULL;
				elen=0;
			}
#endif
		}
		else
		{
			logw(asfd, conf,
				"No meta data after all: %s", sb->path.buf);
			goto end;
		}
	}

	if(sb->path.cmd==CMD_FILE
	  && sb->burp1->datapth.buf)
	{
		unsigned long long sentbytes=0;
		// Need to do sig/delta stuff.
		if(asfd->write(asfd, &(sb->burp1->datapth))
		  || asfd->write(asfd, &sb->attr)
		  || asfd->write(asfd, &sb->path)
		  || load_signature_and_send_delta(asfd, bfd, fp,
			&bytes, &sentbytes, conf, *datalen))
		{
			logp("error in sig/delta for %s (%s)\n",
				sb->path.buf, sb->burp1->datapth.buf);
			goto end;
		}
		else
		{
			cntr_add(conf->cntr, CMD_FILE_CHANGED, 1);
			cntr_add_bytes(conf->cntr, bytes);
			cntr_add_sentbytes(conf->cntr, sentbytes);
		}
	}
	else
	{
		//logp("need to send whole file: %s\n", sb.path);
		// send the whole file.

		if((asfd->write(asfd, &sb->attr)
		  || asfd->write(asfd, &sb->path))
		  || send_whole_file_w(asfd, sb, NULL, 0, &bytes,
			conf->encryption_password, conf, sb->compression,
			bfd, fp, extrameta, elen, *datalen))
				goto end;
		else
		{
			cntr_add(conf->cntr, sb->path.cmd, 1);
			cntr_add_bytes(conf->cntr, bytes);
			cntr_add_sentbytes(conf->cntr, bytes);
		}
	}

end:
	ret=0;
error:
#ifdef HAVE_WIN32
	// If using Windows do not close bfd - it needs
	// to stay open to read VSS/file data/VSS.
	// It will get closed either when given a
	// different file path, or when this function
	// exits.
#else
	close_file_for_sendl(NULL, &fp, asfd);
#endif
	sbuf_free_content(sb);
	if(extrameta) free(extrameta);
	return ret;
}
Beispiel #11
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;
}
Beispiel #12
0
// FIX THIS: Maybe should be in bfile.c.
enum ofr_e open_for_restore(struct asfd *asfd, BFILE *bfd, const char *path,
	struct sbuf *sb, int vss_restore, struct cntr *cntr,
	enum protocol protocol)
{
	static int flags;
        if(bfd->mode!=BF_CLOSED)
        {
#ifdef HAVE_WIN32
		if(bfd->path && !strcmp(bfd->path, path))
		{
			// Already open after restoring the VSS data.
			// Time now for the actual file data.
			return OFR_OK;
		}
		else
		{
#endif
			if(bfd->close(bfd, asfd))
			{
				logp("error closing %s in %s()\n",
					path, __func__);
				return OFR_ERROR;
			}
#ifdef HAVE_WIN32
		}
#endif
	}

#ifdef HAVE_WIN32
	// Some massive hacks to work around times that winattr was not
	// getting set correctly inside server side backups.
	// The EFS one will stop burp segfaulting when restoring affected
	// EFS files.
	if(sb->path.cmd==CMD_EFS_FILE)
		sb->winattr |= FILE_ATTRIBUTE_ENCRYPTED;
	if(S_ISDIR(sb->statp.st_mode))
		sb->winattr |= FILE_ATTRIBUTE_DIRECTORY;
#endif

	bfile_init(bfd, sb->winattr, cntr);
#ifdef HAVE_WIN32
	bfd->set_win32_api(bfd, vss_restore);
#endif
	if(S_ISDIR(sb->statp.st_mode))
	{
		// Windows directories are treated as having file data.
		flags=O_WRONLY|O_BINARY;
		mkdir(path, 0777);
	}
	else
		flags=O_WRONLY|O_BINARY|O_CREAT|O_TRUNC;

	if(bfd->open(bfd, asfd, path, flags, S_IRUSR | S_IWUSR))
	{
		berrno be;
		berrno_init(&be);
		char msg[256]="";
		snprintf(msg, sizeof(msg), "Could not open for writing %s: %s",
			path, berrno_bstrerror(&be, errno));
		if(restore_interrupt(asfd, sb, msg, cntr, protocol))
			return OFR_ERROR;
		return OFR_CONTINUE;
	}
	// Add attributes to bfd so that they can be set when it is closed.
	bfd->winattr=sb->winattr;
	memcpy(&bfd->statp, &sb->statp, sizeof(struct stat));
	return OFR_OK;
}
Beispiel #13
0
// Combine the phase1 and phase2 files into a new manifest.
int backup_phase3_server(const char *phase2data, const char *unchangeddata, const char *manifest, int recovery, int compress, const char *client, struct cntr *p1cntr, struct cntr *cntr, struct config *cconf)
{
	int ars=0;
	int ret=0;
	int pcmp=0;
	FILE *ucfp=NULL;
	FILE *p2fp=NULL;
	FILE *mp=NULL;
	gzFile mzp=NULL;
	struct sbuf ucb;
	struct sbuf p2b;
	char *manifesttmp=NULL;

	logp("Begin phase3 (merge manifests)\n");

	if(!(manifesttmp=get_tmp_filename(manifest))) return -1;

        if(!(ucfp=open_file(unchangeddata, "rb"))
	  || !(p2fp=open_file(phase2data, "rb"))
	  || (compress && !(mzp=gzopen_file(manifesttmp, comp_level(cconf))))
          || (!compress && !(mp=open_file(manifesttmp, "wb"))))
	{
		close_fp(&ucfp);
		gzclose_fp(&mzp);
		close_fp(&p2fp);
		close_fp(&mp);
		free(manifesttmp);
		return -1;
	}

	init_sbuf(&ucb);
	init_sbuf(&p2b);

	while(ucfp || p2fp)
	{
		if(ucfp && !ucb.path && (ars=sbuf_fill(ucfp, NULL, &ucb, cntr)))
		{
			if(ars<0) { ret=-1; break; }
			// ars==1 means it ended ok.
			close_fp(&ucfp);
		}
		if(p2fp && !p2b.path && (ars=sbuf_fill(p2fp, NULL, &p2b, cntr)))
		{
			if(ars<0) { ret=-1; break; }
			// ars==1 means it ended ok.
			close_fp(&p2fp);

			// In recovery mode, only want to read to the last
			// entry in the phase 2 file.
			if(recovery) break;
		}

		if(ucb.path && !p2b.path)
		{
			write_status(client, STATUS_MERGING, ucb.path,
				p1cntr, cntr);
			if(sbuf_to_manifest(&ucb, mp, mzp)) { ret=-1; break; }
			free_sbuf(&ucb);
		}
		else if(!ucb.path && p2b.path)
		{
			write_status(client, STATUS_MERGING, p2b.path,
				p1cntr, cntr);
			if(sbuf_to_manifest(&p2b, mp, mzp)) { ret=-1; break; }
			free_sbuf(&p2b);
		}
		else if(!ucb.path && !p2b.path) 
		{
			continue;
		}
		else if(!(pcmp=sbuf_pathcmp(&ucb, &p2b)))
		{
			// They were the same - write one and free both.
			write_status(client, STATUS_MERGING, p2b.path,
				p1cntr, cntr);
			if(sbuf_to_manifest(&p2b, mp, mzp)) { ret=-1; break; }
			free_sbuf(&p2b);
			free_sbuf(&ucb);
		}
		else if(pcmp<0)
		{
			write_status(client, STATUS_MERGING, ucb.path,
				p1cntr, cntr);
			if(sbuf_to_manifest(&ucb, mp, mzp)) { ret=-1; break; }
			free_sbuf(&ucb);
		}
		else
		{
			write_status(client, STATUS_MERGING, p2b.path,
				p1cntr, cntr);
			if(sbuf_to_manifest(&p2b, mp, mzp)) { ret=-1; break; }
			free_sbuf(&p2b);
		}
	}

	free_sbuf(&ucb);
	free_sbuf(&p2b);

	close_fp(&p2fp);
	close_fp(&ucfp);
	if(close_fp(&mp))
	{
		logp("error closing %s in backup_phase3_server\n",
			manifesttmp);
		ret=-1;
	}
	if(gzclose_fp(&mzp))
	{
		logp("error gzclosing %s in backup_phase3_server\n",
			manifesttmp);
		ret=-1;
	}

	if(!ret)
	{
		if(do_rename(manifesttmp, manifest))
			ret=-1;
		else
		{
			unlink(phase2data);
			unlink(unchangeddata);
		}
	}

	free(manifesttmp);

	logp("End phase3 (merge manifests)\n");

	return ret;
}
Beispiel #14
0
int set_extrameta(const char *path, char cmd, struct stat *statp, const char *extrameta, size_t metalen, struct cntr *cntr)
{
	size_t l=0;
	char cmdtmp='\0';
	unsigned int s=0;
	const char *metadata=NULL;
	int errors=0;

	metadata=extrameta;
	l=metalen;
	while(l>0)
	{
		char *m=NULL;
		if((sscanf(metadata, "%c%08X", &cmdtmp, &s))!=2)
		{
			logw(cntr, "sscanf of metadata failed for %s: %s\n",
				path, metadata);
			return -1;
		}
		metadata+=9;
		l-=9;
		if(!(m=(char *)malloc(s+1)))
		{
			logp("out of memory\n");
			return -1;
		}
		memcpy(m, metadata, s);
		m[s]='\0';

		metadata+=s;
		l-=s;

		switch(cmdtmp)
		{
#if defined(HAVE_LINUX_OS) || \
    defined(HAVE_FREEBSD_OS) || \
    defined(HAVE_OPENBSD_OS) || \
    defined(HAVE_NETBSD_OS)
#ifdef HAVE_ACL
			case META_ACCESS_ACL:
				if(set_acl(path, statp, m, s, cmdtmp, cntr))
					errors++;
				break;
			case META_DEFAULT_ACL:
				if(set_acl(path, statp, m, s, cmdtmp, cntr))
					errors++;
				break;
#endif
#endif
#if defined(HAVE_LINUX_OS)
#ifdef HAVE_XATTR
			case META_XATTR:
				if(set_xattr(path, statp, m, s, cmdtmp, cntr))
					errors++;
				break;
#endif
#endif
#if defined(HAVE_FREEBSD_OS) || \
    defined(HAVE_OPENBSD_OS) || \
    defined(HAVE_NETBSD_OS)
#ifdef HAVE_XATTR
			case META_XATTR_BSD:
				if(set_xattr(path, statp, m, s, cmdtmp, cntr))
					errors++;
				break;
#endif
#endif
			default:
				logp("unknown metadata: %c\n", cmdtmp);
				logw(cntr, "unknown metadata: %c\n", cmdtmp);
				errors++;
				break;
				
		}
		free(m);
	}

	return errors;
}
Beispiel #15
0
int authorise_client(struct asfd *asfd,
	struct conf *conf, char **server_version)
{
	int ret=-1;
	char hello[256]="";
	struct iobuf *rbuf=asfd->rbuf;

	snprintf(hello, sizeof(hello), "hello:%s", VERSION);
	if(asfd->write_str(asfd, CMD_GEN, hello))
	{
		logp("problem with auth\n");
		goto end;
	}

	if(asfd->read(asfd)
	  || rbuf->cmd!=CMD_GEN
	  || strncmp_w(rbuf->buf, "whoareyou"))
	{
		logp("problem with auth\n");
		goto end;
	}
	if(rbuf->buf)
	{
		char *cp=NULL;
		if((cp=strchr(rbuf->buf, ':')))
		{
			cp++;
			if(cp)
			{
				if(!(*server_version=strdup(cp)))
				{
					log_out_of_memory(__func__);
					goto end;
				}
			}
		}
		iobuf_free_content(rbuf);
	}

	if(asfd->write_str(asfd, CMD_GEN, conf->cname)
	  || asfd->read_expect(asfd, CMD_GEN, "okpassword")
	  || asfd->write_str(asfd, CMD_GEN, conf->password)
	  || asfd->read(asfd))
	{
		logp("problem with auth\n");
		goto end;
	}

	if(rbuf->cmd==CMD_WARNING) // special case for the version warning
	{
		//logw(conf->p1cntr, rbuf->buf);
		logp("WARNING: %s\n", rbuf->buf);
		cntr_add(conf->cntr, rbuf->cmd, 0);
		iobuf_free_content(rbuf);
		if(asfd->read(asfd))
		{
			logp("problem with auth\n");
			goto end;
		}
	}
	if(rbuf->cmd==CMD_GEN && !strcmp(rbuf->buf, "ok"))
	{
		// It is OK.
		logp("auth ok\n");
	}
	else
	{
		iobuf_log_unexpected(rbuf, __func__);
		goto end;
	}

	ret=0;
end:
	iobuf_free_content(rbuf);
	return ret;
}
Beispiel #16
0
int backup_phase1_server_all(struct async *as,
	struct sdirs *sdirs, struct conf *conf)
{
	int ars=0;
	int ret=-1;
	struct sbuf *sb=NULL;
	gzFile p1zp=NULL;
	char *phase1tmp=NULL;
	struct asfd *asfd=as->asfd;

	logp("Begin phase1 (file system scan)\n");

	if(!(phase1tmp=get_tmp_filename(sdirs->phase1data)))
		goto end;
	if(!(p1zp=gzopen_file(phase1tmp, comp_level(conf))))
		goto end;
	if(!(sb=sbuf_alloc(conf)))
		goto end;

	while(1)
	{
		sbuf_free_content(sb);
		if(conf->protocol==PROTO_BURP1)
			ars=sbufl_fill(sb, asfd, NULL, NULL, conf->cntr);
		else
			ars=sbuf_fill(sb, asfd, NULL, NULL, NULL, conf);

		if(ars)
		{
			if(ars<0) goto end;
			//ars==1 means it ended ok.
			// Last thing the client sends is 'backupphase2', and
			// it wants an 'ok' reply.
			if(asfd->write_str(asfd, CMD_GEN, "ok")
			  || send_msg_zp(p1zp, CMD_GEN,
				"phase1end", strlen("phase1end")))
					goto end;
			break;
		}
		if(write_status(STATUS_SCANNING, sb->path.buf, conf)
		  || sbufl_to_manifest_phase1(sb, NULL, p1zp))
			goto end;
		cntr_add_phase1(conf->cntr, sb->path.cmd, 0);

		if(sb->path.cmd==CMD_FILE
		  || sb->path.cmd==CMD_ENC_FILE
		  || sb->path.cmd==CMD_METADATA
		  || sb->path.cmd==CMD_ENC_METADATA
		  || sb->path.cmd==CMD_EFS_FILE)
			cntr_add_val(conf->cntr, CMD_BYTES_ESTIMATED,
				(unsigned long long)sb->statp.st_size, 0);
	}

	if(gzclose_fp(&p1zp))
	{
		logp("error closing %s in backup_phase1_server\n", phase1tmp);
		goto end;
	}
	// Possible rename race condition is of no consequence here, because
	// the working directory will always get deleted if phase1 is not
	// complete.
	if(do_rename(phase1tmp, sdirs->phase1data))
		goto end;

	//cntr_print(p1cntr, cntr, ACTION_BACKUP);

	logp("End phase1 (file system scan)\n");
	ret=0;
end:
	free(phase1tmp);
	gzclose_fp(&p1zp);
	sbuf_free(&sb);
	return ret;
}
Beispiel #17
0
static int do_backup_phase2_client(struct config *conf, int resume, struct cntr *cntr)
{
    int ret=0;
    int quit=0;
    char cmd;
    char *buf=NULL;
    size_t len=0;
    char attribs[MAXSTRING];

    struct sbuf sb;

    init_sbuf(&sb);

    if(!resume)
    {
        // Only do this bit if the server did not tell us to resume.
        if(async_write_str(CMD_GEN, "backupphase2")
                || async_read_expect(CMD_GEN, "ok"))
            return -1;
    }

    while(!quit)
    {
        if(async_read(&cmd, &buf, &len))
        {
            ret=-1;
            quit++;
        }
        else if(buf)
        {
            //logp("now: %c:%s\n", cmd, buf);
            if(cmd==CMD_DATAPTH)
            {
                sb.datapth=buf;
                buf=NULL;
                continue;
            }
            else if(cmd==CMD_STAT)
            {
                // Ignore the stat data - we will fill it
                // in again. Some time may have passed by now,
                // and it is best to make it as fresh as
                // possible.
                free(buf);
                buf=NULL;
                continue;
            }
            else if(cmd==CMD_FILE
                    || cmd==CMD_ENC_FILE
                    || cmd==CMD_METADATA
                    || cmd==CMD_ENC_METADATA
                    || cmd==CMD_EFS_FILE)
            {
                int forget=0;
                int64_t winattr=0;
                struct stat statbuf;
                char *extrameta=NULL;
                size_t elen=0;
                unsigned long long bytes=0;
                BFILE bfd;
                FILE *fp=NULL;

                sb.path=buf;
                buf=NULL;

#ifdef HAVE_WIN32
                if(win32_lstat(sb.path, &statbuf, &winattr))
#else
                if(lstat(sb.path, &statbuf))
#endif
                {
                    logw(cntr, "Path has vanished: %s", sb.path);
                    if(forget_file(&sb, cmd, cntr))
                    {
                        ret=-1;
                        quit++;
                    }
                    free_sbuf(&sb);
                    continue;
                }

                if(conf->min_file_size
                        && statbuf.st_size<(boffset_t)conf->min_file_size)
                {
                    logw(cntr, "File size decreased below min_file_size after initial scan: %s", sb.path);
                    forget++;
                }
                else if(conf->max_file_size
                        && statbuf.st_size>(boffset_t)conf->max_file_size)
                {
                    logw(cntr, "File size increased above max_file_size after initial scan: %s", sb.path);
                    forget++;
                }

                if(!forget)
                {
                    encode_stat(attribs, &statbuf, winattr);
                    if(open_file_for_send(&bfd, &fp,
                                          sb.path, winattr, cntr))
                        forget++;
                }

                if(forget)
                {
                    if(forget_file(&sb, cmd, cntr))
                    {
                        ret=-1;
                        quit++;
                    }
                    free_sbuf(&sb);
                    continue;
                }

                if(cmd==CMD_METADATA
                        || cmd==CMD_ENC_METADATA)
                {
                    if(get_extrameta(sb.path,
                                     &statbuf, &extrameta, &elen,
                                     cntr))
                    {
                        logw(cntr, "Meta data error for %s", sb.path);
                        free_sbuf(&sb);
                        close_file_for_send(&bfd, &fp);
                        continue;
                    }
                    if(!extrameta)
                    {
                        logw(cntr, "No meta data after all: %s", sb.path);
                        free_sbuf(&sb);
                        close_file_for_send(&bfd, &fp);
                        continue;
                    }
                }

                if(cmd==CMD_FILE && sb.datapth)
                {
                    unsigned long long sentbytes=0;
                    // Need to do sig/delta stuff.
                    if(async_write_str(CMD_DATAPTH, sb.datapth)
                            || async_write_str(CMD_STAT, attribs)
                            || async_write_str(CMD_FILE, sb.path)
                            || load_signature_and_send_delta(
                                &bfd, fp,
                                &bytes, &sentbytes, cntr))
                    {
                        logp("error in sig/delta for %s (%s)\n", sb.path, sb.datapth);
                        ret=-1;
                        quit++;
                    }
                    else
                    {
                        do_filecounter(cntr, CMD_FILE_CHANGED, 1);
                        do_filecounter_bytes(cntr, bytes);
                        do_filecounter_sentbytes(cntr, sentbytes);
                    }
                }
                else
                {
                    //logp("need to send whole file: %s\n",
                    //	sb.path);
                    // send the whole file.
                    if(async_write_str(CMD_STAT, attribs)
                            || async_write_str(cmd, sb.path)
                            || send_whole_file_w(cmd, sb.path,
                                                 NULL, 0, &bytes,
                                                 conf->encryption_password,
                                                 cntr, conf->compression,
                                                 &bfd, fp,
                                                 extrameta, elen))
                    {
                        ret=-1;
                        quit++;
                    }
                    else
                    {
                        do_filecounter(cntr, cmd, 1);
                        do_filecounter_bytes(cntr, bytes);
                        do_filecounter_sentbytes(cntr, bytes);
                    }
                }
                close_file_for_send(&bfd, &fp);
                free_sbuf(&sb);
                if(extrameta) free(extrameta);
            }
            else if(cmd==CMD_WARNING)
            {
                do_filecounter(cntr, cmd, 0);
                free(buf);
                buf=NULL;
            }
            else if(cmd==CMD_GEN && !strcmp(buf, "backupphase2end"))
            {
                if(async_write_str(CMD_GEN, "okbackupphase2end"))
                    ret=-1;
                quit++;
            }
            else
            {
                logp("unexpected cmd from server: %c %s\n",
                     cmd, buf);
                ret=-1;
                quit++;
                free(buf);
                buf=NULL;
            }
        }
    }
    return ret;
}
Beispiel #18
0
/*
 * If the stream has no more data available, read some from F into
 * BUF, and let the stream use that.  On return, SEEN_EOF is true if
 * the end of file has passed into the stream.
 */
rs_result rs_infilebuf_fill(rs_job_t *job, rs_buffers_t *buf, void *opaque)
{
	int len=0;
	rs_filebuf_t *fb=(rs_filebuf_t *) opaque;
	struct cntr *cntr;
	int fd=fb->fd;
	cntr=fb->cntr;

	//logp("rs_infilebuf_fill\n");

	/* This is only allowed if either the buf has no input buffer
	 * yet, or that buffer could possibly be BUF. */
	if(buf->next_in)
	{
		//logp("infilebuf avail_in %d buf_len %d\n",
		//	buf->avail_in, fb->buf_len);
		if(buf->avail_in > fb->buf_len)
		{
			logp("buf->avail_in > fb->buf_len (%d > %d) in %s\n",
				buf->avail_in, fb->buf_len, __func__);
			return RS_IO_ERROR;
		}
		if(buf->next_in < fb->buf)
		{
			logp("buf->next_in < fb->buf in %s\n", __func__);
			return RS_IO_ERROR;
		}
		if(buf->next_in > fb->buf + fb->buf_len)
		{
			logp("buf->next_in > fb->buf + fb->buf_len in %s\n",
				__func__);
			return RS_IO_ERROR;
		}
	}
	else
	{
		if(buf->avail_in)
		{
			logp("buf->avail_in is %d in %s\n",
				buf->avail_in, __func__);
			return RS_IO_ERROR;
		}
	}

	if(buf->eof_in) return RS_DONE;

	if(buf->avail_in)
		/* Still some data remaining.  Perhaps we should read
		   anyhow? */
		return RS_DONE;

	if(fd>=0)
	{
		static struct iobuf *rbuf=NULL;
		rbuf=fb->asfd->rbuf;

		if(fb->asfd->read(fb->asfd)) return RS_IO_ERROR;
		if(rbuf->cmd==CMD_APPEND)
		{
			//logp("got '%c' in fd infilebuf: %d\n",
			//	CMD_APPEND, rbuf->len);
			memcpy(fb->buf, rbuf->buf, rbuf->len);
			len=rbuf->len;
			iobuf_free_content(rbuf);
		}
		else if(rbuf->cmd==CMD_END_FILE)
		{
			iobuf_free_content(rbuf);
			//logp("got %c in fd infilebuf\n", CMD_END_FILE);
			buf->eof_in=1;
			return RS_DONE;
		}
		else if(rbuf->cmd==CMD_WARNING)
		{
			logp("WARNING: %s\n", rbuf->buf);
			cntr_add(cntr, rbuf->cmd, 0);
			iobuf_free_content(rbuf);
			return RS_DONE;
		}
		else
		{
			iobuf_log_unexpected(rbuf, __func__);
			iobuf_free_content(rbuf);
			return RS_IO_ERROR;
		}
	}
	else if(fb->bfd)
	{
		if(fb->do_known_byte_count)
		{
			if(fb->data_len>0)
			{
				len=fb->bfd->read(fb->bfd, fb->buf,
					min(fb->buf_len, fb->data_len));
				fb->data_len-=len;
			}
			else
			{
				// We have already read as much data as the VSS
				// header told us to, so set len=0 in order to
				// finish up.
				len=0;
			}
		}
		else
			len=fb->bfd->read(fb->bfd, fb->buf, fb->buf_len);
		if(len==0)
		{
			//logp("bread: eof\n");
			buf->eof_in=1;
			return RS_DONE;
		}
		else if(len<0)
		{
			logp("rs_infilebuf_fill: error in bread\n");
			return RS_IO_ERROR;
		}
		//logp("bread: ok: %d\n", len);
		fb->bytes+=len;
		if(!MD5_Update(&(fb->md5), fb->buf, len))
		{
			logp("rs_infilebuf_fill: MD5_Update() failed\n");
			return RS_IO_ERROR;
		}
	}
	else if(fb->fzp)
	{
		if((len=fzp_read(fb->fzp, fb->buf, fb->buf_len))<=0)
		{
			// This will happen if file size is a multiple of
			// input block len.
			if(fzp_eof(fb->fzp))
			{
				buf->eof_in=1;
				return RS_DONE;
			}
			else
			{
				logp("rs_infilebuf_fill: got return %d when trying to read\n", len);
				return RS_IO_ERROR;
			}
		}
		fb->bytes+=len;
		if(!MD5_Update(&(fb->md5), fb->buf, len))
		{
			logp("rs_infilebuf_fill: MD5_Update() failed\n");
			return RS_IO_ERROR;
		}
	}

	buf->avail_in = len;
	buf->next_in = fb->buf;

	return RS_DONE;
}
Beispiel #19
0
static int load_signature_and_send_delta(BFILE *bfd, FILE *in, unsigned long long *bytes, unsigned long long *sentbytes, struct cntr *cntr)
{
    rs_job_t *job;
    rs_result r;
    rs_signature_t *sumset=NULL;
    unsigned char checksum[MD5_DIGEST_LENGTH+1];
    rs_filebuf_t *infb=NULL;
    rs_filebuf_t *outfb=NULL;
    rs_buffers_t rsbuf;
    memset(&rsbuf, 0, sizeof(rsbuf));

    if(load_signature(&sumset, cntr)) return -1;

//logp("start delta\n");

    if(!(job=rs_delta_begin(sumset)))
    {
        logp("could not start delta job.\n");
        rs_free_sumset(sumset);
        return RS_IO_ERROR;
    }

    if(!(infb=rs_filebuf_new(bfd, in, NULL, -1, ASYNC_BUF_LEN, cntr))
            || !(outfb=rs_filebuf_new(NULL, NULL, NULL, async_get_fd(), ASYNC_BUF_LEN, cntr)))
    {
        logp("could not rs_filebuf_new for delta\n");
        if(infb) rs_filebuf_free(infb);
        return -1;
    }
//logp("start delta loop\n");

    while(1)
    {
        size_t wlen=0;
        rs_result delresult;
        delresult=rs_async(job, &rsbuf, infb, outfb);
        if(delresult==RS_DONE)
        {
            r=delresult;
//			logp("delresult done\n");
            break;
        }
        else if(delresult==RS_BLOCKED || delresult==RS_RUNNING)
        {
//			logp("delresult running/blocked: %d\n", delresult);
            // Keep going
        }
        else
        {
            logp("error in rs_async for delta: %d\n", delresult);
            r=delresult;
            break;
        }
        // FIX ME: get it to read stuff (errors, for example) here too.
        if(async_rw(NULL, NULL, '\0', '\0', NULL, &wlen))
            return -1;
    }

    if(r!=RS_DONE)
        logp("delta loop returned: %d\n", r);

//logp("after delta loop: %d\n", r);
//logp("\n");

    if(r==RS_DONE)
    {
        *bytes=infb->bytes;
        *sentbytes=outfb->bytes;
        if(!MD5_Final(checksum, &(infb->md5)))
        {
            logp("MD5_Final() failed\n");
            r=RS_IO_ERROR;
        }
    }
    rs_filebuf_free(infb);
    rs_filebuf_free(outfb);
    rs_job_free(job);
    rs_free_sumset(sumset);

    if(r==RS_DONE && write_endfile(*bytes, checksum)) // finish delta file
        return -1;

    //logp("end of load_sig_send_delta\n");

    return r;
}
Beispiel #20
0
int do_restore_client_burp1(struct asfd *asfd,
                            struct conf *conf, enum action act, int vss_restore)
{
    int ars=0;
    int ret=-1;
    char msg[512]="";
    struct sbuf *sb=NULL;
// Windows needs to have the VSS data written first, and the actual data
// written immediately afterwards. The server is transferring them in two
// chunks. So, leave bfd open after a Windows metadata transfer.
    BFILE bfd;
#ifdef HAVE_WIN32
    binit(&bfd, 0, conf);
#endif

    logp("doing %s\n", act_str(act));

    snprintf(msg, sizeof(msg), "%s %s:%s", act_str(act),
             conf->backup?conf->backup:"", conf->regex?conf->regex:"");
    if(asfd->write_str(asfd, CMD_GEN, msg)
            || asfd->read_expect(asfd, CMD_GEN, "ok"))
        return -1;
    logp("doing %s confirmed\n", act_str(act));

    if(conf->send_client_cntr)
    {
// FIX THIS
//		if(cntr_recv(conf)) goto end;
    }

#if defined(HAVE_WIN32)
    if(act==ACTION_RESTORE) win32_enable_backup_privileges();
#endif

    if(!(sb=sbuf_alloc(conf))) goto end;
    while(1)
    {
        char *fullpath=NULL;

        sbuf_free_content(sb);
        if((ars=sbufl_fill(sb, asfd, NULL, NULL, conf->cntr)))
        {
            if(ars<0) goto end;
            else
            {
                // ars==1 means it ended ok.
                //logp("got %s end\n", act_str(act));
                if(asfd->write_str(asfd,
                                   CMD_GEN, "restoreend ok")) goto end;
            }
            break;
        }

        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(conf->strip)
            {
                int s;
                s=strip_path_components(asfd, sb,
                                        &(sb->path.buf), conf);
                if(s<0) goto end; // error
                else if(s==0)
                {
                    // Too many components stripped
                    // - carry on.
                    continue;
                }
                // It is OK, sb->path is now stripped.
            }
            if(!(fullpath=prepend_s(conf->restoreprefix,
                                    sb->path.buf)))
            {
                log_and_send_oom(asfd, __func__);
                goto end;
            }
            if(act==ACTION_RESTORE)
            {
                strip_invalid_characters(&fullpath);
                if(!overwrite_ok(sb, conf, &bfd, fullpath))
                {
                    char msg[512]="";
                    // Something exists at that path.
                    snprintf(msg, sizeof(msg),
                             "Path exists: %s", fullpath);
                    if(restore_interrupt(asfd, sb, msg, conf))
                        goto end;
                    else
                    {
                        if(fullpath) free(fullpath);
                        continue;
                    }
                }
            }
            break;
        default:
            break;
        }

        switch(sb->path.cmd)
        {
        case CMD_WARNING:
            cntr_add(conf->cntr, sb->path.cmd, 1);
            printf("\n");
            logp("%s", sb->path);
            break;
        case CMD_DIRECTORY:
            if(restore_dir(asfd, sb, fullpath, act, conf))
                goto end;
            break;
        case CMD_FILE:
        case CMD_VSS_T:
            // Have it a separate statement to the
            // encrypted version so that encrypted and not
            // encrypted files can be restored at the
            // same time.
            if(restore_file_or_get_meta(asfd, &bfd, sb,
                                        fullpath, act,
                                        NULL, NULL, NULL,
                                        vss_restore, conf))
            {
                logp("restore_file error\n");
                goto end;
            }
            break;
        case CMD_ENC_FILE:
        case CMD_ENC_VSS_T:
            if(restore_file_or_get_meta(asfd, &bfd, sb,
                                        fullpath, act,
                                        conf->encryption_password,
                                        NULL, NULL, vss_restore, conf))
            {
                logp("restore_file error\n");
                goto end;
            }
            break;
        case CMD_SOFT_LINK:
        case CMD_HARD_LINK:
            if(restore_link(asfd, sb, fullpath,
                            conf->restoreprefix, act, conf))
                goto end;
            break;
        case CMD_SPECIAL:
            if(restore_special(asfd, sb, fullpath, act, conf))
                goto end;
            break;
        case CMD_METADATA:
        case CMD_VSS:
            if(restore_metadata(asfd, &bfd, sb, fullpath,
                                act, NULL, vss_restore, conf))
                goto end;
            break;
        case CMD_ENC_METADATA:
        case CMD_ENC_VSS:
            if(restore_metadata(asfd, &bfd, sb, fullpath,
                                act, conf->encryption_password,
                                vss_restore, conf))
                goto end;
            break;
        case CMD_EFS_FILE:
            if(restore_file_or_get_meta(asfd, &bfd, sb,
                                        fullpath, act,
                                        NULL, NULL, NULL, vss_restore, conf))
            {
                logp("restore_file error\n");
                goto end;
            }
            break;
        default:
            logp("unknown cmd: %c\n", sb->path.cmd);
            goto end;
            break;
        }

        if(fullpath) free(fullpath);
    }

    ret=0;
end:
    sbuf_free(sb);

#ifdef HAVE_WIN32
    // It is possible for a bfd to still be open.
    bclose(&bfd, asfd);
#endif

    cntr_print_end(conf->cntr);
    cntr_print(conf->cntr, act);

    if(!ret) logp("%s finished\n", act_str(act));
    else logp("ret: %d\n", ret);

    return ret;
}
Beispiel #21
0
// Return p1manio position.
static man_off_t *do_resume_work(struct sdirs *sdirs,
                                 struct dpth *dpth, struct conf **cconfs)
{
    man_off_t *pos=NULL;
    man_off_t *p1pos=NULL;
    struct iobuf *chb=NULL;
    struct manio *cmanio=NULL;
    struct manio *umanio=NULL;
    struct manio *p1manio=NULL;
    enum protocol protocol=get_protocol(cconfs);
    struct cntr *cntr=get_cntr(cconfs);
    int compression=get_int(cconfs[OPT_COMPRESSION]);

    if(!(p1manio=manio_open_phase1(sdirs->phase1data, "rb", protocol))
            || !(cmanio=manio_open_phase2(sdirs->changed, "rb", protocol))
            || !(umanio=manio_open_phase2(sdirs->unchanged, "rb", protocol)))
        goto end;

    if(!(chb=iobuf_alloc()))
        return NULL;

    logp("Setting up resume positions...\n");

    if(get_last_good_entry(cmanio, chb, cntr, dpth, protocol, &pos))
        goto error;
    if(manio_close_and_truncate(&cmanio, pos, compression)) goto error;
    man_off_t_free(&pos);
    if(chb->buf)
    {
        logp("  last good entry:    %s\n", chb->buf);
        // Now need to go to the appropriate places in p1manio and
        // unchanged.
        if(forward_past_entry(p1manio, chb, protocol, &p1pos))
            goto error;

        // The unchanged file needs to be positioned just before the
        // found entry, otherwise it ends up having a duplicated entry.
        if(forward_before_entry(umanio,
                                chb, cntr, dpth, protocol, &pos))
            goto error;
        if(manio_close_and_truncate(&umanio, pos, compression))
            goto error;
        man_off_t_free(&pos);
    }
    else
    {
        logp("  nothing previously transferred\n");
        if(!(p1pos=manio_tell(p1manio)))
            goto error;
        if(!(pos=manio_tell(umanio)))
            goto error;
        if(manio_close_and_truncate(&umanio, pos, compression))
            goto error;
    }

    // Now should have all file pointers in the right places to resume.

    goto end;
error:
    man_off_t_free(&p1pos);
end:
    iobuf_free(&chb);
    man_off_t_free(&pos);
    manio_close(&p1manio);
    manio_close(&cmanio);
    manio_close(&umanio);
    return p1pos;
}
Beispiel #22
0
// The failure conditions here are dealt with by the rubble cleaning code.
static int delete_backup(struct sdirs *sdirs, const char *cname, struct bu *bu,
	const char *manual_delete)
{
	logp("deleting %s backup %"PRId64"\n", cname, bu->bno);

	if(sdirs->global_sparse)
	{
		const char *candidate_str=bu->path+strlen(sdirs->base)+1;
		if(remove_from_global_sparse(
			sdirs->global_sparse, candidate_str))
				return -1;
	}

	if(!bu->next && !bu->prev)
	{
		// The current, and only, backup.
		if(do_rename_w(bu->path, sdirs->deleteme, cname, bu))
			return -1;
		// If interrupted here, there will be a dangling 'current'
		// symlink.
		if(unlink(sdirs->current))
		{
			logp("unlink %s: %s\n",
				sdirs->current, strerror(errno));
			return -1;
		}
		return recursive_delete_w(sdirs, bu, manual_delete);
	}
	if(!bu->next && bu->prev)
	{
		// The current backup. There are other backups left.
		// Need to point the symlink at the previous backup.
		const char *target=NULL;
		
		target=bu->prev->basename;
		unlink(sdirs->currenttmp);
		if(symlink(target, sdirs->currenttmp))
		{
			logp("could not symlink '%s' to '%s': %s\n",
				sdirs->currenttmp, target, strerror(errno));
			return -1;
		}
		// If interrupted here, there is a currenttmp and a current
		// symlink, and they both point to valid directories.
		if(do_rename_w(bu->path, sdirs->deleteme, cname, bu))
			return -1;
		// If interrupted here, there is a currenttmp and a current
		// symlink, and the current link is dangling.
		if(do_rename(sdirs->currenttmp, sdirs->current))
			return -1;
		// If interrupted here, moving the symlink could have failed
		// after current was deleted but before currenttmp was renamed.
		if(recursive_delete_w(sdirs, bu, manual_delete))
			return -1;
		return 0;
	}

	// It is not the current backup.
	if(do_rename_w(bu->path, sdirs->deleteme, cname, bu)
	  || recursive_delete_w(sdirs, bu, manual_delete))
		return -1;
	return 0;
}
Beispiel #23
0
int restore_switch_burp1(struct asfd *asfd, struct sbuf *sb,
	const char *fullpath, enum action act,
	BFILE *bfd, int vss_restore, struct conf *conf)
{
	switch(sb->path.cmd)
	{
		case CMD_FILE:
		case CMD_VSS_T:
			// Have it a separate statement to the
			// encrypted version so that encrypted and not
			// encrypted files can be restored at the
			// same time.
			if(restore_file_or_get_meta(asfd, bfd, sb,
				fullpath, act,
				NULL, NULL, NULL,
				vss_restore, conf))
			{
				logp("restore_file error\n");
				goto error;
			}
			break;
		case CMD_ENC_FILE:
		case CMD_ENC_VSS_T:
			if(restore_file_or_get_meta(asfd, bfd, sb,
				fullpath, act,
				conf->encryption_password,
				NULL, NULL, vss_restore, conf))
			{
				logp("restore_file error\n");
				goto error;
			}
			break;
		case CMD_METADATA:
		case CMD_VSS:
			if(restore_metadata(asfd, bfd, sb, fullpath,
				act, NULL, vss_restore, conf))
					goto error;
			break;
		case CMD_ENC_METADATA:
		case CMD_ENC_VSS:
			if(restore_metadata(asfd, bfd, sb, fullpath,
				act, conf->encryption_password,
				vss_restore, conf))
					goto error;
			break;
		case CMD_EFS_FILE:
			if(restore_file_or_get_meta(asfd, bfd, sb,
				fullpath, act,
				NULL, NULL, NULL, vss_restore, conf))
			{
				logp("restore_file error\n");
				goto error;
			}
			break;
		default:
			// Other cases (dir/links/etc) are handled in the
			// calling function.
			logp("unknown cmd: %c\n", sb->path.cmd);
			goto error;
	}
	return 0;
error:
	return -1;
}
Beispiel #24
0
int backup_phase2_client_protocol2(struct asfd *asfd,
	struct conf **confs, int resume)
{
	int ret=-1;
	uint8_t end_flags=0;
	struct slist *slist=NULL;
	struct iobuf *rbuf=NULL;
	struct iobuf *wbuf=NULL;
	struct cntr *cntr=NULL;

	if(confs) cntr=get_cntr(confs);

	if(!asfd || !asfd->as)
	{
		logp("%s() called without async structs!\n", __func__);
		goto end;
	}

	logp("Phase 2 begin (send backup data)\n");
	logfmt("\n");

	if(!(slist=slist_alloc())
	  || !(wbuf=iobuf_alloc())
	  || blks_generate_init())
		goto end;
	rbuf=asfd->rbuf;

	if(!resume)
	{
		// Only do this bit if the server did not tell us to resume.
		if(asfd->write_str(asfd, CMD_GEN, "backupphase2")
		  || asfd_read_expect(asfd, CMD_GEN, "ok"))
			goto end;
	}
	else
	{
		// On resume, the server might update the client with cntr.
		if(cntr_recv(asfd, confs))
			goto end;
        }

	while(!(end_flags&END_BACKUP))
	{
		if(!wbuf->len)
		{
			get_wbuf_from_data(confs, wbuf, slist,
				end_flags);
			if(!wbuf->len)
			{
				if(get_wbuf_from_blks(wbuf, slist,
					&end_flags)) goto end;
			}
		}

		if(wbuf->len)
		{
			if(asfd->append_all_to_write_buffer(asfd, wbuf)
				==APPEND_ERROR)
					goto end;
		}
		if(asfd->as->read_write(asfd->as))
		{
			logp("error in %s\n", __func__);
			goto end;
		}

		if(rbuf->buf && deal_with_read(rbuf, slist, cntr, &end_flags))
			goto end;

		if(slist->head
		// Need to limit how many blocks are allocated at once.
		  && (!slist->blist->head
		   || slist->blist->tail->index
			- slist->blist->head->index<BLKS_MAX_IN_MEM)
		)
		{
			if(add_to_blks_list(asfd, confs, slist))
				goto end;
		}

		if(end_flags&END_BLK_REQUESTS)
		{
			// If got to the end of the file request list
			// and the last block of the last file, and
			// the write buffer is empty, we got to the end.
			if(slist->head==slist->tail)
			{
				if(!slist->tail
				  || slist->blist->last_sent==
					slist->tail->protocol2->bend)
				{
					if(!wbuf->len)
						break;
				}
			}

		}
	}

	if(asfd->write_str(asfd, CMD_GEN, "backup_end"))
		goto end;

	ret=0;
end:
	slist_free(&slist);
	blks_generate_free();
	if(wbuf)
	{
		// Write buffer did not allocate 'buf'.
		wbuf->buf=NULL;
		iobuf_free(&wbuf);
	}
	cntr_print_end(cntr);
	cntr_print(cntr, ACTION_BACKUP, asfd);
	if(ret) logp("Error in backup\n");
	logp("End backup\n");

	return ret;
}
Beispiel #25
0
static int deal_with_read(struct iobuf *rbuf, struct slist *slist,
	struct cntr *cntr, uint8_t *end_flags)
{
	int ret=0;
	switch(rbuf->cmd)
	{
		/* Incoming file request. */
		case CMD_FILE:
		case CMD_METADATA:
			if(add_to_file_requests(slist, rbuf)) goto error;
			return 0;

		/* Incoming data block request. */
		case CMD_DATA_REQ:
			if(add_to_data_requests(slist->blist, rbuf)) goto error;
			goto end;

		/* Incoming control/message stuff. */
		case CMD_WRAP_UP:
		{
			int64_t wrap_up;
			struct blk *blk;
			struct blist *blist=slist->blist;
			from_base64(&wrap_up, rbuf->buf);
			for(blk=blist->head; blk; blk=blk->next)
			{
				if(blk->index==(uint64_t)wrap_up)
				{
					blist->last_requested=blk;
					blist->last_sent=blk;
					break;
				}
			}
			if(!blk)
			{
				logp("Could not find wrap up index: %016" PRIX64 "\n",
					wrap_up);
//				goto error;
			}
			goto end;
		}
		case CMD_MESSAGE:
		case CMD_WARNING:
		{
			log_recvd(rbuf, cntr, 0);
			goto end;
		}
		case CMD_GEN:
			if(!strcmp(rbuf->buf, "requests_end"))
			{
				(*end_flags)|=END_REQUESTS;
				goto end;
			}
			else if(!strcmp(rbuf->buf, "blk_requests_end"))
			{
				(*end_flags)|=END_BLK_REQUESTS;
				goto end;
			}
			else if(!strcmp(rbuf->buf, "backup_end"))
			{
				(*end_flags)|=END_BACKUP;
				goto end;
			}
			break;
		default:
			break;
	}

	iobuf_log_unexpected(rbuf, __func__);
error:
	ret=-1;
end:
	iobuf_free_content(rbuf);
	return ret;
}
Beispiel #26
0
int run_bedup(int argc, char *argv[])
{
	int i=1;
	int ret=0;
	int option=0;
	int nonburp=0;
	unsigned int maxlinks=DEF_MAX_LINKS;
	char *groups=NULL;
	char ext[16]="";
	int givenconfigfile=0;
	const char *configfile=NULL;

	configfile=get_config_path();
	snprintf(ext, sizeof(ext), ".bedup.%d", getpid());

	while((option=getopt(argc, argv, "c:dg:hlm:nvV?"))!=-1)
	{
		switch(option)
		{
			case 'c':
				configfile=optarg;
				givenconfigfile=1;
				break;
			case 'd':
				deletedups=1;
				break;
			case 'g':
				groups=optarg;
				break;
			case 'l':
				makelinks=1;
				break;
			case 'm':
				maxlinks=atoi(optarg);
				break;
			case 'n':
				nonburp=1;
				break;
			case 'V':
				printf("%s-%s\n", prog, VERSION);
				return 0;
			case 'v':
				verbose=1;
				break;
			case 'h':
			case '?':
				return usage();
		}
	}

	if(nonburp && givenconfigfile)
	{
		logp("-n and -c options are mutually exclusive\n");
		return 1;
	}
	if(nonburp && groups)
	{
		logp("-n and -g options are mutually exclusive\n");
		return 1;
	}
	if(!nonburp && maxlinks!=DEF_MAX_LINKS)
	{
		logp("-m option is specified via the configuration file in burp mode (max_hardlinks=)\n");
		return 1;
	}
	if(deletedups && makelinks)
	{
		logp("-d and -l options are mutually exclusive\n");
		return 1;
	}
	if(deletedups && !nonburp)
	{
		logp("-d option requires -n option\n");
		return 1;
	}

	if(optind>=argc)
	{
		if(nonburp)
		{
			logp("No directories found after options\n");
			return 1;
		}
	}
	else
	{
		if(!nonburp)
		{
			logp("Do not specify extra arguments.\n");
			return 1;
		}
	}

	if(maxlinks<2)
	{
		logp("The argument to -m needs to be greater than 1.\n");
		return 1;
	}

	if(nonburp)
	{
		// Read directories from command line.
		for(i=optind; i<argc; i++)
		{
			// Strip trailing slashes, for tidiness.
			if(argv[i][strlen(argv[i])-1]=='/')
				argv[i][strlen(argv[i])-1]='\0';
			if(process_dir("", argv[i], ext, maxlinks,
				0 /* not burp mode */, 0 /* level */))
			{
				ret=1;
				break;
			}
		}
	}
	else
	{
		struct conf **globalcs=NULL;
		struct strlist *grouplist=NULL;
		struct lock *globallock=NULL;

		if(groups)
		{
			char *tok=NULL;
			if((tok=strtok(groups, ",\n")))
			{
				do
				{
					if(strlist_add(&grouplist, tok, 1))
					{
						log_out_of_memory(__func__);
						return -1;
					}
				} while((tok=strtok(NULL, ",\n")));
			}
			if(!grouplist)
			{
				logp("unable to read list of groups\n");
				return -1;
			}
		}

		// Read directories from config files, and get locks.
		if(!(globalcs=confs_alloc())) return -1;
		if(confs_init(globalcs)) return -1;
		if(conf_load_global_only(configfile, globalcs)) return 1;
		if(get_e_burp_mode(globalcs[OPT_BURP_MODE])!=BURP_MODE_SERVER)
		{
			logp("%s is not a server config file\n", configfile);
			confs_free(&globalcs);
			return 1;
		}
		logp("Dedup clients from %s\n",
			get_string(globalcs[OPT_CLIENTCONFDIR]));
		maxlinks=get_int(globalcs[OPT_MAX_HARDLINKS]);
		if(grouplist)
		{
			struct strlist *g=NULL;
			logp("in dedup groups:\n");
			for(g=grouplist; g; g=g->next)
				logp("%s\n", g->path);
		}
		else
		{
			char *lockpath=NULL;
			const char *opt_lockfile=confs_get_lockfile(globalcs);
			// Only get the global lock when doing a global run.
			// If you are doing individual groups, you are likely
			// to want to do many different dedup jobs and a
			// global lock would get in the way.
			if(!(lockpath=prepend(opt_lockfile, ".bedup"))
			  || !(globallock=lock_alloc_and_init(lockpath)))
				return 1;
			lock_get(globallock);
			if(globallock->status!=GET_LOCK_GOT)
			{
				logp("Could not get lock %s (%d)\n", lockpath,
					globallock->status);
				free_w(&lockpath);
				return 1;
			}
			logp("Got %s\n", lockpath);
		}
		ret=iterate_over_clients(globalcs, grouplist, ext, maxlinks);
		confs_free(&globalcs);

		lock_release(globallock);
		lock_free(&globallock);
		strlists_free(&grouplist);
	}

	if(!nonburp)
	{
		logp("%d client storages scanned\n", ccount);
	}
	logp("%llu duplicate %s found\n",
		count, count==1?"file":"files");
	logp("%llu bytes %s%s\n",
		savedbytes, (makelinks || deletedups)?"saved":"saveable",
			bytes_to_human(savedbytes));
	return ret;
}
Beispiel #27
0
static int iterate_over_clients(struct conf **globalcs,
	struct strlist *grouplist, const char *ext, unsigned int maxlinks)
{
	int ret=0;
	DIR *dirp=NULL;
	struct conf **cconfs=NULL;
	struct dirent *dirinfo=NULL;
	const char *globalclientconfdir=get_string(globalcs[OPT_CLIENTCONFDIR]);

	signal(SIGABRT, &sighandler);
	signal(SIGTERM, &sighandler);
	signal(SIGINT, &sighandler);

	if(!(cconfs=confs_alloc())) return -1;
	if(confs_init(cconfs)) return -1;

	if(!(dirp=opendir(globalclientconfdir)))
	{
		logp("Could not opendir '%s': %s\n",
			globalclientconfdir, strerror(errno));
		return 0;
	}
	while((dirinfo=readdir(dirp)))
	{
		char *lockfile=NULL;
		char *lockfilebase=NULL;
		char *client_lockdir=NULL;
		struct lock *lock=NULL;

		if(dirinfo->d_ino==0
		// looks_like...() also avoids '.' and '..'.
		  || looks_like_tmp_or_hidden_file(dirinfo->d_name)
		  || !is_regular_file(globalclientconfdir, dirinfo->d_name))
			continue;

		confs_free_content(cconfs);
		if(confs_init(cconfs)) return -1;

		if(set_string(cconfs[OPT_CNAME], dirinfo->d_name))
			return -1;

		if(conf_load_clientconfdir(globalcs, cconfs))
		{
			logp("could not load config for client %s\n",
				dirinfo->d_name);
			return 0;
		}

		if(grouplist)
		{
			const char *dedup_group=
				get_string(cconfs[OPT_DEDUP_GROUP]);
			if(!dedup_group
			  || !in_group(grouplist, dedup_group))
				continue;
		}

		if(!(client_lockdir=get_string(cconfs[OPT_CLIENT_LOCKDIR])))
			client_lockdir=get_string(cconfs[OPT_DIRECTORY]);

		if(!(lockfilebase=prepend_s(client_lockdir, dirinfo->d_name))
		 || !(lockfile=prepend_s(lockfilebase, BEDUP_LOCKFILE_NAME)))
		{
			free_w(&lockfilebase);
			free_w(&lockfile);
			ret=-1;
			break;
		}
		free_w(&lockfilebase);

		if(!(lock=lock_alloc_and_init(lockfile)))
		{
			ret=-1;
			break;
		}
		lock_get(lock);
		free_w(&lockfile);

		if(lock->status!=GET_LOCK_GOT)
		{
			logp("Could not get %s\n", lock->path);
			continue;
		}
		logp("Got %s\n", lock->path);

		// Remember that we got that lock.
		lock_add_to_list(&locklist, lock);

		switch(process_dir(get_string(cconfs[OPT_DIRECTORY]),
			dirinfo->d_name,
			ext, maxlinks, 1 /* burp mode */, 0 /* level */))
		{
			case 0: ccount++;
			case 1: continue;
			default: ret=-1; break;
		}
		break;
	}
	closedir(dirp);

	locks_release_and_free(&locklist);

	confs_free(&cconfs);

	return ret;
}
Beispiel #28
0
// Return 0 for directory processed, -1 for error, 1 for not processed.
static int process_dir(const char *oldpath, const char *newpath,
	const char *ext, unsigned int maxlinks, int burp_mode, int level)
{
	int ret=-1;
	DIR *dirp=NULL;
	char *path=NULL;
	struct stat info;
	struct dirent *dirinfo=NULL;
	struct file newfile;
	struct mystruct *find=NULL;
	static char working[256]="";
	static char finishing[256]="";

	newfile.path=NULL;

	if(!(path=prepend_s(oldpath, newpath))) goto end;

	if(burp_mode && level==0)
	{
		if(get_link(path, "working", working, sizeof(working))
		  || get_link(path, "finishing", finishing, sizeof(finishing)))
			goto end;
		if(!looks_like_protocol1(path))
		{
			logp("%s does not look like a protocol 1 storage directory - skipping\n", path);
			ret=1;
			goto end;
		}
	}

	if(!(dirp=opendir(path)))
	{
		logp("Could not opendir '%s': %s\n", path, strerror(errno));
		ret=1;
		goto end;
	}
	while((dirinfo=readdir(dirp)))
	{
		if(!strcmp(dirinfo->d_name, ".")
		  || !strcmp(dirinfo->d_name, ".."))
			continue;

		//printf("try %s\n", dirinfo->d_name);

		if(burp_mode
		  && level_exclusion(level, dirinfo->d_name,
			working, finishing))
				continue;

		free_w(&newfile.path);
		if(!(newfile.path=prepend_s(path, dirinfo->d_name)))
			goto end;

		if(lstat(newfile.path, &info))
			continue;

		if(S_ISDIR(info.st_mode))
		{
			if(process_dir(path, dirinfo->d_name, ext, maxlinks,					burp_mode, level+1))
					goto end;
			continue;
		}
		else if(!S_ISREG(info.st_mode)
		  || !info.st_size) // ignore zero-length files
			continue;

		newfile.dev=info.st_dev;
		newfile.ino=info.st_ino;
		newfile.nlink=info.st_nlink;
		newfile.full_cksum=0;
		newfile.part_cksum=0;
		newfile.next=NULL;

		if((find=find_key(info.st_size)))
		{
			//printf("check %d: %s\n", info.st_size, newfile.path);
			if(check_files(find, &newfile, &info, ext, maxlinks))
				goto end;
		}
		else
		{
			//printf("add: %s\n", newfile.path);
			if(add_key(info.st_size, &newfile))
				goto end;
		}
	}
	ret=0;
end:
	closedir(dirp);
	free_w(&newfile.path);
	free_w(&path);
	return ret;
}
Beispiel #29
0
static int check_files(struct mystruct *find, struct file *newfile,
	struct stat *info, const char *ext, unsigned int maxlinks)
{
	int found=0;
	struct fzp *nfp=NULL;
	struct fzp *ofp=NULL;
	struct file *f=NULL;

	for(f=find->files; f; f=f->next)
	{
//printf("  against: '%s'\n", f->path);
		if(!f->path)
		{
			// If the full_match() function fails to open oldfile
			// (which could happen if burp deleted some old
			// directories), it will free path and set it to NULL.
			// Skip entries like this.
			continue;
		}
		if(newfile->dev!=f->dev)
		{
			// Different device.
			continue;
		}
		if(newfile->ino==f->ino)
		{
			// Same device, same inode, therefore these two files
			// are hardlinked to each other already.
			found++;
			break;
		}
		if((!newfile->part_cksum && get_part_cksum(newfile, &nfp))
		  || (!f->part_cksum && get_part_cksum(f, &ofp)))
		{
			// Some error with md5sums Give up.
			return -1;
		}
		if(newfile->part_cksum!=f->part_cksum)
		{
			fzp_close(&ofp);
			continue;
		}
		//printf("  %s, %s\n", find->files->path, newfile->path);
		//printf("  part cksum matched\n");

		if((!newfile->full_cksum && get_full_cksum(newfile, &nfp))
		  || (!f->full_cksum && get_full_cksum(f, &ofp)))
		{
			// Some error with md5sums Give up.
			return -1;
		}
		if(newfile->full_cksum!=f->full_cksum)
		{
			fzp_close(&ofp);
			continue;
		}

		//printf("  full cksum matched\n");
		if(!full_match(newfile, f, &nfp, &ofp))
		{
			fzp_close(&ofp);
			continue;
		}
		//printf("  full match\n");
		//printf("%s, %s\n", find->files->path, newfile->path);

		// If there are already enough links to this file, replace
		// our memory of it with the new file so that files later on
		// can link to the new one. 
		if(f->nlink>=maxlinks)
		{
			// Just need to reset the path name and the number
			// of links, and pretend that it was found otherwise
			// NULL newfile will get added to the memory.
			reset_old_file(f, newfile, info);
			found++;
			break;
		}

		found++;
		count++;

		if(verbose) printf("%s\n", newfile->path);

		// Now hardlink it.
		if(makelinks)
		{
			switch(do_hardlink(newfile, f, ext))
			{
				case 0:
					f->nlink++;
					// Only count bytes as saved if we
					// removed the last link.
					if(newfile->nlink==1)
						savedbytes+=info->st_size;
					break;
				case -1:
					// On error, replace the memory of the
					// old file with the one that we just
					// found. It might work better when
					// someone later tries to link to the
					// new one instead of the old one.
					reset_old_file(f, newfile, info);
					count--;
					break;
				default:
					// Abandon all hope.
					// This could happen if renaming the
					// hardlink failed in such a way that
					// the target file was unlinked without
					// being replaced - ie, if the max
					// number of hardlinks is being hit.
					return -1;
			}
		}
		else if(deletedups)
		{
			if(unlink(newfile->path))
			{
				logp("Could not delete %s: %s\n",
					newfile->path, strerror(errno));
			}
			else
			{
				// Only count bytes as saved if we removed the
				// last link.
				if(newfile->nlink==1)
					savedbytes+=info->st_size;
			}
		}
		else
		{
			// To be able to tell how many bytes
			// are saveable.
			savedbytes+=info->st_size;
		}

		break;
	}
	fzp_close(&nfp);
	fzp_close(&ofp);

	if(found)
	{
		free_w(&newfile->path);
		return 0;
	}

	if(add_file(find, newfile)) return -1;

	return 0;
}
Beispiel #30
-1
int recursive_hardlink(const char *src, const char *dst, const char *client, struct cntr *p1cntr, struct cntr *cntr, struct config *conf)
{
	int n=-1;
	int ret=0;
	struct dirent **dir;
	char *tmp=NULL;
	//logp("in rec hl: %s %s\n", src, dst);
	if(!(tmp=prepend_s(dst, "dummy", strlen("dummy"))))
		return -1;
	if(mkpath(&tmp, dst))
	{
		logp("could not mkpath for %s\n", tmp);
		free(tmp);
		return -1;
	}
	free(tmp);

	if((n=scandir(src, &dir, 0, 0))<0)
	{
		logp("recursive_hardlink scandir %s: %s\n",
			src, strerror(errno));
		return -1;
	}
	while(n--)
	{
		struct stat statp;
		char *fullpatha=NULL;
		char *fullpathb=NULL;
		if(dir[n]->d_ino==0
		  || !strcmp(dir[n]->d_name, ".")
		  || !strcmp(dir[n]->d_name, ".."))
			{ free(dir[n]); continue; }
		if(!(fullpatha=prepend_s(src,
			dir[n]->d_name, strlen(dir[n]->d_name)))
		|| !(fullpathb=prepend_s(dst,
			dir[n]->d_name, strlen(dir[n]->d_name))))
		{
			if(fullpatha) free(fullpatha);
			if(fullpathb) free(fullpathb);
			break;
		}

		if(lstat(fullpatha, &statp))
		{
			logp("could not lstat %s\n", fullpatha);
		}
		else if(S_ISDIR(statp.st_mode))
		{
			if(recursive_hardlink(fullpatha, fullpathb, client,
				p1cntr, cntr, conf))
			{
				free(fullpatha);
				free(fullpathb);
				break;
			}
		}
		else
		{
			//logp("hardlinking %s to %s\n", fullpathb, fullpatha);
			write_status(client, STATUS_SHUFFLING, fullpathb,
				p1cntr, cntr);
			if(do_link(fullpatha, fullpathb, &statp, conf,
				FALSE /* do not overwrite target */))
			{
				free(fullpatha);
				free(fullpathb);
				break;
			}
		}
		free(fullpatha);
		free(fullpathb);
		free(dir[n]);
	}
	if(n>0)
	{
		ret=-1;
		for(; n>0; n--) free(dir[n]);
	}
	free(dir);

	return ret;
}