예제 #1
0
파일: ca.c 프로젝트: Kalimeiro/burp
static char *get_ca_dir(struct conf *conf)
{
	FILE *fp=NULL;
	char buf[4096]="";
	if(!(fp=open_file(conf->ca_conf, "r"))) return NULL;
	while(fgets(buf, sizeof(buf), fp))
	{
		char *field=NULL;
		char *value=NULL;
		if(conf_get_pair(buf, &field, &value)
		  || !field || !value) continue;

		if(!strcasecmp(field, "CA_DIR"))
		{
			if(!(gca_dir=strdup(value)))
			{
				log_out_of_memory(__func__);
				fclose(fp);
				return NULL;
			}
			break;
		}
	}
	fclose(fp);
	return gca_dir;
}
예제 #2
0
파일: list.c 프로젝트: Kalimeiro/burp
static char *json_escape(const char *str)
{
	int i;
	int j;
	int n=0;
	char *estr=NULL;
	const char echars[]="\\\"";

	if(!str) return NULL;

	n=strlen(str);
	estr=(char *)malloc(2*n*sizeof(char));
	if(!estr)
	{
		log_out_of_memory(__func__);
		return NULL;
	}
	for(i=0, j=0; i<n; i++, j++)
	{
		int k=sizeof(echars);
		for(; k && str[i]!=echars[k-1]; k--);
		if(k) estr[j++]='\\';
		estr[j]=str[i];
	}
	estr[j]='\0';
	return estr;
}
예제 #3
0
파일: xattr.c 프로젝트: jkniiv/burp
static char *get_next_str(struct asfd *asfd, char **data, size_t *l,
	struct conf *conf, ssize_t *s, const char *path)
{
	char *ret=NULL;

	if((sscanf(*data, "%08X", (unsigned int *)s))!=1)
	{
		logw(asfd, conf, "sscanf of xattr '%s' %d failed for %s\n",
			*data, *l, path);
		return NULL;
	}
	*data+=8;
	*l-=8;
	if(!(ret=(char *)malloc((*s)+1)))
	{
		log_out_of_memory(__func__);
		return NULL;
	}
	memcpy(ret, *data, *s);
	ret[*s]='\0';

	*data+=*s;
	*l-=*s;

	return ret;
}
예제 #4
0
파일: list.c 프로젝트: ZungBang/burp
int check_browsedir(const char *browsedir,
                    struct sbuf *mb, size_t bdlen, char **last_bd_match)
{
    char *cp=mb->path.buf;
    char *copy=NULL;
    if(bdlen>0)
    {
        if(strncmp(browsedir, cp, bdlen))
            return 0;
        cp+=bdlen;
        if(browsedir[bdlen-1]!='/')
        {
            if(*cp!='\0')
            {
                if(*cp!='/')
                    return 0;
                cp++;
            }
        }
    }
    if(*cp=='\0')
        cp=(char *)".";
    if(!(copy=strdup_w(cp, __func__)))
        goto error;
    if((cp=strchr(copy, '/')))
    {
        if(bdlen==0) cp++;
        *cp='\0';

        maybe_fake_directory(mb);
    }
    else if(!strcmp(mb->path.buf, "/")
            && !strcmp(browsedir, "/"))
        maybe_fake_directory(mb);
    else if(mb->path.cmd==CMD_DIRECTORY)
        maybe_fake_directory(mb);

    // Strip off possible trailing slash.
    if((cp=strrchr(copy, '/')) && cp>copy)
        *cp='\0';

