static char *set_new_datapth(struct sbuf *sb, const char *datadirtmp, struct dpth *dpth, int *istreedata, struct config *cconf) { char *rpath=NULL; if(cconf->directory_tree) *istreedata=treedata(sb); if(*istreedata) { // We want to place this file in a directory structure like // the directory structure on the original client. if(!(sb->datapth=prepend_s("t", sb->path, strlen(sb->path)))) { log_and_send_oom(__FUNCTION__); return NULL; } } else { mk_dpth(dpth, cconf, sb->cmd); if(!(sb->datapth=strdup(dpth->path))) // file data path { log_and_send_oom(__FUNCTION__); return NULL; } } if(build_path(datadirtmp, sb->datapth, strlen(sb->datapth), &rpath, datadirtmp)) { log_and_send("build path failed"); return NULL; } return rpath; }
int init_dpthl(struct dpthl *dpthl, struct asfd *asfd, struct sdirs *sdirs, struct conf *cconf) { char *tmp=NULL; //logp("in init_dpthl\n"); dpthl->looped=0; dpthl->prim=0; dpthl->seco=0; dpthl->tert=0; if((dpthl->prim=get_highest_entry(sdirs->currentdata))<0) { // Could not open directory. Set all zeros. dpthl->prim=0; // mk_dpthl(dpthl, cconf); return 0; } mk_dpthl_prim(dpthl); if(!(tmp=prepend_s(sdirs->currentdata, dpthl->path))) { log_and_send_oom(asfd, __func__); return -1; } if((dpthl->seco=get_highest_entry(tmp))<0) { // Could not open directory. Set zero. dpthl->seco=0; // mk_dpthl(dpthl, cconf); free(tmp); return 0; } free(tmp); mk_dpthl_seco(dpthl); if(!(tmp=prepend_s(sdirs->currentdata, dpthl->path))) { log_and_send_oom(asfd, __func__); return -1; } if((dpthl->tert=get_highest_entry(tmp))<0) { // Could not open directory. Set zero. dpthl->tert=0; // mk_dpthl(dpthl, cconf); free(tmp); return 0; } // At this point, we have the latest data file. Increment to get the // next free one. if(incr_dpthl(dpthl, cconf)) return -1; //logp("init_dpthl: %d/%d/%d\n", dpthl->prim, dpthl->seco, dpthl->tert); //logp("init_dpthl: %s\n", dpthl->path); return 0; }
int check_for_rubble_burp2(struct asfd *asfd, struct sdirs *sdirs, const char *incexc, int *resume, struct conf *cconf) { // FIX THIS - currently just deletes the interrupted backup. ssize_t len=0; char *real=NULL; char lnk[32]=""; if((len=readlink(sdirs->working, lnk, sizeof(lnk)-1))<0) return 0; else if(!len) { unlink(sdirs->working); return 0; } lnk[len]='\0'; if(!(real=prepend_s(sdirs->client, lnk))) { log_and_send_oom(asfd, __func__); return -1; } if(recursive_delete(real, "", 1)) { char msg[256]=""; snprintf(msg, sizeof(msg), "Could not remove interrupted directory: %s", real); log_and_send(asfd, msg); return -1; } unlink(sdirs->working); return 0; }
static char *set_new_datapth(struct asfd *asfd, struct sdirs *sdirs, struct conf **cconfs, struct sbuf *sb, struct dpth *dpth, int *istreedata) { char *tmp=NULL; char *rpath=NULL; if(get_int(cconfs[OPT_DIRECTORY_TREE])) *istreedata=treedata(sb, cconfs); if(*istreedata) { // We want to place this file in a directory structure like // the directory structure on the original client. if(!(tmp=prepend_s(TREE_DIR, sb->path.buf))) { log_and_send_oom(asfd, __func__); return NULL; } } else { if(!(tmp=strdup_w(dpth_protocol1_mk(dpth, get_int(cconfs[OPT_COMPRESSION]), sb->path.cmd), __func__))) return NULL; } iobuf_from_str(&sb->protocol1->datapth, CMD_DATAPTH, tmp); if(build_path(sdirs->datadirtmp, sb->protocol1->datapth.buf, &rpath, sdirs->datadirtmp)) { log_and_send(asfd, "build path failed"); return NULL; } return rpath; }
static char *set_new_datapth(struct asfd *asfd, struct sdirs *sdirs, struct conf *cconf, struct sbuf *sb, struct dpthl *dpthl, int *istreedata) { static char *tmp=NULL; char *rpath=NULL; if(cconf->directory_tree) *istreedata=treedata(sb); if(*istreedata) { // We want to place this file in a directory structure like // the directory structure on the original client. if(!(tmp=prepend_s("t", sb->path.buf))) { log_and_send_oom(asfd, __func__); return NULL; } } else { mk_dpthl(dpthl, cconf, sb->path.cmd); if(!(tmp=strdup(dpthl->path))) // file data path { log_and_send_oom(asfd, __func__); return NULL; } } iobuf_from_str(&sb->burp1->datapth, CMD_DATAPTH, tmp); if(build_path(sdirs->datadirtmp, sb->burp1->datapth.buf, &rpath, sdirs->datadirtmp)) { log_and_send(asfd, "build path failed"); return NULL; } return rpath; }
/* Return 1 for ok, -1 for error, 0 for too many components stripped. */ static int strip_path_components(struct asfd *asfd, struct sbuf *sb, char **path, struct conf *conf) { int s=0; char *tmp=NULL; char *cp=*path; char *dp=NULL; for(s=0; cp && *cp && s<conf->strip; s++) { if(!(dp=strchr(cp, '/'))) { char msg[256]=""; snprintf(msg, sizeof(msg), "Stripped too many components: %s", *path); if(restore_interrupt(asfd, sb, msg, conf)) return -1; return 0; } cp=dp+1; } if(!cp) { char msg[256]=""; snprintf(msg, sizeof(msg), "Stripped too many components: %s", *path); if(restore_interrupt(asfd, sb, msg, conf)) return -1; return 0; } if(!(tmp=strdup(cp))) { log_and_send_oom(asfd, __func__); return -1; } free(*path); *path=tmp; return 1; }
static int extra_comms_read(struct async *as, struct vers *vers, int *srestore, char **incexc, struct conf **globalcs, struct conf **cconfs) { int ret=-1; struct asfd *asfd; struct iobuf *rbuf; asfd=as->asfd; rbuf=asfd->rbuf; while(1) { iobuf_free_content(rbuf); if(asfd->read(asfd)) goto end; if(rbuf->cmd!=CMD_GEN) { iobuf_log_unexpected(rbuf, __func__); goto end; } if(!strcmp(rbuf->buf, "extra_comms_end")) { if(asfd->write_str(asfd, CMD_GEN, "extra_comms_end ok")) goto end; break; } else if(!strncmp_w(rbuf->buf, "autoupgrade:")) { char *os=NULL; const char *autoupgrade_dir= get_string(globalcs[OPT_AUTOUPGRADE_DIR]); os=rbuf->buf+strlen("autoupgrade:"); iobuf_free_content(rbuf); if(os && *os && autoupgrade_server(as, vers->ser, vers->cli, os, get_cntr(globalcs), autoupgrade_dir)) goto end; } else if(!strcmp(rbuf->buf, "srestore ok")) { iobuf_free_content(rbuf); // Client can accept the restore. // Load the restore config, then send it. *srestore=1; if(conf_parse_incexcs_path(cconfs, get_string(cconfs[OPT_RESTORE_PATH])) || incexc_send_server_restore(asfd, cconfs)) goto end; // Do not unlink it here - wait until // the client says that it wants to do the // restore. // Also need to leave it around if the // restore is to an alternative client, so // that the code below that reloads the config // can read it again. //unlink(get_string(cconfs[OPT_RESTORE_PATH])); } else if(!strcmp(rbuf->buf, "srestore not ok")) { const char *restore_path=get_string( cconfs[OPT_RESTORE_PATH]); // Client will not accept the restore. unlink(restore_path); if(set_string(cconfs[OPT_RESTORE_PATH], NULL)) goto end; logp("Client not accepting server initiated restore.\n"); } else if(!strcmp(rbuf->buf, "sincexc ok")) { // Client can accept incexc conf from the // server. iobuf_free_content(rbuf); if(incexc_send_server(asfd, cconfs)) goto end; } else if(!strcmp(rbuf->buf, "incexc")) { // Client is telling server its incexc // configuration so that it can better decide // what to do on resume. iobuf_free_content(rbuf); if(incexc_recv_server(asfd, incexc, globalcs)) goto end; if(*incexc) { char *tmp=NULL; char comp[32]=""; snprintf(comp, sizeof(comp), "compression = %d\n", get_int(cconfs[OPT_COMPRESSION])); if(!(tmp=prepend(*incexc, comp))) goto end; free_w(incexc); *incexc=tmp; } } else if(!strcmp(rbuf->buf, "countersok")) { // Client can accept counters on // resume/verify/restore. logp("Client supports being sent counters.\n"); set_int(cconfs[OPT_SEND_CLIENT_CNTR], 1); } else if(!strncmp_w(rbuf->buf, "uname=") && strlen(rbuf->buf)>strlen("uname=")) { char *uname=rbuf->buf+strlen("uname="); if(!strncasecmp("Windows", uname, strlen("Windows"))) set_int(cconfs[OPT_CLIENT_IS_WINDOWS], 1); } else if(!strncmp_w(rbuf->buf, "orig_client=") && strlen(rbuf->buf)>strlen("orig_client=")) { if(conf_switch_to_orig_client(globalcs, cconfs, rbuf->buf+strlen("orig_client="))) goto end; // If this started out as a server-initiated // restore, need to load the restore file // again. if(*srestore) { if(conf_parse_incexcs_path(cconfs, get_string(cconfs[OPT_RESTORE_PATH]))) goto end; } if(asfd->write_str(asfd, CMD_GEN, "orig_client ok")) goto end; } else if(!strncmp_w(rbuf->buf, "restore_spool=")) { // Client supports temporary spool directory // for restores. if(set_string(cconfs[OPT_RESTORE_SPOOL], rbuf->buf+strlen("restore_spool="))) goto end; } else if(!strncmp_w(rbuf->buf, "protocol=")) { char msg[128]=""; // Client wants to set protocol. enum protocol protocol=get_protocol(cconfs); if(protocol!=PROTO_AUTO) { snprintf(msg, sizeof(msg), "Client is trying to use protocol=%s but server is set to protocol=%d\n", rbuf->buf, protocol); log_and_send_oom(asfd, __func__); goto end; } else if(!strcmp(rbuf->buf+strlen("protocol="), "1")) { set_protocol(cconfs, PROTO_1); set_protocol(globalcs, PROTO_1); } else if(!strcmp(rbuf->buf+strlen("protocol="), "2")) { set_protocol(cconfs, PROTO_2); set_protocol(globalcs, PROTO_2); } else { snprintf(msg, sizeof(msg), "Client is trying to use protocol=%s, which is unknown\n", rbuf->buf); log_and_send_oom(asfd, __func__); goto end; } logp("Client has set protocol=%d\n", (int)get_protocol(cconfs)); } else if(!strncmp_w(rbuf->buf, "rshash=blake2")) { #ifdef RS_DEFAULT_STRONG_LEN logp("Client is trying to use librsync hash blake2, but server does not support it.\n"); goto end; #else set_e_rshash(cconfs[OPT_RSHASH], RSHASH_BLAKE2); set_e_rshash(globalcs[OPT_RSHASH], RSHASH_BLAKE2); #endif } else if(!strncmp_w(rbuf->buf, "msg")) { set_int(cconfs[OPT_MESSAGE], 1); set_int(globalcs[OPT_MESSAGE], 1); } else { iobuf_log_unexpected(rbuf, __func__); goto end; } } ret=0; end: iobuf_free_content(rbuf); return ret; }
static int list_manifest(struct asfd *asfd, const char *fullpath, regex_t *regex, const char *browsedir, struct conf *conf) { int ars=0; int ret=0; struct sbuf *sb=NULL; struct manio *manio=NULL; char *manifest_dir=NULL; char *last_bd_match=NULL; size_t bdlen=0; if(!(manifest_dir=prepend_s(fullpath, conf->protocol==PROTO_BURP1?"manifest.gz":"manifest")) || !(manio=manio_alloc()) || manio_init_read(manio, manifest_dir) || !(sb=sbuf_alloc(conf))) { log_and_send_oom(asfd, __func__); goto error; } manio_set_protocol(manio, conf->protocol); if(browsedir) bdlen=strlen(browsedir); while(1) { int show=0; if((ars=manio_sbuf_fill(manio, asfd, sb, NULL, NULL, conf))<0) goto error; else if(ars>0) goto end; // Finished OK. if(write_status(STATUS_LISTING, sb->path.buf, conf)) goto error; if(browsedir) { int r; if((r=check_browsedir(browsedir, &sb->path.buf, bdlen, &last_bd_match))<0) goto error; if(!r) continue; show++; } else { if(check_regex(regex, sb->path.buf)) show++; } if(show) { if(write_wrapper(asfd, &sb->attr) || write_wrapper(asfd, &sb->path)) goto error; if(sbuf_is_link(sb) && write_wrapper(asfd, &sb->link)) goto error; } sbuf_free_content(sb); } error: ret=-1; end: sbuf_free(&sb); free_w(&manifest_dir); manio_free(&manio); free_w(&last_bd_match); return ret; }
static int list_manifest(const char *fullpath) { int ret=0; struct sbuf *sb=NULL; struct manio *manio=NULL; char *manifest_dir=NULL; char *last_bd_match=NULL; size_t bdlen=0; if(!(manifest_dir=prepend_s(fullpath, protocol==PROTO_1?"manifest.gz":"manifest")) || !(manio=manio_open(manifest_dir, "rb", protocol)) || !(sb=sbuf_alloc(protocol))) { log_and_send_oom(asfd); goto error; } if(browsedir) bdlen=strlen(browsedir); while(1) { sbuf_free_content(sb); switch(manio_read(manio, sb)) { case 0: break; case 1: if(browsedir && *browsedir && !last_bd_match) asfd_write_wrapper_str(asfd, CMD_ERROR, "directory not found"); goto end; // Finished OK. default: goto error; } if(protocol==PROTO_2 && sb->endfile.buf) continue; if(sbuf_is_metadata(sb)) continue; if(write_status(CNTR_STATUS_LISTING, sb->path.buf, cntr)) goto error; if(browsedir) { int r; if((r=check_browsedir(browsedir, sb, bdlen, &last_bd_match))<0) goto error; if(!r) continue; } if(regex && !regex_check(regex, sb->path.buf)) continue; if(asfd_write_wrapper(asfd, &sb->attr) || asfd_write_wrapper(asfd, &sb->path)) goto error; if(sbuf_is_link(sb) && asfd_write_wrapper(asfd, &sb->link)) goto error; } error: ret=-1; end: sbuf_free(&sb); free_w(&manifest_dir); manio_close(&manio); free_w(&last_bd_match); return ret; }
int get_current_backups(const char *basedir, struct bu **arr, int *a, int log) { int i=0; int j=0; int tr=0; int ret=0; DIR *d=NULL; char buf[32]=""; char realwork[32]=""; char realfinishing[32]=""; struct dirent *dp=NULL; // Find out what certain directories really are, if they exist, // so they can be excluded. if(get_link(basedir, "working", realwork, sizeof(realwork)) || get_link(basedir, "finishing", realfinishing, sizeof(realfinishing))) return -1; if(!(d=opendir(basedir))) { if(log) log_and_send("could not open backup directory"); return -1; } while((dp=readdir(d))) { int hardlinked=0; struct stat statp; char *fullpath=NULL; char *timestamp=NULL; char *timestampstr=NULL; char *hlinkedpath=NULL; if(dp->d_ino==0 || !strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..") || !strcmp(dp->d_name, realwork) || !strcmp(dp->d_name, realfinishing)) continue; if(!(fullpath=prepend_s(basedir, dp->d_name, strlen(dp->d_name))) || !(timestamp=prepend_s(fullpath, "timestamp", strlen("timestamp"))) || !(hlinkedpath=prepend_s(fullpath, "hardlinked", strlen("hardlinked")))) { ret=-1; if(timestamp) free(timestamp); if(fullpath) free(fullpath); break; } if((!lstat(fullpath, &statp) && !S_ISDIR(statp.st_mode)) || lstat(timestamp, &statp) || !S_ISREG(statp.st_mode) || read_timestamp(timestamp, buf, sizeof(buf)) || !(timestampstr=strdup(buf))) { free(fullpath); free(timestamp); free(hlinkedpath); continue; } free(timestamp); if(!lstat(hlinkedpath, &statp)) hardlinked++; if(!(*arr=(struct bu *)realloc(*arr,(i+1)*sizeof(struct bu))) || !((*arr)[i].data=prepend_s(fullpath, "data", strlen("data"))) || !((*arr)[i].delta=prepend_s(fullpath, "deltas.reverse", strlen("deltas.reverse")))) { if(log) log_and_send_oom(__FUNCTION__); free(timestampstr); free(fullpath); free(hlinkedpath); break; } (*arr)[i].path=fullpath; (*arr)[i].timestamp=timestampstr; (*arr)[i].hardlinked=hardlinked; (*arr)[i].deletable=0; (*arr)[i].index=strtoul(timestampstr, NULL, 10); (*arr)[i].trindex=0; i++; } closedir(d); if(*arr) qsort(*arr, i, sizeof(struct bu), bu_cmp); if(i>1) { tr=(*arr)[i-1].index; // The oldest backup is deletable. (*arr)[0].deletable=1; } for(j=0; j<i-1; j++) { // Backups that come after hardlinked backups are deletable. if((*arr)[j].hardlinked) (*arr)[j+1].deletable=1; } if(!ret) { if(tr) for(j=0; j<i; j++) { // Transpose indexes so that the oldest index is set // to 1. (*arr)[j].trindex=tr-(*arr)[j].index+1; //printf("%lu: %lu\n", // (*arr)[j].index, (*arr)[j].trindex); } *a=i; } return ret; }
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; }
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; init_sbuf(&mb); if(!(manifest=prepend_s(fullpath, "manifest.gz", strlen("manifest.gz")))) { log_and_send_oom(__FUNCTION__); 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.cmd!=CMD_DIRECTORY && mb.cmd!=CMD_FILE && mb.cmd!=CMD_ENC_FILE && mb.cmd!=CMD_EFS_FILE && mb.cmd!=CMD_SPECIAL && !cmd_is_link(mb.cmd)) continue; //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))<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); return ret; }
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; }
static int restore_manifest(struct asfd *asfd, struct bu *bu, regex_t *regex, int srestore, enum action act, struct sdirs *sdirs, char **dir_for_notify, struct conf **cconfs) { int ret=-1; char *manifest=NULL; char *logpath=NULL; char *logpathz=NULL; // For sending status information up to the server. enum cntr_status cntr_status=CNTR_STATUS_RESTORING; if(act==ACTION_RESTORE) cntr_status=CNTR_STATUS_RESTORING; else if(act==ACTION_VERIFY) cntr_status=CNTR_STATUS_VERIFYING; if((act==ACTION_RESTORE && get_logpaths(bu, "restorelog", &logpath, &logpathz)) || (act==ACTION_VERIFY && get_logpaths(bu, "verifylog", &logpath, &logpathz)) || !(manifest=prepend_s(bu->path, get_protocol(cconfs)==PROTO_1? "manifest.gz":"manifest"))) { log_and_send_oom(asfd, __func__); goto end; } if(log_fzp_set(logpath, cconfs)) { char msg[256]=""; snprintf(msg, sizeof(msg), "could not open log file: %s", logpath); log_and_send(asfd, msg); goto end; } *dir_for_notify=strdup_w(bu->path, __func__); log_restore_settings(cconfs, srestore); // First, do a pass through the manifest to set up cntr. // This is the equivalent of a phase1 scan during backup. if(setup_cntr(asfd, manifest, regex, srestore, act, cntr_status, cconfs)) goto end; if(get_int(cconfs[OPT_SEND_CLIENT_CNTR]) && cntr_send(get_cntr(cconfs))) goto end; // Now, do the actual restore. ret=actual_restore(asfd, bu, manifest, regex, srestore, act, sdirs, cntr_status, cconfs); end: log_fzp_set(NULL, cconfs); compress_file(logpath, logpathz, get_int(cconfs[OPT_COMPRESSION])); if(manifest) free(manifest); if(logpath) free(logpath); if(logpathz) free(logpathz); return ret; }
int do_backup_server_burp1(struct async *as, struct sdirs *sdirs, struct conf *cconf, const char *incexc, int resume) { int ret=0; char msg[256]=""; gzFile mzp=NULL; // Real path to the working directory char *realworking=NULL; char tstmp[64]=""; struct asfd *asfd=as->asfd; struct dpthl dpthl; gzFile cmanfp=NULL; struct stat statp; logp("in do_backup_server\n"); if(init_dpthl(&dpthl, asfd, sdirs, cconf)) { log_and_send(asfd, "could not init_dpthl\n"); goto error; } if(resume) { ssize_t len=0; char real[256]=""; if((len=readlink(sdirs->working, real, sizeof(real)-1))<0) len=0; real[len]='\0'; if(!(realworking=prepend_s(sdirs->client, real))) { log_and_send_oom(asfd, __func__); goto error; } if(open_log(asfd, realworking, cconf)) goto error; } else { // Not resuming - need to set everything up fresh. if(get_new_timestamp(asfd, sdirs, cconf, tstmp, sizeof(tstmp))) goto error; if(!(realworking=prepend_s(sdirs->client, tstmp))) { log_and_send_oom(asfd, __func__); goto error; } // Add the working symlink before creating the directory. // This is because bedup checks the working symlink before // going into a directory. If the directory got created first, // bedup might go into it in the moment before the symlink // gets added. if(symlink(tstmp, sdirs->working)) // relative link to the real work dir { snprintf(msg, sizeof(msg), "could not point working symlink to: %s", realworking); log_and_send(asfd, msg); goto error; } else if(mkdir(realworking, 0777)) { snprintf(msg, sizeof(msg), "could not mkdir for next backup: %s", sdirs->working); log_and_send(asfd, msg); unlink(sdirs->working); goto error; } else if(open_log(asfd, realworking, cconf)) { goto error; } else if(mkdir(sdirs->datadirtmp, 0777)) { snprintf(msg, sizeof(msg), "could not mkdir for datadir: %s", sdirs->datadirtmp); log_and_send(asfd, msg); goto error; } else if(write_timestamp(sdirs->timestamp, tstmp)) { snprintf(msg, sizeof(msg), "unable to write timestamp %s", sdirs->timestamp); log_and_send(asfd, msg); goto error; } else if(incexc && *incexc && write_incexc(realworking, incexc)) { snprintf(msg, sizeof(msg), "unable to write incexc"); log_and_send(asfd, msg); goto error; } if(backup_phase1_server(asfd, sdirs, cconf)) { logp("error in phase 1\n"); goto error; } } // Open the previous (current) manifest. // If the split_vss setting changed between the previous backup // and the new backup, do not open the previous manifest. // This will have the effect of making the client back up everything // fresh. Need to do this, otherwise toggling split_vss on and off // will result in backups that do not work. if(!lstat(sdirs->cmanifest, &statp) && !vss_opts_changed(sdirs, cconf, incexc)) { if(!(cmanfp=gzopen_file(sdirs->cmanifest, "rb"))) { if(!lstat(sdirs->cmanifest, &statp)) { logp("could not open old manifest %s\n", sdirs->cmanifest); goto error; } } } //if(cmanfp) logp("Current manifest: %s\n", sdirs->cmanifest); if(backup_phase2_server(asfd, sdirs, cconf, &cmanfp, &dpthl, resume)) { logp("error in backup phase 2\n"); goto error; } if(backup_phase3_server(sdirs, cconf, 0 /* not recovery mode */, 1 /* compress */)) { logp("error in backup phase 3\n"); goto error; } // will not write anything more to // the new manifest // finish_backup will open it again // for reading if(gzclose_fp(&mzp)) { logp("Error closing manifest after phase3\n"); goto error; } asfd->write_str(asfd, CMD_GEN, "okbackupend"); logp("Backup ending - disconnect from client.\n"); // Close the connection with the client, the rest of the job // we can do by ourselves. asfd_free(&as->asfd); // Move the symlink to indicate that we are now in the end // phase. if(do_rename(sdirs->working, sdirs->finishing)) goto error; set_logfp(NULL, cconf); // does an fclose on logfp. // finish_backup will open logfp again ret=backup_phase4_server(sdirs, cconf); if(!ret && cconf->keep>0) ret=remove_old_backups(asfd, sdirs, cconf); goto end; error: ret=-1; end: gzclose_fp(&cmanfp); gzclose_fp(&mzp); set_logfp(NULL, cconf); // does an fclose on logfp. return ret; }
// a = length of struct bu array // i = position to restore from static int restore_manifest(struct bu *arr, int a, int i, const char *tmppath1, const char *tmppath2, regex_t *regex, int srestore, enum action act, const char *client, char **dir_for_notify, struct cntr *p1cntr, struct cntr *cntr, struct config *cconf) { int ret=0; gzFile zp=NULL; char *manifest=NULL; char *datadir=NULL; FILE *logfp=NULL; char *logpath=NULL; char *logpathz=NULL; // For sending status information up to the server. char status=STATUS_RESTORING; if(act==ACTION_RESTORE) status=STATUS_RESTORING; else if(act==ACTION_VERIFY) status=STATUS_VERIFYING; if( (act==ACTION_RESTORE && !(logpath=prepend_s(arr[i].path, "restorelog", strlen("restorelog")))) || (act==ACTION_RESTORE && !(logpathz=prepend_s(arr[i].path, "restorelog.gz", strlen("restorelog.gz")))) || (act==ACTION_VERIFY && !(logpath=prepend_s(arr[i].path, "verifylog", strlen("verifylog")))) || (act==ACTION_VERIFY && !(logpathz=prepend_s(arr[i].path, "verifylog.gz", strlen("verifylog.gz")))) || !(manifest=prepend_s(arr[i].path, "manifest.gz", strlen("manifest.gz")))) { log_and_send_oom(__FUNCTION__); ret=-1; } else if(!(logfp=open_file(logpath, "ab")) || set_logfp(logfp, cconf)) { char msg[256]=""; snprintf(msg, sizeof(msg), "could not open log file: %s", logpath); log_and_send(msg); ret=-1; } *dir_for_notify=strdup(arr[i].path); log_restore_settings(cconf, srestore); // First, do a pass through the manifest to set up the counters. // This is the equivalent of a phase1 scan during backup. if(!ret && !(zp=gzopen_file(manifest, "rb"))) { log_and_send("could not open manifest"); ret=-1; } else { int ars=0; int quit=0; struct sbuf sb; init_sbuf(&sb); while(!quit) { if((ars=sbuf_fill(NULL, zp, &sb, cntr))) { if(ars<0) ret=-1; // ars==1 means end ok quit++; } else { if((!srestore || check_srestore(cconf, sb.path)) && check_regex(regex, sb.path)) { do_filecounter(p1cntr, sb.cmd, 0); if(sb.endfile) do_filecounter_bytes(p1cntr, strtoull(sb.endfile, NULL, 10)); /* if(sb.cmd==CMD_FILE || sb.cmd==CMD_ENC_FILE || sb.cmd==CMD_METADATA || sb.cmd==CMD_ENC_METADATA || sb.cmd==CMD_VSS || sb.cmd==CMD_ENC_VSS || sb.cmd==CMD_VSS_T || sb.cmd==CMD_ENC_VSS_T || sb.cmd==CMD_EFS_FILE) do_filecounter_bytes(p1cntr, (unsigned long long) sb.statp.st_size); */ } } free_sbuf(&sb); } free_sbuf(&sb); gzclose_fp(&zp); } if(cconf->send_client_counters) { if(send_counters(client, p1cntr, cntr)) { ret=-1; } } // Now, do the actual restore. if(!ret && !(zp=gzopen_file(manifest, "rb"))) { log_and_send("could not open manifest"); ret=-1; } else { char cmd; int s=0; int quit=0; size_t len=0; struct sbuf sb; // For out-of-sequence directory restoring so that the // timestamps come out right: int scount=0; struct sbuf **sblist=NULL; init_sbuf(&sb); while(!quit) { int ars=0; char *buf=NULL; if(async_read_quick(&cmd, &buf, &len)) { logp("read quick error\n"); ret=-1; quit++; break; } if(buf) { //logp("got read quick\n"); if(cmd==CMD_WARNING) { logp("WARNING: %s\n", buf); do_filecounter(cntr, cmd, 0); free(buf); buf=NULL; continue; } else if(cmd==CMD_INTERRUPT) { // Client wanted to interrupt the // sending of a file. But if we are // here, we have already moved on. // Ignore. free(buf); buf=NULL; continue; } else { logp("unexpected cmd from client: %c:%s\n", cmd, buf); free(buf); buf=NULL; ret=-1; quit++; break; } } if((ars=sbuf_fill(NULL, zp, &sb, cntr))) { if(ars<0) ret=-1; // ars==1 means end ok quit++; } else { if((!srestore || check_srestore(cconf, sb.path)) && check_regex(regex, sb.path) && restore_ent(client, &sb, &sblist, &scount, arr, a, i, tmppath1, tmppath2, act, status, cconf, cntr, p1cntr)) { ret=-1; quit++; } } free_sbuf(&sb); } gzclose_fp(&zp); // Restore any directories that are left in the list. if(!ret) for(s=scount-1; s>=0; s--) { if(restore_sbuf(sblist[s], arr, a, i, tmppath1, tmppath2, act, client, status, p1cntr, cntr, cconf)) { ret=-1; break; } } free_sbufs(sblist, scount); if(!ret) ret=do_restore_end(act, cntr); //print_endcounter(cntr); print_filecounters(p1cntr, cntr, act); reset_filecounter(p1cntr, time(NULL)); reset_filecounter(cntr, time(NULL)); } set_logfp(NULL, cconf); compress_file(logpath, logpathz, cconf); if(manifest) free(manifest); if(datadir) free(datadir); if(logpath) free(logpath); if(logpathz) free(logpathz); return ret; }
// a = length of struct bu array // i = position to restore from static int restore_file(struct bu *arr, int a, int i, const char *datapth, const char *fname, const char *tmppath1, const char *tmppath2, int act, const char *endfile, char cmd, int64_t winattr, int compression, struct cntr *cntr, struct config *cconf) { int x=0; char msg[256]=""; // Go up the array until we find the file in the data directory. for(x=i; x<a; x++) { char *path=NULL; struct stat statp; if(!(path=prepend_s(arr[x].data, datapth, strlen(datapth)))) { log_and_send_oom(__FUNCTION__); return -1; } //logp("server file: %s\n", path); if(lstat(path, &statp) || !S_ISREG(statp.st_mode)) { free(path); continue; } else { int patches=0; struct stat dstatp; const char *tmp=NULL; const char *best=NULL; unsigned long long bytes=0; best=path; tmp=tmppath1; // Now go down the array, applying any deltas. for(x-=1; x>=i; x--) { char *dpath=NULL; if(!(dpath=prepend_s(arr[x].delta, datapth, strlen(datapth)))) { log_and_send_oom(__FUNCTION__); free(path); return -1; } if(lstat(dpath, &dstatp) || !S_ISREG(dstatp.st_mode)) { free(dpath); continue; } if(!patches) { // Need to gunzip the first one. if(inflate_or_link_oldfile(best, tmp, compression)) { logp("error when inflating %s\n", best); free(path); free(dpath); return -1; } best=tmp; if(tmp==tmppath1) tmp=tmppath2; else tmp=tmppath1; } if(do_patch(best, dpath, tmp, FALSE /* do not gzip the result */, compression /* from the manifest */, cntr, cconf)) { char msg[256]=""; snprintf(msg, sizeof(msg), "error when patching %s\n", path); log_and_send(msg); free(path); free(dpath); return -1; } best=tmp; if(tmp==tmppath1) tmp=tmppath2; else tmp=tmppath1; unlink(tmp); patches++; } if(act==ACTION_RESTORE) { if(send_file(fname, patches, best, datapth, &bytes, cmd, winattr, compression, cntr, cconf)) { free(path); return -1; } else { do_filecounter(cntr, cmd, 0); do_filecounter_bytes(cntr, strtoull(endfile, NULL, 10)); } } else if(act==ACTION_VERIFY) { if(verify_file(fname, patches, best, datapth, &bytes, endfile, cmd, compression, cntr)) { free(path); return -1; } else { do_filecounter(cntr, cmd, 0); do_filecounter_bytes(cntr, strtoull(endfile, NULL, 10)); } } do_filecounter_sentbytes(cntr, bytes); free(path); return 0; } } logw(cntr, "restore could not find %s (%s)\n", fname, datapth); //return -1; return 0; }