Exemple #1
0
int backup_phase2_client_burp1(struct asfd *asfd, struct conf *conf, int resume)
{
	int ret=0;

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

	ret=do_backup_phase2_client(asfd, conf, resume);

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

	if(ret) logp("Error in phase 2\n");
	logp("Phase 2 end (send file data)\n");

	return ret;
}
Exemple #2
0
static int actual_restore(struct asfd *asfd, struct bu *bu,
	const char *manifest, regex_t *regex, int srestore, enum action act,
	struct sdirs *sdirs, enum cntr_status cntr_status, struct conf **cconfs)
{
        int ret=-1;
	int do_restore_stream=1;
        // For out-of-sequence directory restoring so that the
        // timestamps come out right:
        struct slist *slist=NULL;

	if(linkhash_init()
          || !(slist=slist_alloc()))
                goto end;

	if(get_protocol(cconfs)==PROTO_2)
	{
		switch(maybe_restore_spool(asfd, manifest, sdirs, bu,
			srestore, regex, cconfs, slist, act, cntr_status))
		{
			case 1: do_restore_stream=0; break;
			case 0: do_restore_stream=1; break;
			default: goto end; // Error;
		}
	}
	if(do_restore_stream && restore_stream(asfd, sdirs, slist,
		bu, manifest, regex,
		srestore, cconfs, act, cntr_status))
			goto end;

	if(restore_remaining_dirs(asfd, bu, slist,
		act, sdirs, cntr_status, cconfs)) goto end;

        // Restore has nearly completed OK.

        ret=restore_end(asfd, cconfs);

	cntr_print(get_cntr(cconfs), act);
	cntr_stats_to_file(get_cntr(cconfs), bu->path, act, cconfs);
end:
        slist_free(&slist);
	linkhash_free();
        return ret;
}
Exemple #3
0
static int do_backup_server(struct async *as, struct sdirs *sdirs,
	struct conf **cconfs, const char *incexc, int resume)
{
	int ret=0;
	int do_phase2=1;
	struct asfd *asfd=as->asfd;
	enum protocol protocol=get_protocol(cconfs);
	struct cntr *cntr=get_cntr(cconfs);

	logp("in do_backup_server\n");

	log_rshash(cconfs);

	if(resume)
	{
		if(sdirs_get_real_working_from_symlink(sdirs)
		  || sdirs_get_real_manifest(sdirs, protocol)
		  || open_log(asfd, sdirs, cconfs))
			goto error;
	}
	else
	{
		// Not resuming - need to set everything up fresh.
		if(sdirs_create_real_working(sdirs,
			get_string(cconfs[OPT_TIMESTAMP_FORMAT]))
		  || sdirs_get_real_manifest(sdirs, protocol)
		  || open_log(asfd, sdirs, cconfs))
			goto error;

		if(write_incexc(sdirs->rworking, incexc))
		{
			logp("unable to write incexc\n");
			goto error;
		}

		if(backup_phase1_server(as, sdirs, cconfs))
		{
			logp("error in phase 1\n");
			goto error;
		}
	}

	if(resume)
	{
		struct stat statp;
		if(lstat(sdirs->phase1data, &statp)
		  && !lstat(sdirs->changed, &statp)
		  && !lstat(sdirs->unchanged, &statp))
		{
			// In this condition, it looks like there was an
			// interruption during phase3. Skip phase2.
			do_phase2=0;
		}
	}

	if(do_phase2)
	{
		if(backup_phase2_server(as, sdirs, incexc, resume, cconfs))
		{
			logp("error in backup phase 2\n");
			goto error;
		}

		asfd->write_str(asfd, CMD_GEN, "okbackupend");
	}

	// Close the connection with the client, the rest of the job we can do
	// by ourselves.
	logp("Backup ending - disconnect from client.\n");
	if(asfd_flush_asio(asfd)) goto end;
	as->asfd_remove(as, asfd);
	asfd_close(asfd);