    if(*last_bd_match
            && !strcmp(*last_bd_match, copy))
    {
        // Got a duplicate match.
        free_w(&copy);
        return 0;
    }
    free_w(&mb->path.buf);
    mb->path.buf=copy;
    free_w(last_bd_match);
    if(!(*last_bd_match=strdup_w(copy, __func__)))
        goto error;
    return 1;
error:
    free_w(&copy);
    log_out_of_memory(__func__);
    return -1;
}
예제 #5
0
파일: find.c 프로젝트: Kalimeiro/burp
static int get_files_in_directory(DIR *directory, struct dirent ***nl, int *count)
{
	int status;
	int allocated=0;
	struct dirent **ntmp=NULL;
	struct dirent *entry=NULL;
	struct dirent *result=NULL;

	/* Graham says: this here is doing a funky kind of scandir/alphasort
	   that can also run on Windows.
	   TODO: split into a scandir function
	*/
	while(1)
	{
		char *p;
		if(!(entry=(struct dirent *)malloc(
			sizeof(struct dirent)+name_max+100)))
		{
			log_out_of_memory(__func__);
			return -1;
		}
		status=readdir_r(directory, entry, &result);
		if(status || !result)
		{
			free(entry);
			break;
		}

		p=entry->d_name;
		ASSERT(name_max+1 > (int)sizeof(struct dirent)+strlen(p));

		/* Skip `.', `..', and excluded file names.  */
		if(!p || !strcmp(p, ".") || !strcmp(p, ".."))
		{
			free(entry);
			continue;
		}

		if(*count==allocated)
		{
			if(!allocated) allocated=10;
			else allocated*=2;

			if(!(ntmp=(struct dirent **)
			  realloc_w(*nl, allocated*sizeof(**nl), __func__)))
			{
				free(entry);
				return -1;
			}
			*nl=ntmp;
		}
		(*nl)[(*count)++]=entry;
	}
	if(*nl) qsort(*nl, *count, sizeof(**nl),
		(int (*)(const void *, const void *))myalphasort);
	return 0;
}
예제 #6
0
파일: list.c 프로젝트: Sherlock221B/burp
int check_browsedir(const char *browsedir, char **path,
	size_t bdlen, char **last_bd_match)
{
	char *cp=NULL;
	char *copy=NULL;
	if(strncmp(browsedir, *path, bdlen))
		return 0;
	if((*path)[bdlen+1]=='\0' || (bdlen>1 && (*path)[bdlen]!='/'))
		return 0;

	/* Lots of messing around related to whether browsedir was '', '/', or
   	   something else. */
	if(*browsedir)
	{
		if(!strcmp(browsedir, "/"))
		{
			if(!(copy=strdup_w((*path)+bdlen, __func__)))
				goto error;
			if((cp=strchr(copy+1, '/'))) *cp='\0';
		}
		else
		{
			if(!(copy=strdup_w((*path)+bdlen+1, __func__)))
				goto error;
			if((cp=strchr(copy, '/'))) *cp='\0';
		}
	}
	else
	{
		if(!(copy=strdup_w((*path)+bdlen, __func__)))
			goto error;
		if(*copy=='/') *(copy+1)='\0';
		// Messing around for Windows.
		else if(strlen(copy)>2 && copy[1]==':' && copy[2]=='/')
			copy[2]='\0';
	}
	if(last_bd_match && *last_bd_match)
	{
		if(!strcmp(*last_bd_match, copy))
		{
			// Got a duplicate match.
			free(copy);
			return 0;
		}
		free(*last_bd_match);
	}
	free(*path);
	*path=copy;
	if(!(*last_bd_match=strdup_w(copy, __func__)))
		goto error;
	return 1;
error:
	if(copy) free(copy);
	log_out_of_memory(__func__);
	return -1;
}
예제 #7
0
파일: candidate.c 프로젝트: jkniiv/burp
// When a backup is ongoing, use this to add newly complete candidates.
int candidate_add_fresh(const char *path, struct conf *conf)
{
    int ars;
    int ret=-1;
    gzFile zp=NULL;
    const char *cp=NULL;
    struct sbuf *sb=NULL;
    struct candidate *candidate=NULL;
    struct blk *blk=NULL;

    if(!(candidate=candidates_add_new())) goto end;
    cp=path+strlen(conf->directory);
    while(cp && *cp=='/') cp++;
    if(!(candidate->path=strdup(cp)))
    {
        log_out_of_memory(__func__);
        goto end;
    }

    if(!(sb=sbuf_alloc(conf))
            || !(blk=blk_alloc())
            || !(zp=gzopen_file(path, "rb")))
        goto end;
    while(zp)
    {
        if((ars=sbuf_fill_from_gzfile(sb, NULL /* struct async */,
                                      zp, blk, NULL, conf))<0)
            goto end;
        else if(ars>0)
        {
            // Reached the end.
            break;
        }
        if(!*(blk->weak)) continue;
        if(is_hook(blk->weak))
        {
            if(sparse_add_candidate(blk->weak, candidate))
                goto end;
        }
        *blk->weak='\0';
    }

    if(scores_grow(scores, candidates_len)) goto end;
    candidates_set_score_pointers(candidates, candidates_len, scores);
    scores_reset(scores);
    //printf("HERE: %d candidates\n", (int)candidates_len);

    ret=0;
end:
    gzclose_fp(&zp);
    sbuf_free(sb);
    blk_free(blk);
    return ret;
}
예제 #8
0
파일: prog.c 프로젝트: jkniiv/burp
static int replace_conf_str(const char *newval, char **dest)
{
    if(newval)
    {
        if(*dest) free(*dest);
        if(!(*dest=strdup(newval)))
        {
            log_out_of_memory(__func__);
            return -1;
        }
    }
    return 0;
}
예제 #9
0
파일: asyncio.c 프로젝트: barroque/burp
static int async_alloc_buf(char **buf, size_t *buflen, size_t bufmaxsize)
{
	if(!*buf)
	{
		if(!(*buf=(char *)malloc(bufmaxsize)))
		{
			log_out_of_memory(__FUNCTION__);
			return -1;
		}
		truncate_buf(buf, buflen);
	}
	return 0;
}
예제 #10
0
static int get_link(const char *basedir, const char *lnk, char real[], size_t r)
{
	int len=0;
	char *tmp=NULL;
	if(!(tmp=prepend_s(basedir, lnk, strlen(lnk))))
	{
		log_out_of_memory(__FUNCTION__);
		return -1;
	}
	if((len=readlink(tmp, real, r-1))<0) len=0;
	real[len]='\0';
	free(tmp);
	return 0;
}
예제 #11
0
파일: counter.c 프로젝트: barroque/burp
static int add_to_backup_list(char ***backups, int *b, const char *tok)
{
	const char *str=NULL;
	if(!(str=get_backup_str(tok))) return 0;
	if(!(*backups=(char **)realloc(*backups, ((*b)+2)*sizeof(char *)))
	  || !((*backups)[*b]=strdup(str)))
	{
		log_out_of_memory(__FUNCTION__);
		return -1;
	}
	(*backups)[(*b)+1]=NULL;
	(*b)++;
	return 0;
}
예제 #12
0
파일: bedup.c 프로젝트: kaptk2/burp
static int get_link(const char *basedir, const char *lnk, char real[], size_t r)
{
	int len=0;
	char *tmp=NULL;
	if(!(tmp=prepend(basedir, lnk, "/")))
	{
		log_out_of_memory(__func__);
		return -1;
	}
	if((len=readlink(tmp, real, r-1))<0) len=0;
	real[len]='\0';
	free_w(&tmp);
	// Strip any trailing slash.
	if(real[strlen(real)-1]=='/') real[strlen(real)-1]='\0';
	return 0;
}
예제 #13
0
파일: manio.c 프로젝트: jkniiv/burp
// Return -1 on error, 0 on OK, 1 for srcmanio finished.
int manio_copy_entry(struct asfd *asfd, struct sbuf **csb, struct sbuf *sb,
	struct blk **blk, struct manio *srcmanio,
	struct manio *dstmanio, struct conf *conf)
{
	static int ars;
	static char *copy=NULL;

