示例#1
0
static int list_manifest(const char *fullpath, regex_t *regex, const char *browsedir, const char *client, struct cntr *p1cntr, struct cntr *cntr)
{
    int ars=0;
    int ret=0;
    int quit=0;
    gzFile zp=NULL;
    struct sbuf mb;
    char *manifest=NULL;
    size_t bdlen=0;
    char *lastpath=NULL;

    init_sbuf(&mb);

    if(!(manifest=prepend_s(fullpath,
                            "manifest.gz", strlen("manifest.gz"))))
    {
        log_and_send("out of memory");
        return -1;
    }
    if(!(zp=gzopen_file(manifest, "rb")))
    {
        log_and_send("could not open manifest");
        free(manifest);
        return -1;
    }
    free(manifest);

    if(browsedir) bdlen=strlen(browsedir);

    while(!quit)
    {
        int show=0;
        //logp("list manifest loop\n");
        // Need to parse while sending, to take note of the regex.

        free_sbuf(&mb);
        if((ars=sbuf_fill(NULL, zp, &mb, cntr)))
        {
            if(ars<0) ret=-1;
            // ars==1 means it ended ok.
            break;
        }

        //if(mb.path[mb.plen]=='\n') mb.path[mb.plen]='\0';
        write_status(client, STATUS_LISTING, mb.path, p1cntr, cntr);

        if(browsedir)
        {
            int r;
            if((r=check_browsedir(browsedir,
                                  &(mb.path), bdlen, &lastpath))<0)
            {
                quit++;
                ret=-1;
            }
            if(!r) continue;
            show++;
        }
        else
        {
            if(check_regex(regex, mb.path))
                show++;
        }
        if(show)
        {
            if(async_write(CMD_STAT, mb.statbuf, mb.slen)
                    || async_write(mb.cmd, mb.path, mb.plen))
            {
                quit++;
                ret=-1;
            }
            else if(sbuf_is_link(&mb)
                    && async_write(mb.cmd, mb.linkto, mb.llen))
            {
                quit++;
                ret=-1;
            }
        }
    }
    gzclose_fp(&zp);
    free_sbuf(&mb);
    if(lastpath) free(lastpath);
    return ret;
}
示例#2
0
static int maybe_delete_files_from_manifest(const char *manifest, const char *deletionsfile, struct config *cconf, struct cntr *cntr)
{
	int ars=0;
	int ret=0;
	int pcmp=0;
	FILE *dfp=NULL;
	struct sbuf db;
	struct sbuf mb;
	gzFile nmzp=NULL;
	gzFile omzp=NULL;
	char *manifesttmp=NULL;
	struct stat statp;

	if(lstat(deletionsfile, &statp))
	{
		// No deletions, no problem.
		return 0;
	}
	logp("Performing deletions on manifest\n");

	if(!(manifesttmp=get_tmp_filename(manifest)))
	{
		ret=-1;
		goto end;
	}

        if(!(dfp=open_file(deletionsfile, "rb"))
	  || !(omzp=gzopen_file(manifest, "rb"))
	  || !(nmzp=gzopen_file(manifesttmp, comp_level(cconf))))
	{
		ret=-1;
		goto end;
	}

	init_sbuf(&db);
	init_sbuf(&mb);

	while(omzp || dfp)
	{
		if(dfp && !db.path && (ars=sbuf_fill(dfp, NULL, &db, cntr)))
		{
			if(ars<0) { ret=-1; break; }
			// ars==1 means it ended ok.
			close_fp(&dfp);
		}
		if(omzp && !mb.path && (ars=sbuf_fill(NULL, omzp, &mb, cntr)))
		{
			if(ars<0) { ret=-1; break; }
			// ars==1 means it ended ok.
			gzclose_fp(&omzp);
		}

		if(mb.path && !db.path)
		{
			if(sbuf_to_manifest(&mb, NULL, nmzp)) { ret=-1; break; }
			free_sbuf(&mb);
		}
		else if(!mb.path && db.path)
		{
			free_sbuf(&db);
		}
		else if(!mb.path && !db.path) 
		{
			continue;
		}
		else if(!(pcmp=sbuf_pathcmp(&mb, &db)))
		{
			// They were the same - do not write.
			free_sbuf(&mb);
			free_sbuf(&db);
		}
		else if(pcmp<0)
		{
			// Behind in manifest. Write.
			if(sbuf_to_manifest(&mb, NULL, nmzp)) { ret=-1; break; }
			free_sbuf(&mb);
		}
		else
		{
			// Behind in deletions file. Do not write.
			free_sbuf(&db);
		}
	}

end:
	if(gzclose_fp(&nmzp))
	{
		logp("error closing %s in maybe_delete_files_from_manifest\n",
			manifesttmp);
		ret=-1;
	}
	
	close_fp(&dfp);
	gzclose_fp(&omzp);
	free_sbuf(&db);
	free_sbuf(&mb);
	if(!ret)
	{
		unlink(deletionsfile);
		if(do_rename(manifesttmp, manifest))
		{
			free(manifesttmp);
			return -1;
		}
	}
	if(manifesttmp)
	{
		unlink(manifesttmp);
		free(manifesttmp);
	}
	return ret;
}
示例#3
0
static int process_changed_file(struct sbuf *cb, struct sbuf *p1b, const char *currentdata, const char *datadirtmp, const char *deltmppath, int *resume_partial, struct cntr *cntr, struct config *cconf)
{
	size_t blocklen=0;
	char *curpath=NULL;
	//logp("need to process changed file: %s (%s)\n", cb->path, cb->datapth);

	// Move datapth onto p1b.
	if(p1b->datapth) free(p1b->datapth);
	p1b->datapth=cb->datapth;
	cb->datapth=NULL;

	if(!(curpath=prepend_s(currentdata,
		p1b->datapth, strlen(p1b->datapth))))
	{
		log_out_of_memory(__FUNCTION__);
		return -1;
	}
	if(dpth_is_compressed(cb->compression, curpath))
		p1b->sigzp=gzopen_file(curpath, "rb");
	else
		p1b->sigfp=open_file(curpath, "rb");
	if(!p1b->sigzp && !p1b->sigfp)
	{
		logp("could not open %s: %s\n",
			curpath, strerror(errno));
		free(curpath);
		return -1;
	}

	if(*resume_partial
	  && p1b->cmd==CMD_FILE
	  && cconf->librsync)
	// compression?
	{
		if(resume_partial_changed_file(cb, p1b, currentdata, curpath,
			datadirtmp, deltmppath, cconf, cntr)) return -1;

		// Burp only transfers one file at a time, so
		// if there was an interruption, there is only
		// a possibility of one partial file to resume.
		*resume_partial=0;
	}
	free(curpath);

	blocklen=get_librsync_block_len(cb->endfile);
	if(!(p1b->sigjob=rs_sig_begin(blocklen, RS_DEFAULT_STRONG_LEN)))
	{
		logp("could not start signature job.\n");
		return -1;
	}
	//logp("sig begin: %s\n", p1b->datapth);
	if(!(p1b->infb=rs_filebuf_new(NULL,
		p1b->sigfp, p1b->sigzp, -1, blocklen, -1, cntr)))
	{
		logp("could not rs_filebuf_new for infb.\n");
		return -1;
	}
	if(!(p1b->outfb=rs_filebuf_new(NULL, NULL, NULL,
		async_get_fd(), ASYNC_BUF_LEN, -1, 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->senddatapth++;
	p1b->sendstat++;
	p1b->sendpath++;

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

	return 0;
}
示例#4
0
static int resume_partial_new_file(struct sbuf *p1b, struct cntr *cntr, const char *currentdata, const char *datadirtmp, const char *deltmppath, struct dpth *dpth, struct config *cconf)
{
	int ret=0;
	int junk=0;
	struct sbuf cb;
	char *rpath=NULL;
	int istreedata=0;
	struct stat statp;
	char *partial=NULL;
	char *partialdir=NULL;
	char *zdeltmp=NULL;
	// It does not matter what this checksum is set to.
	// This is just to get an endfile string in the format that
	// process_changed_file expects.
	unsigned char checksum[18]="0123456789ABCDEF";

	// Need to set up a fake current sbuf.
	init_sbuf(&cb);
	cb.cmd=p1b->cmd;
	cb.compression=p1b->compression;
	cb.path=strdup(p1b->path);
	cb.statbuf=strdup(p1b->statbuf);
	if(!(rpath=set_new_datapth(&cb, datadirtmp, dpth, &istreedata, cconf)))
	{
		ret=-1;
		goto end;
	}

	if(!(partialdir=prepend_s(datadirtmp, "p", strlen("p")))
	  || !(partial=prepend_s(partialdir,
		cb.datapth, strlen(cb.datapth)))
	  || build_path(partialdir, cb.datapth, strlen(cb.datapth),
		&partial, partialdir))
	{
		ret=-1;
		goto end;
	}

	if(!lstat(partial, &statp) && S_ISREG(statp.st_mode))
	{
		// A previous resume was going on.
		// Need to concatenate the possible delta onto the partial
		// file.
		FILE *dfp=NULL;
		gzFile dzp=NULL;
		logp("Resume previously resumed partial new file: %s %s\n",
			cb.path, rpath);

		if(!(cb.endfile=strdup(
			get_endfile_str(statp.st_size, checksum))))
		{
			ret=-1;
			goto end;
		}
		if(cb.compression)
		{
			// Recreate partial, in case it was only partially
			// written and consequently has gz errors.
			if(!(zdeltmp=prepend(deltmppath, ".z", strlen(".z"),
				0 /* no slash */))
			  || !(dzp=gzopen_file(zdeltmp, "wb"))
			  || copy_gzpath_to_gzFile(partial, dzp)
			  || do_rename(zdeltmp, partial))
			{
				ret=-1;
				goto end;
			}
		}
		else
		{
			// Just append to the existing one.
			if(!(dfp=open_file(partial, "ab")))
			{
				ret=-1;
				goto end;
			}
		}
		if(!lstat(deltmppath, &statp) && S_ISREG(statp.st_mode))
		{
			if(cb.compression)
			{
				if(copy_gzpath_to_gzFile(deltmppath, dzp))
				{
					ret=-1;
					goto end;
				}
			}
			else
			{
				if(copy_path_to_File(deltmppath, dfp))
				{
					ret=-1;
					goto end;
				}
			}
		}
		if(dfp && close_fp(&dfp))
		{
			ret=-1;
			goto end;
		}
		if(dzp && gzclose_fp(&dzp))
		{
			ret=-1;
			goto end;
		}
		if(process_changed_file(&cb, p1b, partialdir, NULL, NULL,
			&junk /* resume_partial=0 */,
			cntr, cconf))
		{
			ret=-1;
			goto end;
		}
		if(!istreedata) incr_dpth(dpth, cconf);

		goto end;
	}

	logp("Resume partial new file: %s %s\n", cb.path, rpath);
	if(!lstat(rpath, &statp) && S_ISREG(statp.st_mode))
	{
		if(!(cb.endfile=strdup(
			get_endfile_str(statp.st_size, checksum))))
		{
			ret=-1;
			goto end;
		}
		// If compression is on, be careful with gzip unexpected
		// end of file errors.
		// Otherwise, just rename the whole file.
		unlink(partial);
		if(cb.compression)
		{
			if(copy_gzpath_to_gzpath(rpath, partial))
			{
				logp("Error in copy_gzpath_to_gzpath\n");
				ret=-1;
				goto end;
			}
			// delete the original.
			if(unlink(rpath))
			{
				logp("Failed to unlink %s: %s\n",
					rpath, strerror(errno));
				return -1;
			}
		}
		else
		{
			if(do_rename(rpath, partial))
			{
				ret=-1;
				goto end;
			}
		}
		// So, we have created a new directory beginning with 'p',
		// and moved the partial download to it.
		// We can now use the partial file as the basis of a librsync
		// transfer.
		if(process_changed_file(&cb, p1b, partialdir, NULL, NULL,
			&junk /* resume_partial=0 */,
			cntr, cconf))
		{
			ret=-1;
			goto end;
		}
		if(!istreedata) incr_dpth(dpth, cconf);
		goto end;
	}

	logp("Actually, no - just treat it as completely new\n");
end:
	if(rpath) free(rpath);
	if(partialdir) free(partialdir);
	if(partial) free(partial);
	if(zdeltmp) free(zdeltmp);
	free_sbuf(&cb);
	return ret;
}
示例#5
0
int backup_phase2_server(gzFile *cmanfp, const char *phase1data, const char *phase2data, const char *unchangeddata, const char *datadirtmp, struct dpth *dpth, const char *currentdata, const char *working, const char *client, struct cntr *p1cntr, int resume, struct cntr *cntr, struct config *cconf)
{
	int ars=0;
	int ret=0;
	gzFile p1zp=NULL;
	char *deltmppath=NULL;
	char *last_requested=NULL;
	// Where to write phase2data.
	// Data is not getting written to a compressed file.
	// This is important for recovery if the power goes.
	FILE *p2fp=NULL;
	// unchanged data
	FILE *ucfp=NULL;
	int resume_partial=resume;

	struct sbuf cb;		// file list in current manifest
	struct sbuf p1b;	// file list from client

	struct sbuf rb;		// receiving file from client

	init_sbuf(&cb);
	init_sbuf(&p1b);
	init_sbuf(&rb);

	if(!(p1zp=gzopen_file(phase1data, "rb")))
		goto error;

	// Open in read+write mode, so that they can be read through if
	// we need to resume.
	// First, open them in a+ mode, so that they will be created if they
	// do not exist.
	if(!(ucfp=open_file(unchangeddata, "a+b")))
		goto error;
	if(!(p2fp=open_file(phase2data, "a+b")))
		goto error;
	close_fp(&ucfp);
	close_fp(&p2fp);

	if(!(ucfp=open_file(unchangeddata, "r+b")))
		goto error;
	if(!(p2fp=open_file(phase2data, "r+b")))
		goto error;

	if(resume && do_resume(p1zp, p2fp, ucfp, dpth, cconf, client,
		p1cntr, cntr)) goto error;

	logp("Begin phase2 (receive file data)\n");

	if(!(deltmppath=prepend_s(working, "delta.tmp", strlen("delta.tmp"))))
		goto error;

	while(1)
	{
		int sts=0;
	//	logp("in loop, %s %s %c\n",
	//		*cmanfp?"got cmanfp":"no cmanfp",
	//		rb.path?:"no rb.path", rb.path?'X':rb.cmd);
		if(rb.path) write_status(client, STATUS_BACKUP,
			rb.path, p1cntr, cntr);
		else write_status(client, STATUS_BACKUP,
			p1b.path, p1cntr, cntr);
		if((last_requested || !p1zp || writebuflen)
		  && (ars=do_stuff_to_receive(&rb, p2fp, datadirtmp, dpth,
			working, &last_requested, deltmppath, cntr, cconf)))
		{
			if(ars<0) goto error;
			// 1 means ok.
			break;
		}

		if((sts=do_stuff_to_send(&p1b, &last_requested))<0)
			goto error;

		if(!sts && p1zp)
		{
		   free_sbuf(&p1b);

		   if((ars=sbuf_fill_phase1(NULL, p1zp, &p1b, cntr)))
		   {
			if(ars<0) goto error;
			// ars==1 means it ended ok.
			gzclose_fp(&p1zp);
			//logp("ended OK - write phase2end");
			if(async_write_str(CMD_GEN, "backupphase2end"))
				goto error;
		   }

		   //logp("check: %s\n", p1b.path);

		   if(!*cmanfp)
		   {
			// No old manifest, need to ask for a new file.
			//logp("no cmanfp\n");
			if(process_new(&p1b, ucfp, currentdata,
				datadirtmp, deltmppath,
				dpth, &resume_partial,
				cntr, cconf)) goto error;
		   }
		   else
		   {
			// Have an old manifest, look for it there.

			// Might already have it, or be ahead in the old
			// manifest.
			if(cb.path)
			{
				if((ars=maybe_process_file(&cb, &p1b,
					ucfp, currentdata, datadirtmp,
					deltmppath, dpth, &resume_partial,
					cntr, cconf)))
				{
					if(ars<0) goto error;
					// Do not free it - need to send stuff.
					continue;
				}
				//free_sbuf(&p1b);
			}

			while(*cmanfp)
			{
				free_sbuf(&cb);
				if((ars=sbuf_fill(NULL, *cmanfp, &cb, cntr)))
				{
					// ars==1 means it ended ok.
					if(ars<0) goto error;
					gzclose_fp(cmanfp);
		//logp("ran out of current manifest\n");
					if(process_new(&p1b, ucfp,
						currentdata, datadirtmp,
						deltmppath, dpth,
						&resume_partial, cntr, cconf))
							goto error;
					break;
				}
		//logp("against: %s\n", cb.path);
				if((ars=maybe_process_file(&cb, &p1b,
					ucfp, currentdata, datadirtmp,
					deltmppath, dpth, &resume_partial,
					cntr, cconf)))
				{
					if(ars<0) goto error;
					// Do not free it - need to send stuff.
					break;
				}
			}
		   }
		}
	}

	goto end;

error:
	ret=-1;
end:
	if(close_fp(&p2fp))
	{
		logp("error closing %s in backup_phase2_server\n",
			phase2data);
		ret=-1;
	}
	if(close_fp(&ucfp))
	{
		logp("error closing %s in backup_phase2_server\n",
			unchangeddata);
		ret=-1;
	}
	free(deltmppath);
	free_sbuf(&cb);
	free_sbuf(&p1b);
	free_sbuf(&rb);
	gzclose_fp(&p1zp);
	if(!ret) unlink(phase1data);

	logp("End phase2 (receive file data)\n");

	return ret;
}
示例#6
0
// TODO: Some of the repeated code in this can be factored out.
static int resume_partial_changed_file(struct sbuf *cb, struct sbuf *p1b, const char *currentdata, const char *curpath, const char *datadirtmp, const char *deltmppath, struct config *cconf, struct cntr *cntr)
{
	int ret=0;
	int istreedata=0;
	struct stat dstatp;
	struct stat cstatp;
	char *partial=NULL;
	char *partialdir=NULL;
	char *zdeltmp=NULL;
	struct sbuf xb;

	init_sbuf(&xb);
	xb.cmd=cb->cmd;
	xb.compression=cb->compression;
	xb.path=strdup(cb->path);
	xb.statbuf=strdup(cb->statbuf);
	xb.datapth=strdup(p1b->datapth);
	xb.endfile=strdup(cb->endfile);

	logp("Resume partial changed file: %s\n", xb.path);
	if(!lstat(deltmppath, &dstatp) && S_ISREG(dstatp.st_mode)
	     && !lstat(curpath, &cstatp) && S_ISREG(cstatp.st_mode))
	{
		int junk=0;
		gzFile dzp=NULL;
		FILE *dfp=NULL;
		struct stat pstatp;
		if(!(partialdir=prepend_s(datadirtmp, "p", strlen("p")))
		  || !(partial=prepend_s(partialdir,
			xb.datapth, strlen(xb.datapth)))
		  || build_path(partialdir, xb.datapth, strlen(xb.datapth),
			&partial, partialdir))
		{
			ret=-1;
			goto end;
		}

		if(!lstat(partial, &pstatp))
		{
			if(!S_ISREG(pstatp.st_mode))
			{
				logp("%s is not a regular file\n", partial);
				goto actuallyno;
			}
			if(pstatp.st_size>cstatp.st_size)
			{
				// Looks like a previously resumed file.
				if(xb.compression)
				{
					// Need to read and recreate it, in
					// case it was not fully created.
					if(!(zdeltmp=prepend(deltmppath,
						".z", strlen(".z"),
						0 /* no slash */))
					  || !(dzp=gzopen_file(zdeltmp, "wb"))
					  || copy_gzpath_to_gzFile(partial,
						dzp)
					  || do_rename(zdeltmp, partial))
					{
						ret=-1;
						goto end;
					}
				}
				else
				{
					// Append to the existing one.
					if(!(dfp=open_file(partial, "ab")))
					{
						ret=-1;
						goto end;
					}
				}
			}
			else
			{
				unlink(partial);
				// Copy the whole of p1b->sigfp/sigzp to
				// partial.
				if(xb.compression)
				{
					if(!(dzp=gzopen_file(partial, "wb"))
					  || copy_gzFile_to_gzFile(p1b->sigzp,
						dzp))
					{
						ret=-1;
						goto end;
					}
				}
				else
				{
					if(!(dfp=open_file(partial, "wb"))
					  || copy_File_to_File(p1b->sigfp, dfp))
					{
						ret=-1;
						goto end;
					}
				}
			}
			// Now, copy the whole of deltmppath onto partial.
			// dzp or dfp will be open by this point.
			if(xb.compression)
			{
				if(copy_gzpath_to_gzFile(deltmppath, dzp))
				{
					ret=-1;
					goto end;
				}
			}
			else
			{
				if(copy_path_to_File(deltmppath, dfp))
				{
					ret=-1;
					goto end;
				}
			}
		}
		else
		{
		//	Copy the whole of p1b->sigfp/sigzp onto partial.
		//	Copy the whole of deltmppath onto partial.
			if(xb.compression)
			{
				// There is no partial, this creates it.
				if(!(dzp=gzopen_file(partial, "wb"))
				  || copy_gzFile_to_gzFile(p1b->sigzp, dzp))
				{
					ret=-1;
					goto end;
				}
			}
			else
			{
				// There is no partial, this creates it.
				if(!(dfp=open_file(partial, "wb"))
				  || copy_File_to_File(p1b->sigfp, dfp))
				{
					ret=-1;
					goto end;
				}
			}
			if(xb.compression)
			{
				if(copy_gzpath_to_gzFile(deltmppath, dzp))
				{
					ret=-1;
					goto end;
				}
			}
			else
			{
				if(copy_path_to_File(deltmppath, dfp))
				{
					ret=-1;
					goto end;
				}
			}
		}
		if(dfp && close_fp(&dfp))
		{
			ret=-1;
			goto end;
		}
		if(dzp && gzclose_fp(&dzp))
		{
			ret=-1;
			goto end;
		}
		// Use partial as the basis for a librsync transfer.
		
		// So, we have created a new directory beginning with 'p',
		// and moved the partial download to it.
		// We can now use the partial file as the basis of a librsync
		// transfer. 
		if(process_changed_file(&xb, p1b, partialdir, NULL, NULL,
			&junk /* resume_partial=0 */,
			cntr, cconf))
		{
			ret=-1;
			goto end;
		}

		goto end;
	}

actuallyno:
	logp("Actually, no - just forget the previous delta\n");
end:
	if(partialdir) free(partialdir);
	if(partial) free(partial);
	if(zdeltmp) free(zdeltmp);
	free_sbuf(&xb);
	return ret;
}
示例#7
0
static int process_changed_file(struct asfd *asfd,
	struct sdirs *sdirs, struct conf *cconf,
	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_copy(&p1b->burp1->datapth, &cb->burp1->datapth);
	cb->burp1->datapth.buf=NULL;

	if(!(curpath=prepend_s(adir, p1b->burp1->datapth.buf)))
	{
		log_out_of_memory(__func__);
		return -1;
	}
	if(dpthl_is_compressed(cb->compression, curpath))
		p1b->burp1->sigzp=gzopen_file(curpath, "rb");
	else
		p1b->burp1->sigfp=open_file(curpath, "rb");
	if(!p1b->burp1->sigzp && !p1b->burp1->sigfp)
	{
		logp("could not open %s: %s\n", curpath, strerror(errno));
		free(curpath);
		return -1;
	}
	free(curpath);

	blocklen=get_librsync_block_len(cb->burp1->endfile.buf);
	if(!(p1b->burp1->sigjob=rs_sig_begin(blocklen, RS_DEFAULT_STRONG_LEN)))
	{
		logp("could not start signature job.\n");
		return -1;
	}
	//logp("sig begin: %s\n", p1b->burp1->datapth.buf);
	if(!(p1b->burp1->infb=rs_filebuf_new(asfd, NULL,
		p1b->burp1->sigfp, p1b->burp1->sigzp,
		-1, blocklen, -1, cconf->cntr)))
	{
		logp("could not rs_filebuf_new for infb.\n");
		return -1;
	}
	if(!(p1b->burp1->outfb=rs_filebuf_new(asfd, NULL, NULL, NULL,
		asfd->fd, ASYNC_BUF_LEN, -1, cconf->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;
}
示例#8
0
int backup_phase2_server(struct asfd *asfd,
	struct sdirs *sdirs, struct conf *cconf,
	gzFile *cmanfp, struct dpthl *dpthl, int resume)
{
	int ars=0;
	int ret=0;
	gzFile p1zp=NULL;
	char *deltmppath=NULL;
	char *last_requested=NULL;
	// Where to write phase2data.
	// Data is not getting written to a compressed file.
	// This is important for recovery if the power goes.
	FILE *p2fp=NULL;
	// unchanged data
	FILE *ucfp=NULL;

	struct sbuf *cb=NULL; // file list in current manifest
	struct sbuf *p1b=NULL; // file list from client

	struct sbuf *rb=NULL; // receiving file from client

	if(!(cb=sbuf_alloc(cconf))
	  || !(p1b=sbuf_alloc(cconf))
	  || !(rb=sbuf_alloc(cconf)))
		goto error;

	if(!(p1zp=gzopen_file(sdirs->phase1data, "rb")))
		goto error;

	// Open in read+write mode, so that they can be read through if
	// we need to resume.
	// First, open them in a+ mode, so that they will be created if they
	// do not exist.
	if(!(ucfp=open_file(sdirs->unchangeddata, "a+b"))
	  || !(p2fp=open_file(sdirs->phase2data, "a+b")))
		goto error;
	close_fp(&ucfp);
	close_fp(&p2fp);
	if(!(ucfp=open_file(sdirs->unchangeddata, "r+b"))
	  || !(p2fp=open_file(sdirs->phase2data, "r+b")))
		goto error;

	if(resume && do_resume(p1zp, p2fp, ucfp, dpthl, cconf))
		goto error;

	logp("Begin phase2 (receive file data)\n");

	while(1)
	{
		int sts=0;
		//printf("in loop, %s %s %c\n",
		//	*cmanfp?"got cmanfp":"no cmanfp",
		//	rb->path.buf?:"no rb->path",
	 	//	rb->path.buf?'X':rb->path.cmd);
		if(write_status(STATUS_BACKUP,
			rb->path.buf?rb->path.buf:p1b->path.buf, cconf))
				goto error;
		if((last_requested || !p1zp || asfd->writebuflen)
		  && (ars=do_stuff_to_receive(asfd, sdirs,
			cconf, rb, p2fp, dpthl, &last_requested)))
		{
			if(ars<0) goto error;
			// 1 means ok.
			break;
		}

		if((sts=do_stuff_to_send(asfd, p1b, &last_requested))<0)
			goto error;

		if(!sts && p1zp)
		{
		   sbuf_free_content(p1b);

		   if((ars=sbufl_fill_phase1(p1b, NULL, p1zp, cconf->cntr)))
		   {
			if(ars<0) goto error;
			// ars==1 means it ended ok.
			gzclose_fp(&p1zp);
			//logp("ended OK - write phase2end");
			if(asfd->write_str(asfd, CMD_GEN, "backupphase2end"))
				goto error;
		   }

		   //logp("check: %s\n", p1b.path);

		   if(!*cmanfp)
		   {
			// No old manifest, need to ask for a new file.
			//logp("no cmanfp\n");
			if(process_new(sdirs, cconf, p1b, ucfp, dpthl))
				goto error;
		   }
		   else
		   {
			// Have an old manifest, look for it there.

			// Might already have it, or be ahead in the old
			// manifest.
			if(cb->path.buf)
			{
				if((ars=maybe_process_file(asfd, sdirs, cconf,
					cb, p1b, ucfp, dpthl)))
				{
					if(ars<0) goto error;
					// Do not free it - need to send stuff.
					continue;
				}
				//free_sbufl(&p1b);
			}

			while(*cmanfp)
			{
				sbuf_free_content(cb);
				if((ars=sbufl_fill(cb, asfd, NULL,
					*cmanfp, cconf->cntr)))
				{
					// ars==1 means it ended ok.
					if(ars<0) goto error;
					gzclose_fp(cmanfp);
		//logp("ran out of current manifest\n");
					if(process_new(sdirs, cconf,
						p1b, ucfp, dpthl))
							goto error;
					break;
				}
		//logp("against: %s\n", cb.path);
				if((ars=maybe_process_file(asfd, sdirs, cconf,
					cb, p1b, ucfp, dpthl)))
				{
					if(ars<0) goto error;
					// Do not free it - need to send stuff.
					break;
				}
			}
		   }
		}
	}

	goto end;

error:
	ret=-1;
end:
	if(close_fp(&p2fp))
	{
		logp("error closing %s in backup_phase2_server\n",
			sdirs->phase2data);
		ret=-1;
	}
	if(close_fp(&ucfp))
	{
		logp("error closing %s in backup_phase2_server\n",
			sdirs->unchangeddata);
		ret=-1;
	}
	free(deltmppath);
	sbuf_free(cb);
	sbuf_free(p1b);
	sbuf_free(rb);
	gzclose_fp(&p1zp);
	if(!ret) unlink(sdirs->phase1data);

	logp("End phase2 (receive file data)\n");

	return ret;
}
示例#9
0
int backup_phase1_server(struct asfd *asfd,
                         struct sdirs *sdirs, struct conf *conf)
{
    int ars=0;
    int ret=-1;
    struct sbuf *sb=NULL;
    gzFile p1zp=NULL;
    char *phase1tmp=NULL;

    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;
    }
    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;
}
示例#10
0
/* Need to make all the stuff that this does atomic so that existing backups
   never get broken, even if somebody turns the power off on the server. */ 
static int atomic_data_jiggle(const char *finishing, const char *working, const char *manifest, const char *current, const char *currentdata, const char *datadir, const char *datadirtmp, const char *deletionsfile, struct config *cconf, const char *client, int hardlinked, unsigned long bno, struct cntr *p1cntr, struct cntr *cntr)
{
	int ret=0;
	int ars=0;
	char *datapth=NULL;
	char *tmpman=NULL;
	struct stat statp;

	char *deltabdir=NULL;
	char *deltafdir=NULL;
	char *sigpath=NULL;
	gzFile zp=NULL;
	struct sbuf sb;

	FILE *delfp=NULL;

	logp("Doing the atomic data jiggle...\n");

	if(!(tmpman=get_tmp_filename(manifest))) return -1;
	if(lstat(manifest, &statp))
	{
		// Manifest does not exist - maybe the server was killed before
		// it could be renamed.
		logp("%s did not exist - trying %s\n", manifest, tmpman);
		do_rename(tmpman, manifest);
	}
	free(tmpman);
	if(!(zp=gzopen_file(manifest, "rb"))) return -1;

	if(!(deltabdir=prepend_s(current,
		"deltas.reverse", strlen("deltas.reverse")))
	  || !(deltafdir=prepend_s(finishing,
		"deltas.forward", strlen("deltas.forward")))
	  || !(sigpath=prepend_s(current,
		"sig.tmp", strlen("sig.tmp"))))
	{
		logp("out of memory\n");
		gzclose_fp(&zp);
		return -1;
	}

	mkdir(datadir, 0777);
	init_sbuf(&sb);
	while(!(ars=sbuf_fill(NULL, zp, &sb, cntr)))
	{
		if(sb.datapth)
		{
			write_status(client, STATUS_SHUFFLING,
				sb.datapth, p1cntr, cntr);

			if((ret=jiggle(sb.datapth, currentdata, datadirtmp,
				datadir, deltabdir, deltafdir,
				sigpath, sb.endfile, deletionsfile, &delfp,
				&sb,
				hardlinked, sb.compression, cntr, cconf)))
					break;
		}
		free_sbuf(&sb);
	}
	if(!ret)
	{
		if(ars>0) ret=0;
		else ret=-1;
	}

	if(close_fp(&delfp))
	{
		logp("error closing %s in atomic_data_jiggle\n", deletionsfile);
		ret=-1;
	}
	gzclose_fp(&zp);

	if(maybe_delete_files_from_manifest(manifest, deletionsfile,
		cconf, cntr)) ret=-1;

	// Remove the temporary data directory, we have probably removed
	// useful files from it.
	sync(); // try to help CIFS
	recursive_delete(deltafdir, NULL, FALSE /* do not del files */);

	if(deltabdir) free(deltabdir);
	if(deltafdir) free(deltafdir);
	if(sigpath) free(sigpath);
	if(datapth) free(datapth);
	return ret;
}
示例#11
0
static int make_rev_delta(const char *src, const char *sig, const char *del, int compression, struct cntr *cntr, struct config *cconf)
{
	gzFile srczp=NULL;
	FILE *srcfp=NULL;
	FILE *sigp=NULL;
	rs_result result;
	rs_signature_t *sumset=NULL;

//logp("make rev delta: %s %s %s\n", src, sig, del);
	if(!(sigp=open_file(sig, "rb"))) return -1;
	if((result=rs_loadsig_file(sigp, &sumset, NULL))
	  || (result=rs_build_hash_table(sumset)))
	{
		fclose(sigp);
		rs_free_sumset(sumset);
		return result;
	}
	fclose(sigp);

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

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

	if(!srczp && !srcfp)
	{
		rs_free_sumset(sumset);
		return -1;
	}

	if(cconf->compression)
	{
		gzFile delzp=NULL;
		if(!(delzp=gzopen_file(del, comp_level(cconf))))
		{
			gzclose_fp(&srczp);
			close_fp(&srcfp);
			rs_free_sumset(sumset);
			return -1;
		}
		result=rs_delta_gzfile(sumset, srcfp, srczp, NULL, delzp, NULL, cntr);
		if(gzclose_fp(&delzp))
		{
			logp("error closing %s in make_rev_delta\n", del);
			result=RS_IO_ERROR;
		}
	}
	else
	{
		FILE *delfp=NULL;
		if(!(delfp=open_file(del, "wb")))
		{
			gzclose_fp(&srczp);
			close_fp(&srcfp);
			rs_free_sumset(sumset);
			return -1;
		}
		result=rs_delta_gzfile(sumset, srcfp, srczp, delfp, NULL, NULL, cntr);
		if(close_fp(&delfp))
		{
			logp("error closing %s in make_rev_delta\n", del);
			gzclose_fp(&srczp);
			close_fp(&srcfp);
			rs_free_sumset(sumset);
			return -1;
		}
	}

	rs_free_sumset(sumset);
	gzclose_fp(&srczp);
	close_fp(&srcfp);

	return result;
}