	if(backup_phase3_server(sdirs, cconfs))
	{
		logp("error in backup phase 3\n");
		goto error;
	}

	if(do_rename(sdirs->working, sdirs->finishing))
		goto error;

	if(backup_phase4_server(sdirs, cconfs))
	{
		logp("error in backup phase 4\n");
		goto error;
	}

	cntr_print(cntr, ACTION_BACKUP, asfd);
	cntr_stats_to_file(cntr, sdirs->rworking, ACTION_BACKUP);

	if(protocol==PROTO_2)
	{
		// Regenerate dindex before the symlink is renamed, so that the
		// champ chooser cleanup does not try to remove data files
		// whilst the dindex regeneration is happening.
		if(regenerate_client_dindex(sdirs))
			goto error;
	}

	// Move the symlink to indicate that we are now in the end phase. The
	// rename() race condition is automatically recoverable here.
	if(do_rename(sdirs->finishing, sdirs->current))
		goto error;

	logp("Backup completed.\n");
	log_fzp_set(NULL, cconfs);
	compress_filename(sdirs->rworking,
		"log", "log.gz", get_int(cconfs[OPT_COMPRESSION]));

	goto end;
error:
	ret=-1;
end:

	log_fzp_set(NULL, cconfs);
	return ret;
}
Exemple #4
0
// Return 0 for OK, -1 for error, 1 for timer conditions not met.
int do_backup_client(struct asfd *asfd, struct conf *conf, enum action action,
	long name_max, int resume)
{
	int ret=0;

	if(action==ACTION_ESTIMATE)
		logp("do estimate client\n");
	else
		logp("do backup client\n");

#if defined(HAVE_WIN32)
	win32_enable_backup_privileges();
#if defined(WIN32_VSS)
	if((ret=win32_start_vss(conf))) return ret;
#endif
	if(action==ACTION_BACKUP_TIMED)
	{
		// Run timed backups with lower priority.
		// I found that this has to be done after the snapshot, or the
		// snapshot never finishes. At least, I waited 30 minutes with
		// nothing happening.
#if defined(B_VSS_XP) || defined(B_VSS_W2K3)
		if(SetThreadPriority(GetCurrentThread(),
					THREAD_PRIORITY_LOWEST))
			logp("Set thread_priority_lowest\n");
		else
			logp("Failed to set thread_priority_lowest\n");
#else
		if(SetThreadPriority(GetCurrentThread(),
					THREAD_MODE_BACKGROUND_BEGIN))
			logp("Set thread_mode_background_begin\n");
		else
			logp("Failed to set thread_mode_background_begin\n");
#endif
	}
#endif

	// Scan the file system and send the results to the server.
	// Skip phase1 if the server wanted to resume.
	if(!ret && !resume)
		ret=backup_phase1_client(asfd, conf, name_max,
			action==ACTION_ESTIMATE);

	if(action!=ACTION_ESTIMATE && !ret)
	{
		// Now, the server will be telling us what data we need to
		// send.
		if(conf->protocol==PROTO_BURP1)
			ret=backup_phase2_client_burp1(asfd, conf, resume);
		else
			ret=backup_phase2_client(asfd, conf, resume);
	}

	if(action==ACTION_ESTIMATE) cntr_print(conf->cntr, ACTION_ESTIMATE);

#if defined(HAVE_WIN32)
	if(action==ACTION_BACKUP_TIMED)
	{
		if(SetThreadPriority(GetCurrentThread(),
					THREAD_MODE_BACKGROUND_END))
			logp("Set thread_mode_background_end\n");
		else
			logp("Failed to set thread_mode_background_end\n");
	}
#if defined(WIN32_VSS)
	win32_stop_vss();
#endif
#endif

	return ret;
}
Exemple #5
0
// Return 0 for OK, -1 for error.
int do_backup_client(struct asfd *asfd, struct conf **confs, enum action action,
	int resume)
{
	int ret=-1;
	int breaking=get_int(confs[OPT_BREAKPOINT]);

	if(action==ACTION_ESTIMATE)
		logp("do estimate client\n");
	else
	{
		logp("do backup client\n");
		if(get_protocol(confs)==PROTO_1)
			logp("Using librsync hash %s\n",
			  rshash_to_str(get_e_rshash(confs[OPT_RSHASH])));
	}

#ifdef HAVE_WIN32
	win32_enable_backup_privileges();
#ifdef WIN32_VSS
	if(win32_start_vss(confs)) return ret;
#endif
	if(action==ACTION_BACKUP_TIMED) set_low_priority();
#endif

	// Scan the file system and send the results to the server.
	// Skip phase1 if the server wanted to resume.
	if(!resume)
	{
		if(breaking==1)
		{
			breakpoint(breaking, __func__);
			goto end;
		}
		if(backup_phase1_client(asfd, confs, action==ACTION_ESTIMATE))
			goto end;
	}

	switch(action)
	{
		case ACTION_DIFF:
		case ACTION_DIFF_LONG:
			ret=1;
			goto end;
		case ACTION_ESTIMATE:
			cntr_print(get_cntr(confs), ACTION_ESTIMATE);
			break;
		default:
			// Now, the server will be telling us what data we need
			// to send.
			if(breaking==2)
			{
				breakpoint(breaking, __func__);
				goto end;
			}

			if(get_protocol(confs)==PROTO_1)
				ret=backup_phase2_client_protocol1(asfd,
					confs, resume);
			else
				ret=backup_phase2_client_protocol2(asfd,
					confs, resume);
			if(ret) goto end;
			break;
	}

	ret=0;
end:
#if defined(HAVE_WIN32)
	if(action==ACTION_BACKUP_TIMED) unset_low_priority();
#if defined(WIN32_VSS)
	win32_stop_vss();
#endif
#endif
	return ret;
}
Exemple #6
0
int backup_phase2_client_protocol2(struct asfd *asfd,
	struct conf **confs, int resume)
{
	int ret=-1;
	uint8_t end_flags=0;
	struct slist *slist=NULL;
	struct iobuf *rbuf=NULL;
	struct iobuf *wbuf=NULL;
	struct cntr *cntr=NULL;