	// Use the most recent stat for the new manifest.
	if(dstmanio && manio_write_sbuf(dstmanio, sb)) goto error;

	if(!(copy=strdup((*csb)->path.buf)))
	{
		log_out_of_memory(__func__);
		goto error;
	}

	while(1)
	{
		if((ars=manio_sbuf_fill(srcmanio, asfd, *csb,
			*blk, NULL, conf))<0) goto error;
		else if(ars>0)
		{
			// Finished.
			sbuf_free(*csb); *csb=NULL;
			blk_free(*blk); *blk=NULL;
			free(copy);
			return 1;
		}

		// Got something.
		if(strcmp((*csb)->path.buf, copy))
		{
			// Found the next entry.
			free(copy);
			return 0;
		}
		// Should have the next signature.
		// Write it to the destination manifest.
		if(dstmanio && manio_write_sig_and_path(dstmanio, *blk))
			goto error;
	}

error:
	if(copy) free(copy);
	return -1;
}
예제 #14
0
파일: ssl.c 프로젝트: adrianimboden/burp
static int setenv_x509_date(ASN1_TIME *tm, const char *env)
{
	BIO *bio_out=NULL;
	BUF_MEM *bptr=NULL;
	char tmpbuf[256]="";
	if(!(bio_out=BIO_new(BIO_s_mem())))
	{
		log_out_of_memory(__func__);
		return -1;
	}
	ASN1_TIME_print(bio_out, tm);
	BIO_get_mem_ptr(bio_out, &bptr);
	BIO_gets(bio_out, tmpbuf, sizeof(tmpbuf)-1);
	BIO_free_all(bio_out);
	sanitise(tmpbuf);
	setenv(env, (char*)tmpbuf, 1);
	return 0;
}
예제 #15
0
파일: ssl.c 프로젝트: adrianimboden/burp
static int setenv_x509_serialnumber(ASN1_INTEGER *i, const char *env)
{
	BIO *bio_out=NULL;
	BUF_MEM *bptr=NULL;
	char tmpbuf[256]="";
	if(!(bio_out=BIO_new(BIO_s_mem())))
	{
		log_out_of_memory(__func__);
		return -1;
	}
	i2a_ASN1_INTEGER(bio_out, i);
	BIO_get_mem_ptr(bio_out, &bptr);
	BIO_gets(bio_out, tmpbuf, sizeof(tmpbuf)-1);
	BIO_free_all(bio_out);
	sanitise(tmpbuf);
	setenv(env, (char*)tmpbuf, 1);
	return 0;
}
예제 #16
0
파일: conffile.c 프로젝트: EmisFR/burp
static int deal_with_dot_inclusion(const char *conf_path,
	char **extrafile, struct conf **confs)
{
	int ret=-1;
	char *copy=NULL;
#ifndef HAVE_WIN32
	int i=0;
	glob_t globbuf;
	if(**extrafile!='/')
#else
	if(strlen(*extrafile)>2
	  && (*extrafile)[1]!=':')
#endif
	{
		// It is relative to the directory that the
		// current conf file is in.
		char *cp=NULL;
		char *tmp=NULL;
		if(!(copy=strdup_w(conf_path, __func__)))
			goto end;
		if((cp=strrchr(copy, '/'))) *cp='\0';
		if(!(tmp=prepend_s(copy, *extrafile)))
		{
			log_out_of_memory(__func__);
			goto end;
		}
		free_w(extrafile);
		*extrafile=tmp;
	}
#ifndef HAVE_WIN32
	// Treat it is a glob expression.
	memset(&globbuf, 0, sizeof(globbuf));
	glob(*extrafile, 0, NULL, &globbuf);
	for(i=0; (unsigned int)i<globbuf.gl_pathc; i++)
		if((ret=conf_load_lines_from_file(globbuf.gl_pathv[i], confs)))
			goto end;
#else
	ret=conf_load_lines_from_file(*extrafile, confs);
#endif

end:
	free_w(&copy);
	return ret;
}
예제 #17
0
static int gen_rev_delta(const char *sigpath, const char *deltadir,
	const char *oldpath, const char *finpath, const char *path,
	struct sbuf *sb, struct conf *cconf)
{
	int ret=-1;
	char *delpath=NULL;
	if(!(delpath=prepend_s(deltadir, path)))
	{
		log_out_of_memory(__func__);
		goto end;
	}
	//logp("Generating reverse delta...\n");
/*
	logp("delpath: %s\n", delpath);
	logp("finpath: %s\n", finpath);
	logp("sigpath: %s\n", sigpath);
	logp("oldpath: %s\n", oldpath);
*/
	if(mkpath(&delpath, deltadir))
	{
		logp("could not mkpaths for: %s\n", delpath);
		goto end;
	}
	else if(make_rev_sig(finpath, sigpath,
		sb->burp1->endfile.buf, sb->compression, cconf))
	{
		logp("could not make signature from: %s\n", finpath);
		goto end;
	}
	else if(make_rev_delta(oldpath, sigpath,
		delpath, sb->compression, cconf))
	{
		logp("could not make delta from: %s\n", oldpath);
		goto end;
	}
	else unlink(sigpath);	

