예제 #1
0
파일: backup_phase4.c 프로젝트: kaptk2/burp
static int make_rev_sig(const char *dst, const char *sig, const char *endfile,
	int compression, struct conf **confs)
{
	int ret=-1;
	FILE *dstfp=NULL;
	gzFile dstzp=NULL;
	FILE *sigp=NULL;
//logp("make rev sig: %s %s\n", dst, sig);

	if(dpth_protocol1_is_compressed(compression, dst))
		dstzp=gzopen_file(dst, "rb");
	else
		dstfp=open_file(dst, "rb");

	if((!dstzp && !dstfp)
	  || !(sigp=open_file(sig, "wb"))
	  || rs_sig_gzfile(NULL, dstfp, dstzp, sigp,
		get_librsync_block_len(endfile),
		RS_DEFAULT_STRONG_LEN,
		NULL, get_cntr(confs[OPT_CNTR]))!=RS_DONE)
			goto end;
	ret=0;
end:
//logp("end of make rev sig\n");
	gzclose_fp(&dstzp);
	close_fp(&dstfp);
	if(close_fp(&sigp))
	{
		logp("error closing %s in %s\n", sig, __func__);
		return -1;
	}
	return ret;
}
예제 #2
0
static int make_rev_sig(const char *dst, const char *sig, const char *endfile,
	int compression, struct conf **confs)
{
	int ret=-1;
	struct fzp *dstfzp=NULL;
	struct fzp *sigp=NULL;
//logp("make rev sig: %s %s\n", dst, sig);

	if(dpth_protocol1_is_compressed(compression, dst))
		dstfzp=fzp_gzopen(dst, "rb");
	else
		dstfzp=fzp_open(dst, "rb");

	if(!dstfzp
	  || !(sigp=fzp_open(sig, "wb"))
	  || rs_sig_gzfile(dstfzp, sigp,
		get_librsync_block_len(endfile),
		RS_DEFAULT_STRONG_LEN, confs)!=RS_DONE)
			goto end;
	ret=0;
end:
//logp("end of make rev sig\n");
	fzp_close(&dstfzp);
	if(fzp_close(&sigp))
	{
		logp("error closing %s in %s\n", sig, __func__);
		return -1;
	}
	return ret;
}
예제 #3
0
파일: backup_phase4.c 프로젝트: grke/burp
static int make_rev_delta(const char *src, const char *sig, const char *del,
	int compression, struct conf **cconfs)
{
	int ret=-1;
	rs_result result;
	struct fzp *srcfzp=NULL;
	struct fzp *delfzp=NULL;
	struct fzp *sigp=NULL;
	rs_signature_t *sumset=NULL;

//logp("make rev delta: %s %s %s\n", src, sig, del);
	if(!(sigp=fzp_open(sig, "rb"))) goto end;

	if((result=rs_loadsig_fzp(sigp, &sumset))!=RS_DONE)
	{
		logp("rs_loadsig_fzp returned %d %s\n",
			result, rs_strerror(result));
		goto end;
	}
	if((result=rs_build_hash_table(sumset))!=RS_DONE)
	{
		logp("rs_build_hash_table returned %d %s\n",
			result, rs_strerror(result));
		goto end;
	}

//logp("make rev deltb: %s %s %s\n", src, sig, del);

	if(dpth_protocol1_is_compressed(compression, src))
		srcfzp=fzp_gzopen(src, "rb");
	else
		srcfzp=fzp_open(src, "rb");

	if(!srcfzp) goto end;

	if(get_int(cconfs[OPT_COMPRESSION]))
		delfzp=fzp_gzopen(del,
			comp_level(get_int(cconfs[OPT_COMPRESSION])));
	else
		delfzp=fzp_open(del, "wb");
	if(!delfzp) goto end;

	if((result=rs_delta_gzfile(sumset, srcfzp, delfzp))!=RS_DONE)
	{
		logp("rs_delta_gzfile returned %d %s\n",
			result, rs_strerror(result));
		goto end;
	}
	ret=0;
end:
	if(sumset) rs_free_sumset(sumset);
	fzp_close(&srcfzp);
	fzp_close(&sigp);
	if(fzp_close(&delfzp))
	{
		logp("error closing delfzp %s in %s\n", del, __func__);
		ret=-1;
	}
	return ret;
}
예제 #4
0
파일: restore.c 프로젝트: pkdevbox/burp
static int send_file(struct asfd *asfd, struct sbuf *sb,
	int patches, const char *best,
	uint64_t *bytes, struct cntr *cntr)
{
	int ret=0;
	static BFILE *bfd=NULL;

	if(!bfd && !(bfd=bfile_alloc())) return -1;

	bfile_init(bfd, 0, cntr);
	if(bfd->open_for_send(bfd, asfd, best, sb->winattr,
		1 /* no O_NOATIME */, cntr, PROTO_1)) return -1;
	//logp("sending: %s\n", best);
	if(asfd->write(asfd, &sb->path))
		ret=-1;
	else if(patches)
	{
		// If we did some patches, the resulting file
		// is not gzipped. Gzip it during the send. 
		ret=send_whole_file_gzl(asfd, best, sb->protocol1->datapth.buf,
			1, bytes, NULL, cntr, 9, bfd, NULL, 0);
	}
	else
	{
		// If it was encrypted, it may or may not have been compressed
		// before encryption. Send it as it as, and let the client
		// sort it out.
		if(sbuf_is_encrypted(sb))
		{
			ret=send_whole_filel(asfd, sb->path.cmd, best,
				sb->protocol1->datapth.buf, 1, bytes,
				cntr, bfd, NULL, 0);
		}
		// It might have been stored uncompressed. Gzip it during
		// the send. If the client knew what kind of file it would be
		// receiving, this step could disappear.
		else if(!dpth_protocol1_is_compressed(sb->compression,
			sb->protocol1->datapth.buf))
		{
			ret=send_whole_file_gzl(asfd,
				best, sb->protocol1->datapth.buf, 1, bytes,
				NULL, cntr, 9, bfd, NULL, 0);
		}
		else
		{
			// If we did not do some patches, the resulting
			// file might already be gzipped. Send it as it is.
			ret=send_whole_filel(asfd, sb->path.cmd, best,
				sb->protocol1->datapth.buf, 1, bytes,
				cntr, bfd, NULL, 0);
		}
	}
	bfd->close(bfd, asfd);
	return ret;
}
예제 #5
0
파일: backup_phase4.c 프로젝트: kaptk2/burp
static int make_rev_delta(const char *src, const char *sig, const char *del,
	int compression, struct conf **cconfs)
{
	int ret=-1;
	FILE *srcfp=NULL;
	FILE *delfp=NULL;
	FILE *sigp=NULL;
	gzFile srczp=NULL;
	gzFile delzp=NULL;
	rs_signature_t *sumset=NULL;

//logp("make rev delta: %s %s %s\n", src, sig, del);
	if(!(sigp=open_file(sig, "rb"))) goto end;

	if(rs_loadsig_file(sigp, &sumset, NULL)!=RS_DONE
	  || rs_build_hash_table(sumset)!=RS_DONE)
		goto end;

//logp("make rev deltb: %s %s %s\n", src, sig, del);

	if(dpth_protocol1_is_compressed(compression, src))
		srczp=gzopen_file(src, "rb");
	else
		srcfp=open_file(src, "rb");

	if(!srczp && !srcfp) goto end;

	if(get_int(cconfs[OPT_COMPRESSION]))
		delzp=gzopen_file(del, comp_level(cconfs));
	else
		delfp=open_file(del, "wb");
	if(!delzp && !delfp) goto end;

	if(rs_delta_gzfile(NULL, sumset, srcfp, srczp,
		delfp, delzp, NULL, get_cntr(cconfs[OPT_CNTR]))!=RS_DONE)
			goto end;
	ret=0;
end:
	if(sumset) rs_free_sumset(sumset);
	gzclose_fp(&srczp);
	close_fp(&srcfp);
	close_fp(&sigp);
	if(gzclose_fp(&delzp))
	{
		logp("error closing zp %s in %s\n", del, __func__);
		ret=-1;
	}
	if(close_fp(&delfp))
	{
		logp("error closing fp %s in %s\n", del, __func__);
		ret=-1;
	}
	return ret;
}
예제 #6
0
파일: backup_phase4.c 프로젝트: kaptk2/burp
// Also used by restore.c.
// FIX THIS: This stuff is very similar to make_rev_delta, can maybe share
// some code.
int do_patch(struct asfd *asfd, const char *dst, const char *del,
	const char *upd, bool gzupd, int compression, struct conf **cconfs)
{
	FILE *dstp=NULL;
	FILE *delfp=NULL;
	gzFile delzp=NULL;
	gzFile updp=NULL;
	FILE *updfp=NULL;
	rs_result result=RS_IO_ERROR;

	//logp("patching...\n");

	if(!(dstp=open_file(dst, "rb"))) goto end;

	if(dpth_protocol1_is_compressed(compression, del))
		delzp=gzopen_file(del, "rb");
	else
		delfp=open_file(del, "rb");

	if(!delzp && !delfp) goto end;

	if(gzupd)
		updp=gzopen(upd, comp_level(cconfs));
	else
		updfp=fopen(upd, "wb");

	if(!updp && !updfp) goto end;

	result=rs_patch_gzfile(asfd,
		dstp, delfp, delzp, updfp, updp, NULL, get_cntr(cconfs[OPT_CNTR]));
end:
	close_fp(&dstp);
	gzclose_fp(&delzp);
	close_fp(&delfp);
	if(close_fp(&updfp))
	{
		logp("error closing %s in %s\n", upd, __func__);
		result=RS_IO_ERROR;
	}
	if(gzclose_fp(&updp))
	{
		logp("error gzclosing %s in %s\n", upd, __func__);
		result=RS_IO_ERROR;
	}
	return result;
}
예제 #7
0
파일: backup_phase4.c 프로젝트: kaptk2/burp
static int inflate_or_link_oldfile(const char *oldpath, const char *infpath,
	int compression, struct conf **cconfs)
{
	struct stat statp;

	if(lstat(oldpath, &statp))
	{
		logp("could not lstat %s\n", oldpath);
		return -1;
	}

	if(dpth_protocol1_is_compressed(compression, oldpath))
		return inflate_oldfile(oldpath, infpath, &statp, cconfs);

	// If it was not a compressed file, just hard link it.
	// It is possible that infpath already exists, if the server
	// was interrupted on a previous run just after this point.
	return do_link(oldpath, infpath, &statp, cconfs,
		1 /* allow overwrite of infpath */);
}
예제 #8
0
파일: restore.c 프로젝트: pkdevbox/burp
static int inflate_or_link_oldfile(struct asfd *asfd, const char *oldpath,
	const char *infpath, struct conf **cconfs, int compression)
{
	int ret=0;
	struct stat statp;

	if(lstat(oldpath, &statp))
	{
		logp("could not lstat %s\n", oldpath);
		return -1;
	}

	if(dpth_protocol1_is_compressed(compression, oldpath))
	{
		//logp("inflating...\n");

		if(!statp.st_size)
		{
			// Empty file - cannot inflate.
			logp("asked to inflate zero length file: %s\n",
				oldpath);
			return create_zero_length_file(infpath);
		}

		if((ret=zlib_inflate(asfd, oldpath, infpath, get_cntr(cconfs))))
			logp("zlib_inflate returned: %d\n", ret);
	}
	else
	{
		// Not compressed - just hard link it.
		if(do_link(oldpath, infpath, &statp, cconfs,
			1 /* allow overwrite of infpath */))
				return -1;
	}
	return ret;
}
예제 #9
0
파일: restore.c 프로젝트: vanElden/burp
static int do_restore_file_or_get_meta(struct asfd *asfd, BFILE *bfd,
	struct sbuf *sb, const char *fname,
	char **metadata, size_t *metalen,
	struct cntr *cntr, const char *rpath,
	const char *encryption_password)
{
	int ret=-1;
	int enccompressed=0;
	uint64_t rcvdbytes=0;
	uint64_t sentbytes=0;
	const char *encpassword=NULL;

	if(sbuf_is_encrypted(sb))
		encpassword=encryption_password;
	enccompressed=dpth_protocol1_is_compressed(sb->compression,
		sb->protocol1->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,
			&rcvdbytes, &sentbytes, encpassword, enccompressed,
			cntr, metadata);
		*metalen=sentbytes;
		// skip setting cntr, as we do not actually
		// restore until a bit later
		goto end;
	}
	else
	{
		ret=transfer_gzfile_inl(asfd, sb, fname, bfd,
			&rcvdbytes, &sentbytes,
			encpassword, enccompressed, cntr, NULL);
#ifndef HAVE_WIN32
		if(bfd && bfd->close(bfd, asfd))
		{
			logp("error closing %s in %s\n",
				fname, __func__);
			goto end;
		}
#endif
		if(!ret) attribs_set(asfd, rpath,
			&sb->statp, sb->winattr, cntr);
	}

	ret=0;