	if(confs) cntr=get_cntr(confs);

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

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

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

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

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

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

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

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

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

		}
	}

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

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

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

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

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

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

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

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

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

        switch(sb->path.cmd)
        {
        case CMD_DIRECTORY:
        case CMD_FILE:
        case CMD_ENC_FILE:
        case CMD_SOFT_LINK:
        case CMD_HARD_LINK:
        case CMD_SPECIAL:
        case CMD_METADATA:
        case CMD_ENC_METADATA:
        case CMD_VSS:
        case CMD_ENC_VSS:
        case CMD_VSS_T:
        case CMD_ENC_VSS_T:
        case CMD_EFS_FILE:
            if(conf->strip)
            {
                int s;
                s=strip_path_components(asfd, sb,
                                        &(sb->path.buf), conf);
                if(s<0) goto end; // error
                else if(s==0)
                {
                    // Too many components stripped
                    // - carry on.
                    continue;
                }
                // It is OK, sb->path is now stripped.
            }
            if(!(fullpath=prepend_s(conf->restoreprefix,
                                    sb->path.buf)))
            {
                log_and_send_oom(asfd, __func__);
                goto end;
            }
            if(act==ACTION_RESTORE)
            {
                strip_invalid_characters(&fullpath);
                if(!overwrite_ok(sb, conf, &bfd, fullpath))
                {
                    char msg[512]="";
                    // Something exists at that path.
                    snprintf(msg, sizeof(msg),
                             "Path exists: %s", fullpath);
                    if(restore_interrupt(asfd, sb, msg, conf))
                        goto end;
                    else
                    {
                        if(fullpath) free(fullpath);
                        continue;
                    }
                }
            }
            break;
        default:
            break;
        }

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

        if(fullpath) free(fullpath);
    }

    ret=0;