	ret=0;
end:
	if(delpath) free(delpath);
	return ret;
}
예제 #18
0
파일: list_server.c 프로젝트: barroque/burp
int check_browsedir(const char *browsedir, char **path, size_t bdlen)
{
	char *cp=NULL;
	char *copy=NULL;
	if(strncmp(browsedir, *path, bdlen))
		return 0;
	if((*path)[bdlen+1]=='\0') return 0;

	/* Lots of messing around related to whether browsedir was '', '/', or
   	   something else. */
	if(*browsedir)
	{
		if(!strcmp(browsedir, "/"))
		{
			if(!(copy=strdup((*path)+bdlen)))
				goto err;
			if((cp=strchr(copy+1, '/'))) *cp='\0';
		}
		else
		{
			if(!(copy=strdup((*path)+bdlen+1)))
				goto err;
			if((cp=strchr(copy, '/'))) *cp='\0';
		}
	}
	else
	{
		if(!(copy=strdup((*path)+bdlen)))
			goto err;
		if(*copy=='/') *(copy+1)='\0';
		// Messing around for Windows.
		else if(strlen(copy)>2 && copy[1]==':' && copy[2]=='/')
			copy[2]='\0';
	}
	free(*path);
	*path=copy;
	return 1;
err:
	if(copy) free(copy);
	log_out_of_memory(__FUNCTION__);
	return -1;
}
예제 #19
0
파일: asyncio.c 프로젝트: barroque/burp
static int parse_readbuf(char *cmd, char **dest, size_t *rlen)
{
	unsigned int s=0;
	char cmdtmp='\0';

	if(readbuflen>=5)
	{
		if((sscanf(readbuf, "%c%04X", &cmdtmp, &s))!=2)
		{
			logp("sscanf of '%s' failed in parse_readbuf\n",
				readbuf);
			truncate_buf(&readbuf, &readbuflen);
			return -1;
		}
	}
	if(readbuflen>=s+5)
	{
		*cmd=cmdtmp;
		if(!(*dest=(char *)malloc(s+1)))
		{
			log_out_of_memory(__FUNCTION__);
			truncate_buf(&readbuf, &readbuflen);
			return -1;
		}
		if(!(memcpy(*dest, readbuf+5, s)))
		{
			logp("memcpy failed in parse_readbuf\n");
			truncate_buf(&readbuf, &readbuflen);
			return -1;
		}
		(*dest)[s]='\0';
		if(!(memmove(readbuf, readbuf+s+5, readbuflen-s-5)))
		{
			logp("memmove failed in parse_readbuf\n");
			truncate_buf(&readbuf, &readbuflen);
			return -1;
		}
		readbuflen-=s+5;
		*rlen=s;
	}
	return 0;
}
예제 #20
0
파일: restore.c 프로젝트: EmisFR/burp
static int make_link(struct asfd *asfd,
	const char *fname, const char *lnk, enum cmd cmd, struct cntr *cntr,
	const char *restore_prefix)
{
	int ret=-1;

#ifdef HAVE_WIN32
	logw(asfd, cntr, "windows seems not to support hardlinks or symlinks\n");
#else
	unlink(fname);
	if(cmd==CMD_HARD_LINK)
	{
		char *flnk=NULL;
		if(!(flnk=prepend_s(restore_prefix, lnk)))
		{
			log_out_of_memory(__func__);
			return -1;
		}
		//printf("%s -> %s\n", fname, flnk);
		ret=link(flnk, fname);
		free_w(&flnk);
	}
	else if(cmd==CMD_SOFT_LINK)
	{
		//printf("%s -> %s\n", fname, lnk);
		ret=symlink(lnk, fname);
	}
	else
	{
		logp("unexpected link command: %c\n", cmd);
		ret=-1;
	}
#endif

	if(ret) logp("could not %slink %s -> %s: %s\n",
		cmd==CMD_HARD_LINK?"hard":"sym",
		fname, lnk, strerror(errno));

	return ret;
}
예제 #21
0
파일: bedup.c 프로젝트: pkdevbox/burp
static int looks_like_protocol1(const char *basedir)
{
	int ret=-1;
	char *tmp=NULL;
	struct stat statp;
	if(!(tmp=prepend_s(basedir, "current")))
	{
		log_out_of_memory(__func__);
		goto end;
	}
	// If there is a 'current' symlink here, we think it looks like a
	// protocol 1 backup.
	if(!lstat(tmp, &statp) && S_ISLNK(statp.st_mode))
	{
		ret=1;
		goto end;
	}
	ret=0;
end:
	free_w(&tmp);
	return ret;
}
예제 #22
0
파일: bedup.c 프로젝트: kaptk2/burp
/* Make it atomic by linking to a temporary file, then moving it into place. */
static int do_hardlink(struct file *o, struct file *n, const char *ext)
{
	int ret=-1;
	char *tmppath=NULL;
	if(!(tmppath=prepend(o->path, ext, "")))
	{
		log_out_of_memory(__func__);
		goto end;
	}
	if(link(n->path, tmppath))
	{
		logp("Could not hardlink %s to %s: %s\n", tmppath, n->path,
			strerror(errno));
		goto end;
	}
	if((ret=do_rename(tmppath, o->path)))
		goto end;
	ret=0;
end:
	free_w(&tmppath);
	return ret;
}
예제 #23
0
static int gen_rev_delta(const char *sigpath, const char *deltadir, const char *oldpath, const char *finpath, const char *path, const char *endfile, int compression, struct cntr *cntr, struct config *cconf)
{
	int ret=0;
	char *delpath=NULL;
	if(!(delpath=prepend_s(deltadir, path, strlen(path))))
	{
		log_out_of_memory(__FUNCTION__);
		ret=-1;
	}
	//logp("Generating reverse delta...\n");
/*
	logp("delpath: %s\n", delpath);
	logp("finpath: %s\n", finpath);
	logp("sigpath: %s\n", sigpath);
	logp("oldpath: %s\n", oldpath);
*/
	if(mkpath(&delpath, deltadir))
	{
		logp("could not mkpaths for: %s\n", delpath);
		ret=-1;
	}
	else if(make_rev_sig(finpath, sigpath,
		endfile, compression, cntr))
	{
		logp("could not make signature from: %s\n", finpath);
		ret=-1;
	}
	else if(make_rev_delta(oldpath, sigpath, delpath,
		compression, cntr, cconf))
	{
		logp("could not make delta from: %s\n", oldpath);
		ret=-1;
	}
	else unlink(sigpath);	
	if(delpath) free(delpath);
	return ret;
}
예제 #24
0
파일: counter.c 프로젝트: barroque/burp
int str_to_counters(const char *str, char **client, char *status, char *phase, char **path, struct cntr *p1cntr, struct cntr *cntr, char ***backups)
{
	int t=0;
	char *tok=NULL;
	char *copy=NULL;

	reset_filecounter(p1cntr, 0);
	reset_filecounter(cntr, 0);

	if(!(copy=strdup(str)))
	{
		log_out_of_memory(__FUNCTION__);
		return -1;
	}

	if((tok=strtok(copy, "\t\n")))
	{
		char *counter_version=NULL;
		if(client && !(*client=strdup(tok)))
		{
			log_out_of_memory(__FUNCTION__);
			return -1;
		}
		if(!(counter_version=strtok(NULL, "\t\n")))
		{
			free(copy);
			return 0;
		}
		// First token after the client name is the version of
		// the counter parser thing, which now has to be noted
		// because counters might be passed to the client instead
		// of just the server status monitor.
		if(*counter_version==COUNTER_VERSION_2
		  || *counter_version==COUNTER_VERSION_1) // old version
		{
		  while(1)
		  {
			int x=1;
			t++;
			if(!(tok=strtok(NULL, "\t\n")))
				break;
			if     (t==x++) { if(status) *status=*tok; }
			else if(t==x++)
			{
				if(status && (*status==STATUS_IDLE
				  || *status==STATUS_SERVER_CRASHED
				  || *status==STATUS_CLIENT_CRASHED))
				{
					int b=0;
					if(backups)
					{
						// Build a list of backups.
					  do
					  {
						if(add_to_backup_list(backups,
								&b, tok))
						{
							free(copy);
							return -1;
						}
					  } while((tok=strtok(NULL, "\t\n")));
					}
				}
				else
				{
					if(phase) *phase=*tok;
				}
			}
			else if(t==x++) { extract_ul(tok,
						&(cntr->total),
						&(cntr->total_changed),
						&(cntr->total_same),
						&(cntr->total_deleted),
						&(p1cntr->total)); }
			else if(t==x++) { extract_ul(tok,
						&(cntr->file),
						&(cntr->file_changed),
						&(cntr->file_same),
						&(cntr->file_deleted),
						&(p1cntr->file)); }
			else if(t==x++) { extract_ul(tok,
						&(cntr->enc),
						&(cntr->enc_changed),
						&(cntr->enc_same),
						&(cntr->enc_deleted),
						&(p1cntr->enc)); }
			else if(t==x++) { extract_ul(tok,
						&(cntr->meta),
						&(cntr->meta_changed),
						&(cntr->meta_same),
						&(cntr->meta_deleted),
						&(p1cntr->meta)); }
			else if(t==x++) { extract_ul(tok,
						&(cntr->encmeta),
						&(cntr->encmeta_changed),
						&(cntr->encmeta_same),
						&(cntr->encmeta_deleted),
						&(p1cntr->encmeta)); }
			else if(t==x++) { extract_ul(tok,
						&(cntr->dir),
						&(cntr->dir_changed),
						&(cntr->dir_same),
						&(cntr->dir_deleted),
						&(p1cntr->dir)); }
			else if(t==x++) { extract_ul(tok,
						&(cntr->slink),
						&(cntr->slink_changed),
						&(cntr->slink_same),
						&(cntr->slink_deleted),
						&(p1cntr->slink)); }
			else if(t==x++) { extract_ul(tok,
						&(cntr->hlink),
						&(cntr->hlink_changed),
						&(cntr->hlink_same),
						&(cntr->hlink_deleted),
						&(p1cntr->hlink)); }
			else if(t==x++) { extract_ul(tok,
						&(cntr->special),
						&(cntr->special_changed),
						&(cntr->special_same),
						&(cntr->special_deleted),
						&(p1cntr->special)); }
			else if(*counter_version==COUNTER_VERSION_2
			  && t==x++) { extract_ul(tok,
						&(cntr->vss),
						&(cntr->vss_changed),
						&(cntr->vss_same),
						&(cntr->vss_deleted),
						&(p1cntr->vss)); }
			else if(*counter_version==COUNTER_VERSION_2
			  && t==x++) { extract_ul(tok,
						&(cntr->encvss),
						&(cntr->encvss_changed),
						&(cntr->encvss_same),
						&(cntr->encvss_deleted),
						&(p1cntr->encvss)); }
			else if(*counter_version==COUNTER_VERSION_2
			  && t==x++) { extract_ul(tok,
						&(cntr->vss_t),
						&(cntr->vss_t_changed),
						&(cntr->vss_t_same),
						&(cntr->vss_t_deleted),
						&(p1cntr->vss_t)); }
			else if(*counter_version==COUNTER_VERSION_2
			  && t==x++) { extract_ul(tok,
						&(cntr->encvss_t),
						&(cntr->encvss_t_changed),
						&(cntr->encvss_t_same),
						&(cntr->encvss_t_deleted),
						&(p1cntr->encvss_t)); }
			else if(t==x++) { extract_ul(tok,
						&(cntr->gtotal),
						&(cntr->gtotal_changed),
						&(cntr->gtotal_same),
						&(cntr->gtotal_deleted),
						&(p1cntr->gtotal)); }
			else if(t==x++) { cntr->warning=
						strtoull(tok, NULL, 10); }
			else if(t==x++) { p1cntr->byte=
						strtoull(tok, NULL, 10); }
			else if(t==x++) { cntr->byte=
						strtoull(tok, NULL, 10); }
			else if(t==x++) { cntr->recvbyte=
						strtoull(tok, NULL, 10); }
			else if(t==x++) { cntr->sentbyte=
						strtoull(tok, NULL, 10); }
			else if(t==x++) { p1cntr->start=atol(tok); }
			else if(t==x++) { if(path && !(*path=strdup(tok)))
			  { log_out_of_memory(__FUNCTION__); return -1; } }
		  }
		}
	}

	free(copy);
        return 0;
}
예제 #25
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;
}
예제 #26
0
파일: prog.c 프로젝트: jkniiv/burp
int main (int argc, char *argv[])
{
    int ret=1;
    int option=0;
    int daemon=1;
    int forking=1;
    int strip=0;
    struct lock *lock=NULL;
    struct conf *conf=NULL;
    int forceoverwrite=0;
    enum action act=ACTION_LIST;
    const char *backup=NULL;
    const char *restoreprefix=NULL;
    const char *regex=NULL;
    const char *browsefile=NULL;
    const char *browsedir=NULL;
    const char *conffile=get_conf_path();
    const char *orig_client=NULL;
    // The orig_client is the original client that the normal client
    // would like to restore from.
#ifndef HAVE_WIN32
    const char *sclient=NULL; // Status monitor client to view.
    int generate_ca_only=0;
#endif
    int vss_restore=1;
    int json=0;

    init_log(argv[0]);

    while((option=getopt(argc, argv, "a:b:c:C:d:ghfFil:nr:s:vxjz:?"))!=-1)
    {
        switch(option)
        {
        case 'a':
            if(parse_action(&act, optarg)) goto end;
            break;
        case 'b':
            backup=optarg;
            break;
        case 'c':
            conffile=optarg;
            break;
        case 'C':
            orig_client=optarg;
#ifndef HAVE_WIN32
            sclient=optarg;
#endif
            break;
        case 'd':
            restoreprefix=optarg; // for restores
            browsedir=optarg; // for lists
            break;
        case 'f':
            forceoverwrite=1;
            break;
        case 'F':
            daemon=0;
            break;
        case 'g':
#ifndef HAVE_WIN32
            generate_ca_only=1;
#endif
            break;
        case 'i':
            cmd_print_all();
            ret=0;
            goto end;
        case 'l':
            logp("-l <logfile> option obsoleted\n");
            break;
        case 'n':
            forking=0;
            break;
        case 'r':
            regex=optarg;
            break;
        case 's':
            strip=atoi(optarg);
            break;
        case 'v':
            printf("%s-%s\n", progname(), VERSION);
            ret=0;
            goto end;
        case 'x':
            vss_restore=0;
            break;
        case 'j':
            json=1;
            break;
        case 'z':
            browsefile=optarg;
            break;
        case 'h':
        case '?':
        default:
            usage();
            goto end;
        }
    }
    if(optind<argc)
    {
        usage();
        goto end;
    }

    if(!(conf=conf_alloc()))
        goto end;

    if(reload(conf, conffile,
              1 /* first time */,
              0 /* no oldmax_children setting */,
              0 /* no oldmax_status_children setting */,
              json)) goto end;

    if((act==ACTION_RESTORE || act==ACTION_VERIFY) && !backup)
    {
        logp("No backup specified. Using the most recent.\n");
        backup="0";
    }

    if(act==ACTION_DELETE && !backup)
    {
        logp("No backup specified for deletion.\n");
        goto end;
    }

    if(conf->mode==MODE_CLIENT)
    {
        if(orig_client && *orig_client)
        {
            if(!(conf->orig_client=strdup(orig_client)))
            {
                log_out_of_memory(__func__);
                goto end;
            }
        }
    }

    if(conf->mode==MODE_SERVER
            && (act==ACTION_STATUS
                || act==ACTION_STATUS_SNAPSHOT
                || act==ACTION_CHAMP_CHOOSER))
    {
        // These server modes need to run without getting the lock.
    }
    else
    {
        if(!(lock=lock_alloc_and_init(conf->lockfile)))
            goto end;
        lock_get(lock);
        switch(lock->status)
        {
        case GET_LOCK_GOT:
            break;
        case GET_LOCK_NOT_GOT:
            logp("Could not get lockfile.\n");
            logp("Another process is probably running,\n");
            goto end;
        case GET_LOCK_ERROR:
        default:
            logp("Could not get lockfile.\n");
            logp("Maybe you do not have permissions to write to %s.\n", conf->lockfile);
            goto end;
        }
    }

    conf->overwrite=forceoverwrite;
    conf->strip=strip;
    conf->forking=forking;
    conf->daemon=daemon;
    if(replace_conf_str(backup, &conf->backup)
            || replace_conf_str(restoreprefix, &conf->restoreprefix)
            || replace_conf_str(regex, &conf->regex)
            || replace_conf_str(browsefile, &conf->browsefile)
            || replace_conf_str(browsedir, &conf->browsedir))
        goto end;
    if(conf->mode==MODE_SERVER)
    {
#ifdef HAVE_WIN32
        logp("Sorry, server mode is not implemented for Windows.\n");
#else
        if(act==ACTION_STATUS || act==ACTION_STATUS_SNAPSHOT)
        {
            // We are running on the server machine, being a client
            // of the burp server, getting status information.
            ret=status_client_ncurses(conf, act, sclient);
        }
        else if(act==ACTION_CHAMP_CHOOSER)
        {
            // We are running on the server machine, wanting to
            // be a standalone champion chooser process.
            if(!sclient || !*sclient)
            {
                logp("No client name specified for standalone champion chooser process.\n");
                logp("Try using the '-C' option.\n");
                ret=1;
            }
            else
                ret=champ_chooser_server_standalone(conf,
                                                    sclient);
        }
        else
            ret=server(conf, conffile, lock, generate_ca_only);
#endif
    }
    else
    {
        logp("before client\n");
        ret=client(conf, act, vss_restore, json);
        logp("after client\n");
    }

end:
    lock_release(lock);
    lock_free(&lock);
    conf_free(conf);
    return ret;
}
예제 #27
0
파일: fsops.c 프로젝트: pkdevbox/burp
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
		  || !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)>0)
		{
			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;
}
예제 #28
0
파일: bedup.c 프로젝트: kaptk2/burp
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;
			// 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(
				get_string(globalcs[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;
}
예제 #29
0
static int jiggle(struct sdirs *sdirs, struct fdirs *fdirs, struct sbuf *sb,
	int hardlinked_current, const char *deltabdir, const char *deltafdir,
	const char *sigpath, FILE **delfp, struct conf *cconf)
{
	int ret=-1;
	struct stat statp;
	char *oldpath=NULL;
	char *newpath=NULL;
	char *finpath=NULL;
	char *deltafpath=NULL;
	const char *datapth=sb->burp1->datapth.buf;

	// If the previous backup was a hardlinked_archive, there will not be
	// a currentdup directory - just directly use the file in the previous
	// backup.
	if(!(oldpath=prepend_s(hardlinked_current?
		sdirs->currentdata:fdirs->currentdupdata, datapth))
	  || !(newpath=prepend_s(fdirs->datadirtmp, datapth))
	  || !(finpath=prepend_s(fdirs->datadir, datapth))
	  || !(deltafpath=prepend_s(deltafdir, datapth)))
		goto end;

	if(!lstat(finpath, &statp) && S_ISREG(statp.st_mode))
	{
		// Looks like an interrupted jiggle
		// did this file already.
		static int donemsg=0;
		if(!lstat(deltafpath, &statp) && S_ISREG(statp.st_mode))
		{
			logp("deleting unneeded forward delta: %s\n",
				deltafpath);
			unlink(deltafpath);
		}
		if(!donemsg)
		{
			logp("skipping already present file: %s\n", finpath);
			logp("to save log space, skips of other already present files will not be logged\n");
			donemsg++;
		}
	}
	else if(mkpath(&finpath, fdirs->datadir))
	{
		logp("could not create path for: %s\n", finpath);
		goto end;
	}
	else if(mkpath(&newpath, fdirs->datadirtmp))
	{
		logp("could not create path for: %s\n", newpath);
		goto end;
	}
	else if(!lstat(deltafpath, &statp) && S_ISREG(statp.st_mode))
	{
		int lrs;
		char *infpath=NULL;

		// Got a forward patch to do.
		// First, need to gunzip the old file,
		// otherwise the librsync patch will take
		// forever, because it will be doing seeks
		// all over the place, and gzseeks are slow.
	  	if(!(infpath=prepend_s(deltafdir, "inflate")))
		{
			log_out_of_memory(__func__);
			goto end;
		}

		//logp("Fixing up: %s\n", datapth);
		if(inflate_or_link_oldfile(oldpath, infpath,
			sb->compression, cconf))
		{
			logp("error when inflating old file: %s\n", oldpath);
			free(infpath);
			goto end;
		}

		if((lrs=do_patch(NULL, infpath, deltafpath, newpath,
			cconf->compression,
			sb->compression /* from the manifest */, cconf)))
		{
			logp("WARNING: librsync error when patching %s: %d\n",
				oldpath, lrs);
			cntr_add(cconf->cntr, CMD_WARNING, 1);
			// Try to carry on with the rest of the backup
			// regardless.
			//ret=-1;
			// Remove anything that got written.
			unlink(newpath);
			unlink(infpath);
			free(infpath);

			// First, note that we want to remove this entry from
			// the manifest.
			if(!*delfp
			  && !(*delfp=open_file(fdirs->deletionsfile, "ab")))
			{
				// Could not mark this file as deleted. Fatal.
				goto end;
			}
			if(sbufl_to_manifest(sb, *delfp, NULL))
				goto end;
			if(fflush(*delfp))
			{
				logp("error fflushing deletions file in %s: %s\n", __func__, strerror(errno));
				goto end;
			}
	
			ret=0;
			goto end;
		}

		// Get rid of the inflated old file.
		unlink(infpath);
		free(infpath);

		// Need to generate a reverse diff, unless we are keeping a
		// hardlinked archive.
		if(!hardlinked_current)
		{
			if(gen_rev_delta(sigpath, deltabdir,
				oldpath, newpath, datapth, sb, cconf))
					goto end;
		}

		// Power interruptions should be recoverable. If it happens
		// before this point, the data jiggle for this file has to be
		// done again.
		// Once finpath is in place, no more jiggle is required.

		// Use the fresh new file.
		// Rename race condition is of no consequence, because finpath
		// will just get recreated automatically.
		if(do_rename(newpath, finpath))
			goto end;

		// Remove the forward delta, as it is no longer needed. There
		// is a reverse diff and the finished finished file is in place.
		//logp("Deleting delta.forward...\n");
		unlink(deltafpath);

		// Remove the old file. If a power cut happens just before
		// this, the old file will hang around forever.
		// FIX THIS: maybe put in something to detect this.
		// ie, both a reverse delta and the old file exist.
		if(!hardlinked_current)
		{
			//logp("Deleting oldpath...\n");
			unlink(oldpath);
		}
	}
	else if(!lstat(newpath, &statp) && S_ISREG(statp.st_mode))
	{
		// Use the fresh new file.
		// This needs to happen after checking
		// for the forward delta, because the
		// patching stuff writes to newpath.

		// Rename race condition is of no consequence, because finpath
		// will just get recreated automatically.

		//logp("Using newly received file\n");
		if(do_rename(newpath, finpath))
			goto end;
	}
	else if(!lstat(oldpath, &statp) && S_ISREG(statp.st_mode))
	{
		// Use the old unchanged file.
		// Hard link it first.
		//logp("Hard linking to old file: %s\n", datapth);
		if(do_link(oldpath, finpath, &statp, cconf,
		  0 /* do not overwrite finpath (should never need to) */))
			goto end;
		else
		{
			// If we are not keeping a hardlinked
			// archive, delete the old link.
			if(!hardlinked_current)
			{
				//logp("Unlinking old file: %s\n", oldpath);
				unlink(oldpath);
			}
		}
	}
	else
	{
		logp("could not find: %s\n", oldpath);
		goto end;
	}

	ret=0;
end:
	free_w(&oldpath);
	free_w(&newpath);
	free_w(&finpath);
	free_w(&deltafpath);
	return ret;
}
예제 #30
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(struct sdirs *sdirs, struct fdirs *fdirs,
	int hardlinked_current, struct conf *cconf, unsigned long bno)
{
	int ars=0;
	int ret=-1;
	char *datapth=NULL;
	char *tmpman=NULL;
	struct stat statp;

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

	FILE *delfp=NULL;

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

	if(!(tmpman=get_tmp_filename(fdirs->manifest)))
		goto end;
	if(lstat(fdirs->manifest, &statp))
	{
		// Manifest does not exist - maybe the server was killed before
		// it could be renamed.
		logp("%s did not exist - trying %s\n", fdirs->manifest, tmpman);
		// Rename race condition is of no consequence, because manifest
		// already does not exist.
		do_rename(tmpman, fdirs->manifest);
	}
	if(!(zp=gzopen_file(fdirs->manifest, "rb")))
		goto end;

	if(!(deltabdir=prepend_s(fdirs->currentdup, "deltas.reverse"))
	  || !(deltafdir=prepend_s(sdirs->finishing, "deltas.forward"))
	  || !(sigpath=prepend_s(fdirs->currentdup, "sig.tmp"))
	  || !(sb=sbuf_alloc(cconf)))
	{
		log_out_of_memory(__func__);
		goto end;
	}

	mkdir(fdirs->datadir, 0777);

	while(!(ars=sbufl_fill(sb, NULL, NULL, zp, cconf->cntr)))
	{
		if(sb->burp1->datapth.buf)
		{
			if(write_status(STATUS_SHUFFLING,
				sb->burp1->datapth.buf, cconf)) goto end;

			if((ret=jiggle(sdirs, fdirs, sb, hardlinked_current,
				deltabdir, deltafdir,
				sigpath, &delfp, cconf))) goto end;
		}
		sbuf_free_content(sb);
	}
	if(ars<0) goto end;

	if(close_fp(&delfp))
	{
		logp("error closing %s in atomic_data_jiggle\n",
			fdirs->deletionsfile);
		goto end;
	}

	if(maybe_delete_files_from_manifest(tmpman, fdirs, cconf))
		goto end;

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

end:
	gzclose_fp(&zp);
	close_fp(&delfp);
	sbuf_free(&sb);
	free_w(&deltabdir);
	free_w(&deltafdir);
	free_w(&sigpath);
	free_w(&datapth);
	free_w(&tmpman);
	return ret;
}