end:
	if(ret)
	{
		char msg[256]="";
		snprintf(msg, sizeof(msg),
			"Could not transfer file in: %s", rpath);
		if(restore_interrupt(asfd, sb, msg, cntr, PROTO_1))
			ret=-1;
	}
	return ret;
}
예제 #10
0
파일: restore.c 프로젝트: pkdevbox/burp
static int verify_file(struct asfd *asfd, struct sbuf *sb,
	int patches, const char *best,
	uint64_t *bytes, struct cntr *cntr)
{
	MD5_CTX md5;
	size_t b=0;
	const char *cp=NULL;
	const char *newsum=NULL;
	uint8_t in[ZCHUNK];
	uint8_t checksum[MD5_DIGEST_LENGTH];
	uint64_t cbytes=0;
	struct fzp *fzp=NULL;

	if(!(cp=strrchr(sb->endfile.buf, ':')))
	{
		logw(asfd, cntr,
			"%s has no md5sum!\n", sb->protocol1->datapth.buf);
		return 0;
	}
	cp++;
	if(!MD5_Init(&md5))
	{
		logp("MD5_Init() failed\n");
		return -1;
	}
	if(patches
	  || sb->path.cmd==CMD_ENC_FILE
	  || sb->path.cmd==CMD_ENC_METADATA
	  || sb->path.cmd==CMD_EFS_FILE
	  || sb->path.cmd==CMD_ENC_VSS
	  || (!patches && !dpth_protocol1_is_compressed(sb->compression, best)))
		fzp=fzp_open(best, "rb");
	else
		fzp=fzp_gzopen(best, "rb");

	if(!fzp)
	{
		logw(asfd, cntr, "could not open %s\n", best);
		return 0;
	}
	while((b=fzp_read(fzp, in, ZCHUNK))>0)
	{
		cbytes+=b;
		if(!MD5_Update(&md5, in, b))
		{
			logp("MD5_Update() failed\n");
			fzp_close(&fzp);
			return -1;
		}
	}
	if(!fzp_eof(fzp))
	{
		logw(asfd, cntr, "error while reading %s\n", best);
		fzp_close(&fzp);
		return 0;
	}
	fzp_close(&fzp);
	if(!MD5_Final(checksum, &md5))
	{
		logp("MD5_Final() failed\n");
		return -1;
	}
	newsum=bytes_to_md5str(checksum);

	if(strcmp(newsum, cp))
	{
		logp("%s %s\n", newsum, cp);
		logw(asfd, cntr, "md5sum for '%s (%s)' did not match!\n",
			sb->path.buf, sb->protocol1->datapth.buf);
		logp("md5sum for '%s (%s)' did not match!\n",
			sb->path.buf, sb->protocol1->datapth.buf);
		return 0;
	}
	*bytes+=cbytes;

	// Just send the file name to the client, so that it can show cntr.
	if(asfd->write(asfd, &sb->path)) return -1;
	return 0;
}
예제 #11
0
static int maybe_do_delta_stuff(struct asfd *asfd,
	struct sdirs *sdirs, struct sbuf *cb, struct sbuf *p1b,
	struct fzp *ucfp, struct conf **cconfs)
{
	int oldcompressed=0;
	int compression=get_int(cconfs[OPT_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, ucfp);

	// 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, ucfp, 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
		// FIX THIS: make unencrypted metadata use the librsync
		  || cb->path.cmd==CMD_METADATA
		  || p1b->path.cmd==CMD_METADATA
		  || cb->path.cmd==CMD_VSS
		  || p1b->path.cmd==CMD_VSS
		  || cb->path.cmd==CMD_ENC_VSS
		  || p1b->path.cmd==CMD_ENC_VSS
		  || cb->path.cmd==CMD_VSS_T
		  || p1b->path.cmd==CMD_VSS_T
		  || cb->path.cmd==CMD_ENC_VSS_T
		  || p1b->path.cmd==CMD_ENC_VSS_T
		  || cb->path.cmd==CMD_EFS_FILE
		  || p1b->path.cmd==CMD_EFS_FILE)
			return process_new_file(sdirs, cconfs, cb, p1b, ucfp);
		// 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, ucfp, cconfs);
	}

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

	// 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])
	  || cb->path.cmd==CMD_ENC_FILE
	  || p1b->path.cmd==CMD_ENC_FILE
	  || 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
	  || cb->path.cmd==CMD_VSS
	  || p1b->path.cmd==CMD_VSS
	  || cb->path.cmd==CMD_ENC_VSS
	  || p1b->path.cmd==CMD_ENC_VSS
	  || cb->path.cmd==CMD_VSS_T
	  || p1b->path.cmd==CMD_VSS_T
	  || cb->path.cmd==CMD_ENC_VSS_T
	  || p1b->path.cmd==CMD_ENC_VSS_T)
		return process_new_file(sdirs, cconfs, cb, p1b, ucfp);

	// 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, ucfp);

	// Otherwise, do the delta stuff (if possible).
	if(cmd_is_filedata(p1b->path.cmd))
	{
		if(process_changed_file(asfd, sdirs, cconfs, cb, p1b,
			sdirs->currentdata)) return -1;
	}
	else
	{
		if(changed_non_file(p1b, ucfp, p1b->path.cmd, cconfs))
			return -1;
	}
	sbuf_free_content(cb);
	return 1;
}
예제 #12
0
static int process_changed_file(struct asfd *asfd,
	struct sdirs *sdirs, struct conf **cconfs,
	struct sbuf *cb, struct sbuf *p1b,
	const char *adir)
{
	size_t blocklen=0;
	char *curpath=NULL;
	//logp("need to process changed file: %s (%s)\n",
	//	cb->path, cb->datapth);

	// Move datapth onto p1b.
	iobuf_move(&p1b->protocol1->datapth, &cb->protocol1->datapth);

	if(!(curpath=prepend_s(adir, p1b->protocol1->datapth.buf)))
	{
		log_out_of_memory(__func__);
		return -1;
	}
	if(dpth_protocol1_is_compressed(cb->compression, curpath))
		p1b->protocol1->sigfzp=fzp_gzopen(curpath, "rb");
	else
		p1b->protocol1->sigfzp=fzp_open(curpath, "rb");
	if(!p1b->protocol1->sigfzp)
	{
		logp("could not open %s: %s\n", curpath, strerror(errno));
		free(curpath);
		return -1;
	}
	free(curpath);

	blocklen=get_librsync_block_len(cb->protocol1->endfile.buf);
	if(!(p1b->protocol1->sigjob=
#ifdef RS_DEFAULT_STRONG_LEN
		rs_sig_begin(blocklen, RS_DEFAULT_STRONG_LEN)
#else
		// This is for librsync-1.0.0. RS_DEFAULT_STRONG_LEN was 8 in
		// librsync-0.9.7.
		rs_sig_begin(blocklen, 8,
		  rshash_to_magic_number(get_e_rshash(cconfs[OPT_RSHASH])))
#endif
	))
	{
		logp("could not start signature job.\n");
		return -1;
	}
	//logp("sig begin: %s\n", p1b->protocol1->datapth.buf);
	if(!(p1b->protocol1->infb=rs_filebuf_new(asfd, NULL,
		p1b->protocol1->sigfzp,
		-1, blocklen, -1, get_cntr(cconfs[OPT_CNTR]))))
	{
		logp("could not rs_filebuf_new for infb.\n");
		return -1;
	}
	if(!(p1b->protocol1->outfb=rs_filebuf_new(asfd, NULL, NULL,
		asfd->fd, ASYNC_BUF_LEN, -1, get_cntr(cconfs[OPT_CNTR]))))
	{
		logp("could not rs_filebuf_new for in_outfb.\n");
		return -1;
	}

	// Flag the things that need to be sent (to the client)
	p1b->flags |= SBUFL_SEND_DATAPTH;
	p1b->flags |= SBUFL_SEND_STAT;
	p1b->flags |= SBUFL_SEND_PATH;

	//logp("sending sig for %s\n", p1b->path);
	//logp("(%s)\n", p1b->datapth);

	return 0;
}
예제 #13
0
파일: restore.c 프로젝트: pablodav/burp
static int do_send_file(struct asfd *asfd, struct sbuf *sb,
	int patches, const char *best, struct cntr *cntr)
{
	enum send_e ret=SEND_FATAL;
	struct BFILE bfd;
	uint64_t bytes=0; // Unused.

	bfile_init(&bfd, 0, cntr);
	if(bfd.open_for_send(&bfd, asfd, best, sb->winattr,
		1 /* no O_NOATIME */, cntr, PROTO_1))
			return SEND_FATAL;
	if(asfd->write(asfd, &sb->path))
		ret=SEND_FATAL;
	else if(patches)
	{
		// If we did some patches, the resulting file
		// is not gzipped. Gzip it during the send.
		ret=send_whole_file_gzl(
			asfd,
			sb->protocol1->datapth.buf,
			/*quick_read*/1,
			&bytes,
			/*encpassword*/NULL,
			cntr,
			/*compression*/9,
			&bfd,
			/*extrameta*/NULL,
			/*elen*/0,
			/*key_deriv*/ENCRYPTION_UNSET,
			/*salt*/0
		);
	}
	else
	{
		// If it was encrypted, it may or may not have been compressed
		// before encryption. Send it as it as, and let the client
		// sort it out.
		if(sbuf_is_encrypted(sb))
		{
			ret=send_whole_filel(asfd,
#ifdef HAVE_WIN32
				sb->path.cmd
#endif
				sb->protocol1->datapth.buf,
				1, &bytes, cntr, &bfd, NULL, 0);
		}
		// It might have been stored uncompressed. Gzip it during
		// the send. If the client knew what kind of file it would be
		// receiving, this step could disappear.
		else if(!dpth_protocol1_is_compressed(sb->compression,
			sb->protocol1->datapth.buf))
		{
			ret=send_whole_file_gzl(
				asfd,
				sb->protocol1->datapth.buf,
				/*quick_read*/1,
				&bytes,
				/*encpassword*/NULL,
				cntr,
				/*compression*/9,
				&bfd,
				/*extrameta*/NULL,
				/*elen*/0,
				/*key_deriv*/ENCRYPTION_UNSET,
				/*salt*/0
			);
		}
		else
		{
			// If we did not do some patches, the resulting
			// file might already be gzipped. Send it as it is.
			ret=send_whole_filel(asfd,
#ifdef HAVE_WIN32
				sb->path.cmd
#endif
				sb->protocol1->datapth.buf,
				1, &bytes, cntr, &bfd, NULL, 0);
		}
	}
	bfd.close(&bfd, asfd);

	switch(ret)
	{
		case SEND_OK:
		case SEND_ERROR: // Carry on.
			return 0;
		case SEND_FATAL:
		default:
			return -1;
	}
}