end:
    sbuf_free(sb);

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

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

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

    return ret;
}
Exemple #8
0
int do_restore_client(struct asfd *asfd,
	struct conf **confs, enum action act, int vss_restore)
{
	int ret=-1;
	char msg[512]="";
	struct sbuf *sb=NULL;
	struct blk *blk=NULL;
	BFILE *bfd=NULL;
	char *fullpath=NULL;
	char *style=NULL;
	char *datpath=NULL;
	struct cntr *cntr=get_cntr(confs);
	enum protocol protocol=get_protocol(confs);
	int strip=get_int(confs[OPT_STRIP]);
	int overwrite=get_int(confs[OPT_OVERWRITE]);
	const char *backup=get_string(confs[OPT_BACKUP]);
	const char *regex=get_string(confs[OPT_REGEX]);
	const char *restore_prefix=get_string(confs[OPT_RESTOREPREFIX]);
	const char *encryption_password=get_string(confs[OPT_ENCRYPTION_PASSWORD]);

	if(!(bfd=bfile_alloc())) goto end;

	bfile_init(bfd, 0, cntr);

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

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

	if(!(style=get_restore_style(asfd, confs)))
		goto error;
	if(!strcmp(style, RESTORE_SPOOL))
	{
		if(restore_spool(asfd, confs, &datpath))
			goto error;
	}
	else
		logp("Streaming restore direct\n");

	logf("\n");

	if(get_int(confs[OPT_SEND_CLIENT_CNTR]) && cntr_recv(asfd, confs))
		goto error;

	if(!(sb=sbuf_alloc(protocol))
	  || (protocol==PROTO_2 && !(blk=blk_alloc())))
	{
		log_and_send_oom(asfd, __func__);
		goto error;
	}

	while(1)
	{
		sbuf_free_content(sb);
		if(protocol==PROTO_1)
			sb->flags |= SBUF_CLIENT_RESTORE_HACK;

		switch(sbuf_fill_from_net(sb, asfd, blk, datpath, cntr))
		{
			case 0: break;
			case 1: if(asfd->write_str(asfd, CMD_GEN,
				"restoreend ok")) goto error;
				goto end; // It was OK.
			default:
			case -1: goto error;
		}

		if(protocol==PROTO_2)
		{
			if(blk->data)
			{
				int wret=0;
				if(act==ACTION_VERIFY)
					cntr_add(cntr, CMD_DATA, 1);
				else
					wret=write_data(asfd, bfd, blk);
				if(!datpath) blk_free_content(blk);
				blk->data=NULL;
				if(wret) goto error;
				continue;
			}
			else if(sb->endfile.buf)
			{
				continue;
			}
		}

		switch(sb->path.cmd)
		{
			case CMD_DIRECTORY:
			case CMD_FILE:
			case CMD_ENC_FILE:
			case CMD_SOFT_LINK:
			case CMD_HARD_LINK:
			case CMD_SPECIAL:
			case CMD_METADATA:
			case CMD_ENC_METADATA:
			case CMD_VSS:
			case CMD_ENC_VSS:
			case CMD_VSS_T:
			case CMD_ENC_VSS_T:
			case CMD_EFS_FILE:
				if(strip)
				{
					int s;
					s=strip_path_components(asfd,
						sb, strip, cntr, protocol);
					if(s<0) goto error;
					if(s==0)
					{
						// Too many components stripped
						// - carry on.
						continue;
					}
					// It is OK, sb.path is now stripped.
				}
				free_w(&fullpath);
				if(!(fullpath=prepend_s(restore_prefix,
					sb->path.buf)))
				{
					log_and_send_oom(asfd, __func__);
					goto error;
				}
				if(act==ACTION_RESTORE)
				{
				  strip_invalid_characters(&fullpath);
				  if(!overwrite_ok(sb, overwrite,
#ifdef HAVE_WIN32
					bfd,
#endif
					fullpath))
				  {
					char msg[512]="";
					// Something exists at that path.
					snprintf(msg, sizeof(msg),
						"Path exists: %s\n", fullpath);
					if(restore_interrupt(asfd,
						sb, msg, cntr, protocol))
							goto error;
					continue;
				  }
				}
				break;
			case CMD_MESSAGE:
			case CMD_WARNING:
				log_recvd(&sb->path, cntr, 1);
				logf("\n");
				continue;
			default:
				break;
		}

		switch(sb->path.cmd)
		{
			// These are the same in both protocol1 and protocol2.
			case CMD_DIRECTORY:
				if(restore_dir(asfd, sb, fullpath, act, cntr,
					protocol))
						goto error;
				continue;
			case CMD_SOFT_LINK:
			case CMD_HARD_LINK:
				if(restore_link(asfd, sb, fullpath, act, cntr,
					protocol, restore_prefix))
						goto error;
				continue;
			case CMD_SPECIAL:
				if(restore_special(asfd, sb,
					fullpath, act, cntr, protocol))
						goto error;
				continue;
			default:
				break;
		}

		if(protocol==PROTO_2)
		{
			if(restore_switch_protocol2(asfd, sb, fullpath, act,
				bfd, vss_restore, cntr))
					goto error;
		}
		else
		{
			if(restore_switch_protocol1(asfd, sb, fullpath, act,
				bfd, vss_restore, cntr, encryption_password))
					goto error;
		}
	}

end:
	ret=0;
error:
	// It is possible for a fd to still be open.
	bfd->close(bfd, asfd);
	bfile_free(&bfd);

	cntr_print_end(cntr);
	cntr_print(cntr, act);

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

	sbuf_free(&sb);
	free_w(&style);
	if(datpath)
	{
		recursive_delete(datpath);
		free_w(&datpath);
	}
	free_w(&fullpath);
	blk_free(&blk);

	return ret;
}
Exemple #9
0
int backup_phase2_client_burp2(struct asfd *asfd, struct conf *conf, int resume)
{
	int ret=-1;
	int sigs_end=0;
	int backup_end=0;
	int requests_end=0;
	int blk_requests_end=0;
	struct win *win=NULL; // Rabin sliding window.
	struct slist *slist=NULL;
	struct blist *blist=NULL;
	struct iobuf *rbuf=NULL;
	struct iobuf *wbuf=NULL;

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

	if(!(slist=slist_alloc())
	  || !(blist=blist_alloc())
	  || !(wbuf=iobuf_alloc())
	  || blks_generate_init(conf)
	  || !(win=win_alloc(&conf->rconf)))
		goto end;
	rbuf=asfd->rbuf;

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

	while(!backup_end)
	{
		if(!wbuf->len)
		{
			get_wbuf_from_data(conf, wbuf, slist, blist,
				blk_requests_end);
			if(!wbuf->len)
			{
				get_wbuf_from_blks(wbuf, slist,
					requests_end, &sigs_end);
			}
		}

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

		if(rbuf->buf && deal_with_read(rbuf, slist, blist,
			conf, &backup_end, &requests_end, &blk_requests_end))
				goto end;

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

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

		}
	}

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

	ret=0;
end:
blk_print_alloc_stats();
//sbuf_print_alloc_stats();
	win_free(win);
	slist_free(&slist);
	blist_free(&blist);
	// Write buffer did not allocate 'buf'.
	wbuf->buf=NULL;
	iobuf_free(&wbuf);

	cntr_print_end(conf->cntr);
	cntr_print(conf->cntr, ACTION_BACKUP);
	if(ret) logp("Error in backup\n");
	logp("End backup\n");

	return ret;
}
Exemple #10
0
int backup_phase4_server(struct sdirs *sdirs, struct conf *cconf)
{
	int ret=-1;
	struct stat statp;
	ssize_t len=0;
	char realcurrent[256]="";
	unsigned long bno=0;
	int hardlinked_current=0;
	char tstmp[64]="";
	int previous_backup=0;
	struct fdirs *fdirs=NULL;

	if((len=readlink(sdirs->current, realcurrent, sizeof(realcurrent)-1))<0)
		len=0;
	realcurrent[len]='\0';

	if(!(fdirs=fdirs_alloc())
	  || fdirs_init(fdirs, sdirs, realcurrent))
		goto end;

	if(set_logfp(fdirs->logpath, cconf))
		goto end;

	logp("Begin phase4 (shuffle files)\n");

	if(write_status(STATUS_SHUFFLING, NULL, cconf))
		goto end;

	if(!lstat(sdirs->current, &statp)) // Had a previous backup.
	{
		previous_backup++;

		if(lstat(fdirs->hlinkedcurrent, &statp))
		{
			hardlinked_current=0;
			logp("Previous backup is not a hardlinked_archive\n");
			logp(" will generate reverse deltas\n");
		}
		else
		{
			hardlinked_current=1;
			logp("Previous backup is a hardlinked_archive\n");
			logp(" will not generate reverse deltas\n");
		}

		// If current was not a hardlinked_archive, need to duplicate
		// it.
		if(!hardlinked_current && lstat(fdirs->currentdup, &statp))
		{
			// Have not duplicated the current backup yet.
			if(!lstat(fdirs->currentduptmp, &statp))
			{
				logp("Removing previous directory: %s\n",
					fdirs->currentduptmp);
				if(recursive_delete(fdirs->currentduptmp,
					NULL, 1 /* del files */))
				{
					logp("Could not delete %s\n",
						fdirs->currentduptmp);
					goto end;
				}
			}
			logp("Duplicating current backup.\n");
			if(recursive_hardlink(sdirs->current,
				fdirs->currentduptmp, cconf)
			// The rename race condition is of no consequence here
			// because currentdup does not exist.
			  || do_rename(fdirs->currentduptmp, fdirs->currentdup))
				goto end;
		}
	}

	if(timestamp_read(fdirs->timestamp, tstmp, sizeof(tstmp)))
	{
		logp("could not read timestamp file: %s\n",
			fdirs->timestamp);
		goto end;
	}
	// Get the backup number.
	bno=strtoul(tstmp, NULL, 10);

	// Determine whether the new backup should be a hardlinked
	// archive or not, from the conf and the backup number...
	if(need_hardlinked_archive(cconf, bno))
	{
		// Create a file to indicate that the previous backup
		// does not have others depending on it.
		FILE *hfp=NULL;
		if(!(hfp=open_file(fdirs->hlinked, "wb"))) goto end;

		// Stick the next backup timestamp in it. It might
		// be useful one day when wondering when the next
		// backup, now deleted, was made.
		fprintf(hfp, "%s\n", tstmp);
		if(close_fp(&hfp))
		{
			logp("error closing hardlinked indication\n");
			goto end;
		}
	}
	else
		unlink(fdirs->hlinked);

	if(atomic_data_jiggle(sdirs, fdirs, hardlinked_current, cconf, bno))
	{
		logp("could not finish up backup.\n");
		goto end;
	}

	if(write_status(STATUS_SHUFFLING, "deleting temporary files", cconf))
		goto end;

	// Remove the temporary data directory, we have now removed
	// everything useful from it.
	recursive_delete(fdirs->datadirtmp, NULL, 1 /* del files */);

	// Clean up the currentdata directory - this is now the 'old'
	// currentdata directory. Any files that were deleted from
	// the client will be left in there, so call recursive_delete
	// with the option that makes it not delete files.
	// This will have the effect of getting rid of unnecessary
	// directories.
	sync(); // try to help CIFS
	recursive_delete(fdirs->currentdupdata, NULL, 0 /* do not del files */);

	// Rename the old current to something that we know to delete.
	if(previous_backup && !hardlinked_current)
	{
		if(deleteme_move(sdirs->client,
			fdirs->fullrealcurrent, realcurrent, cconf)
		// I have tested that potential race conditions on the
		// rename() are automatically recoverable here.
		  || do_rename(fdirs->currentdup, fdirs->fullrealcurrent))
			goto end;
	}

	if(deleteme_maybe_delete(cconf, sdirs->client))
		goto end;

	cntr_stats_to_file(cconf->cntr, sdirs->finishing, ACTION_BACKUP);

	// Rename the finishing symlink so that it becomes the current symlink
	// I have tested that potential race conditions on the
	// rename() are automatically recoverable here.
	if(do_rename(sdirs->finishing, sdirs->current))
		goto end;

	cntr_print(cconf->cntr, ACTION_BACKUP);
	logp("Backup completed.\n");
	logp("End phase4 (shuffle files)\n");
	set_logfp(NULL, cconf); // will close logfp.

	compress_filename(sdirs->current, "log", "log.gz", cconf);

	ret=0;
end:
	fdirs_free(fdirs);
	return ret;
}
Exemple #11
0
int backup_phase4_server(struct sdirs *sdirs, struct conf *cconf)
{
	int ret=-1;
	struct stat statp;
	char *manifest=NULL;
	char *deletionsfile=NULL;
	char *datadir=NULL;
	char *datadirtmp=NULL;
	char *currentdup=NULL;
	char *currentduptmp=NULL;
	char *currentdupdata=NULL;
	char *timestamp=NULL;
	char *fullrealcurrent=NULL;
	char *logpath=NULL;
	char *hlinkedpath=NULL;
	ssize_t len=0;
	char realcurrent[256]="";

	unsigned long bno=0;
	int hardlinked=0;
	char tstmp[64]="";
	int newdup=0;
	int previous_backup=0;

	if((len=readlink(sdirs->current, realcurrent, sizeof(realcurrent)-1))<0)
		len=0;
	realcurrent[len]='\0';

	if(!(datadir=prepend_s(sdirs->finishing, "data"))
	  || !(datadirtmp=prepend_s(sdirs->finishing, "data.tmp"))
	  || !(manifest=prepend_s(sdirs->finishing, "manifest.gz"))
	  || !(deletionsfile=prepend_s(sdirs->finishing, "deletions"))
	  || !(currentdup=prepend_s(sdirs->finishing, "currentdup"))
	  || !(currentduptmp=prepend_s(sdirs->finishing, "currentdup.tmp"))
	  || !(currentdupdata=prepend_s(currentdup, "data"))
	  || !(timestamp=prepend_s(sdirs->finishing, "timestamp"))
	  || !(fullrealcurrent=prepend_s(sdirs->client, realcurrent))
	  || !(logpath=prepend_s(sdirs->finishing, "log"))
	  || !(hlinkedpath=prepend_s(currentdup, "hardlinked")))
		goto end;

	if(set_logfp(logpath, cconf))
		goto end;

	logp("Begin phase4 (shuffle files)\n");

	if(write_status(STATUS_SHUFFLING, NULL, cconf))
		goto end;

	if(!lstat(sdirs->current, &statp)) // Had a previous backup
	{
		previous_backup++;

		if(lstat(currentdup, &statp))
		{
			// Have not duplicated the current backup yet.
			if(!lstat(currentduptmp, &statp))
			{
				logp("Removing previous currentduptmp directory: %s\n", currentduptmp);
				if(recursive_delete(currentduptmp,
					NULL, 1 /* del files */))
				{
					logp("Could not delete %s\n",
						currentduptmp);
					goto end;
				}
			}
			logp("Duplicating current backup.\n");
			if(recursive_hardlink(sdirs->current, currentduptmp, cconf)
			  || do_rename(currentduptmp, currentdup))
				goto end;
			newdup++;
		}

		if(read_timestamp(timestamp, tstmp, sizeof(tstmp)))
		{
			logp("could not read timestamp file: %s\n", timestamp);
			goto end;
		}
		// Get the backup number.
		bno=strtoul(tstmp, NULL, 10);

		if(newdup)
		{
			// When we have just created currentdup, determine
			// hardlinked archive from the conf and the backup
			// number...
			hardlinked=do_hardlinked_archive(cconf, bno);
		}
		else
		{
			// ...if recovering, find out what currentdup started
			// out as.
			// Otherwise it is possible that things can be messed
			// up by somebody swapping between hardlinked and
			// not hardlinked at the same time as a resume happens.
			if(lstat(hlinkedpath, &statp))
			{
				logp("previous attempt started not hardlinked\n");
				hardlinked=0;
			}
			else
			{
				logp("previous attempt started hardlinked\n");
				hardlinked=1;
			}
		}

		if(hardlinked)
		{
			// Create a file to indicate that the previous backup
			// does not have others depending on it.
			FILE *hfp=NULL;
			if(!(hfp=open_file(hlinkedpath, "wb")))
				goto end;
			// Stick the next backup timestamp in it. It might
			// be useful one day when wondering when the next
			// backup, now deleted, was made.
			fprintf(hfp, "%s\n", tstmp);
			if(close_fp(&hfp))
			{
				logp("error closing hardlinked indication\n");
				goto end;
			}
			logp(" doing hardlinked archive\n");
			logp(" will not generate reverse deltas\n");
		}
		else
		{
			logp(" not doing hardlinked archive\n");
			logp(" will generate reverse deltas\n");
			unlink(hlinkedpath);
		}
	}

	if(atomic_data_jiggle(sdirs, cconf, manifest, currentdup,
		currentdupdata, datadir, datadirtmp, deletionsfile,
		hardlinked, bno))
	{
		logp("could not finish up backup.\n");
		goto end;
	}

	if(write_status(STATUS_SHUFFLING, "deleting temporary files", cconf))
		goto end;

	// Remove the temporary data directory, we have now removed
	// everything useful from it.
	recursive_delete(datadirtmp, NULL, 1 /* del files */);

	// Clean up the currentdata directory - this is now the 'old'
	// currentdata directory. Any files that were deleted from
	// the client will be left in there, so call recursive_delete
	// with the option that makes it not delete files.
	// This will have the effect of getting rid of unnecessary
	// directories.
	sync(); // try to help CIFS
	recursive_delete(currentdupdata, NULL, 0 /* do not del files */);

	// Rename the old current to something that we know to delete.
	if(previous_backup)
	{
		if(deleteme_move(sdirs->client,
			fullrealcurrent, realcurrent, cconf)
		  || do_rename(currentdup, fullrealcurrent))
			goto end;
	}

	if(deleteme_maybe_delete(cconf, sdirs->client))
		goto end;

	cntr_stats_to_file(cconf->cntr, sdirs->finishing, ACTION_BACKUP);

	// Rename the finishing symlink so that it becomes the current symlink
	do_rename(sdirs->finishing, sdirs->current);

	cntr_print(cconf->cntr, ACTION_BACKUP);
	logp("Backup completed.\n");
	logp("End phase4 (shuffle files)\n");
	set_logfp(NULL, cconf); // will close logfp.

	compress_filename(sdirs->current, "log", "log.gz", cconf);

	ret=0;
end:
	if(datadir) free(datadir);
	if(datadirtmp) free(datadirtmp);
	if(manifest) free(manifest);
	if(deletionsfile) free(deletionsfile);
	if(currentdup) free(currentdup);
	if(currentduptmp) free(currentduptmp);
	if(currentdupdata) free(currentdupdata);
	if(timestamp) free(timestamp);
	if(fullrealcurrent) free(fullrealcurrent);
	if(logpath) free(logpath);
	if(hlinkedpath) free(hlinkedpath);

	return ret;
}