static void get_wbuf_from_data(struct conf **confs, struct iobuf *wbuf, struct slist *slist, uint8_t end_flags) { struct blk *blk; struct blist *blist=slist->blist; for(blk=blist->last_sent; blk; blk=blk->next) { if(blk->requested) { iobuf_set(wbuf, CMD_DATA, blk->data, blk->length); blk->requested=0; blist->last_sent=blk; cntr_add(get_cntr(confs), CMD_DATA, 1); break; } else { cntr_add_same(get_cntr(confs), CMD_DATA); if(end_flags&END_BLK_REQUESTS) { // Force onwards when the server has said that // there are no more blocks to request. blist->last_sent=blk; continue; } } if(blk==blist->last_requested) break; } // Need to free stuff that is no longer needed. free_stuff(slist); }
int restore_dir(struct asfd *asfd, struct sbuf *sb, const char *dname, enum action act, struct conf **confs) { int ret=0; char *rpath=NULL; if(act==ACTION_RESTORE) { if(build_path(dname, "", &rpath, NULL)) { ret=warn_and_interrupt(asfd, sb, confs, "build path failed: %s", dname); goto end; } else if(!is_dir_lstat(rpath)) { if(mkdir(rpath, 0777)) { ret=warn_and_interrupt(asfd, sb, confs, "mkdir error: %s", strerror(errno)); goto end; } } attribs_set(asfd, rpath, &(sb->statp), sb->winattr, confs); if(!ret) cntr_add(get_cntr(confs[OPT_CNTR]), sb->path.cmd, 1); } else cntr_add(get_cntr(confs[OPT_CNTR]), sb->path.cmd, 1); end: if(rpath) free(rpath); return ret; }
static int restore_link(struct asfd *asfd, struct sbuf *sb, const char *fname, enum action act, struct conf **confs) { int ret=0; if(act==ACTION_RESTORE) { char *rpath=NULL; if(build_path(fname, "", &rpath, NULL)) { ret=warn_and_interrupt(asfd, sb, confs, "build path failed: %s", fname); goto end; } else if(make_link(asfd, fname, sb->link.buf, sb->link.cmd, confs)) { ret=warn_and_interrupt(asfd, sb, confs, "could not create link", ""); goto end; } else if(!ret) { attribs_set(asfd, fname, &(sb->statp), sb->winattr, confs); cntr_add(get_cntr(confs[OPT_CNTR]), sb->path.cmd, 1); } if(rpath) free(rpath); } else cntr_add(get_cntr(confs[OPT_CNTR]), sb->path.cmd, 1); end: return ret; }
int restore_sbuf_protocol1(struct asfd *asfd, struct sbuf *sb, struct bu *bu, enum action act, struct sdirs *sdirs, enum cntr_status cntr_status, struct conf **cconfs) { if((sb->protocol1->datapth.buf && asfd->write(asfd, &(sb->protocol1->datapth))) || asfd->write(asfd, &sb->attr)) return -1; else if(sbuf_is_filedata(sb) || sbuf_is_vssdata(sb)) { if(!sb->protocol1->datapth.buf) { logw(asfd, get_cntr(cconfs), "Got filedata entry with no datapth: %c:%s\n", sb->path.cmd, sb->path.buf); return 0; } return restore_file(asfd, bu, sb, act, sdirs, cconfs); } else { if(asfd->write(asfd, &sb->path)) return -1; // If it is a link, send what // it points to. else if(sbuf_is_link(sb) && asfd->write(asfd, &sb->link)) return -1; cntr_add(get_cntr(cconfs), sb->path.cmd, 0); } return 0; }
static int deal_with_receive_end_file(struct asfd *asfd, struct sdirs *sdirs, struct sbuf *rb, struct fzp *chfp, struct conf **cconfs, char **last_requested) { static char *cp=NULL; static struct iobuf *rbuf; rbuf=asfd->rbuf; // Finished the file. // Write it to the phase2 file, and free the buffers. if(fzp_close(&(rb->protocol1->fzp))) { logp("error closing delta for %s in receive\n", rb->path); goto error; } iobuf_move(&rb->protocol1->endfile, rbuf); if(rb->flags & SBUFL_RECV_DELTA && finish_delta(sdirs, rb)) goto error; if(sbufl_to_manifest(rb, chfp)) goto error; if(rb->flags & SBUFL_RECV_DELTA) cntr_add_changed(get_cntr(cconfs[OPT_CNTR]), rb->path.cmd); else cntr_add(get_cntr(cconfs[OPT_CNTR]), rb->path.cmd, 0); if(*last_requested && !strcmp(rb->path.buf, *last_requested)) { free(*last_requested); *last_requested=NULL; } cp=strchr(rb->protocol1->endfile.buf, ':'); if(rb->protocol1->endfile.buf) cntr_add_bytes(get_cntr(cconfs[OPT_CNTR]), strtoull(rb->protocol1->endfile.buf, NULL, 10)); if(cp) { // checksum stuff goes here } sbuf_free_content(rb); return 0; error: sbuf_free_content(rb); return -1; }
static int restore_remaining_dirs(struct asfd *asfd, struct bu *bu, struct slist *slist, enum action act, struct sdirs *sdirs, enum cntr_status cntr_status, struct conf **cconfs) { int ret=-1; struct sbuf *sb; struct sbuf *need_data=NULL; if(!(need_data=sbuf_alloc(get_protocol(cconfs)))) goto end; // Restore any directories that are left in the list. for(sb=slist->head; sb; sb=sb->next) { if(get_protocol(cconfs)==PROTO_1) { if(restore_sbuf_protocol1(asfd, sb, bu, act, sdirs, cntr_status, cconfs)) goto end; } else { if(restore_sbuf_protocol2(asfd, sb, act, cntr_status, get_cntr(cconfs), need_data)) goto end; } } ret=0; end: sbuf_free(&need_data); return ret; }
// return 1 to say that a file was processed static int maybe_process_file(struct asfd *asfd, struct sdirs *sdirs, struct sbuf *cb, struct sbuf *p1b, struct fzp *ucfp, struct conf **cconfs) { switch(sbuf_pathcmp(cb, p1b)) { case 0: return maybe_do_delta_stuff(asfd, sdirs, cb, p1b, ucfp, cconfs); case 1: //logp("ahead: %s\n", p1b->path); // ahead - need to get the whole file if(process_new(sdirs, cconfs, p1b, ucfp)) return -1; // Do not free. return 1; case -1: default: //logp("behind: %s\n", p1b->path); // Behind - need to read more from the old manifest. // Count a deleted file - it was in the old manifest // but not the new. cntr_add_deleted(get_cntr(cconfs[OPT_CNTR]), cb->path.cmd); return 0; } }
// Return -1 for error, 0 for could not open file, 1 for success. int rabin_open_file(struct sbuf *sb, struct asfd *asfd, struct cntr *cntr, struct conf **confs) { struct BFILE *bfd=&sb->protocol2->bfd; #ifdef HAVE_WIN32 if(win32_lstat(sb->path.buf, &sb->statp, &sb->winattr)) #else if(lstat(sb->path.buf, &sb->statp)) #endif { // This file is no longer available. logw(asfd, cntr, "%s has vanished\n", sb->path.buf); return 0; } sb->compression=get_int(confs[OPT_COMPRESSION]); // Encryption not yet implemented in protocol2. //sb->protocol2->encryption=conf->protocol2->encryption_password?1:0; if(attribs_encode(sb)) return -1; if(sbuf_is_metadata(sb)) return rabin_open_file_extrameta(sb, asfd, cntr); if(bfd->open_for_send(bfd, asfd, sb->path.buf, sb->winattr, get_int(confs[OPT_ATIME]), cntr, PROTO_2)) { logw(asfd, get_cntr(confs), "Could not open %s\n", sb->path.buf); return 0; } return 1; }
END_TEST START_TEST(test_protocol1_restore_file_not_found) { struct asfd *asfd; struct sbuf *sb; struct conf **confs; struct cntr *cntr; clean(); confs=setup_confs(); sb=setup_sbuf("/path", "/datapth", NULL, 0); asfd=asfd_mock_setup(&areads, &awrites); setup_not_found_message(asfd, sb); // Passing in NULL bu means that the file will not be found, as there // are no backups to traverse. // The function should return 0, so that the calling function // can continue. fail_unless(!restore_file( asfd, NULL /*bu*/, sb, ACTION_RESTORE, NULL /*sdirs*/, confs )); cntr=get_cntr(confs); fail_unless(cntr->ent[CMD_WARNING]->count==1); tear_down(&sb, NULL, &confs, &asfd); }
static int make_rev_sig(const char *dst, const char *sig, const char *endfile, int compression, struct conf **confs) { int ret=-1; FILE *dstfp=NULL; gzFile dstzp=NULL; FILE *sigp=NULL; //logp("make rev sig: %s %s\n", dst, sig); if(dpth_protocol1_is_compressed(compression, dst)) dstzp=gzopen_file(dst, "rb"); else dstfp=open_file(dst, "rb"); if((!dstzp && !dstfp) || !(sigp=open_file(sig, "wb")) || rs_sig_gzfile(NULL, dstfp, dstzp, sigp, get_librsync_block_len(endfile), RS_DEFAULT_STRONG_LEN, NULL, get_cntr(confs[OPT_CNTR]))!=RS_DONE) goto end; ret=0; end: //logp("end of make rev sig\n"); gzclose_fp(&dstzp); close_fp(&dstfp); if(close_fp(&sigp)) { logp("error closing %s in %s\n", sig, __func__); return -1; } return ret; }
// Used on resume, this just reads the phase1 file and sets up cntr. static int read_phase1(struct manio *p1manio, struct conf **cconfs) { int ret=-1; struct sbuf *p1b; enum protocol protocol=get_protocol(cconfs); struct cntr *cntr=get_cntr(cconfs); if(!(p1b=sbuf_alloc(protocol))) return -1; while(1) { sbuf_free_content(p1b); switch(manio_read(p1manio, p1b)) { case 0: break; case 1: ret=0; default: goto end; } cntr_add_phase1(cntr, p1b->path.cmd, 0); if(sbuf_is_estimatable(p1b)) cntr_add_val(cntr, CMD_BYTES_ESTIMATED, (uint64_t)p1b->statp.st_size); } end: sbuf_free(&p1b); return ret; }
static enum cliret restore_wrapper(struct asfd *asfd, enum action action, int vss_restore, struct conf **confs) { enum cliret ret=CLIENT_OK; const char *r_script_pre=get_string(confs[OPT_R_SCRIPT_PRE]); const char *r_script_post=get_string(confs[OPT_R_SCRIPT_POST]); if(r_script_pre) { int a=0; const char *args[12]; args[a++]=r_script_pre; if(get_int(confs[OPT_R_SCRIPT_RESERVED_ARGS])) { args[a++]="pre"; args[a++]="reserved2"; args[a++]="reserved3"; args[a++]="reserved4"; args[a++]="reserved5"; } args[a++]=NULL; if(run_script(asfd, args, get_strlist(confs[OPT_R_SCRIPT_PRE_ARG]), confs, 1, 1, 1)) ret=CLIENT_ERROR; } if(ret==CLIENT_OK) { if(do_restore_client(asfd, confs, action, vss_restore)) ret=CLIENT_ERROR; } if((ret==CLIENT_OK || get_int(confs[OPT_R_SCRIPT_POST_RUN_ON_FAIL])) && r_script_post) { int a=0; const char *args[12]; args[a++]=r_script_pre; if(get_int(confs[OPT_R_SCRIPT_RESERVED_ARGS])) { args[a++]="post"; // Tell post script whether the restore failed. args[a++]=ret?"1":"0"; args[a++]="reserved3"; args[a++]="reserved4"; args[a++]="reserved5"; } args[a++]=NULL; if(run_script(asfd, args, get_strlist(confs[OPT_R_SCRIPT_POST_ARG]), confs, 1, 1, 1)) ret=CLIENT_ERROR; } // Return non-zero if there were warnings, // so that the test script can easily check. if(ret==CLIENT_OK && get_cntr(confs)->ent[CMD_WARNING]->count) ret=CLIENT_RESTORE_WARNINGS; return ret; }
static enum cliret initial_comms(struct async *as, enum action *action, char **incexc, struct conf **confs) { struct asfd *asfd; char *server_version=NULL; enum cliret ret=CLIENT_OK; asfd=as->asfd; if(authorise_client(asfd, &server_version, get_string(confs[OPT_CNAME]), get_string(confs[OPT_PASSWORD]), get_cntr(confs))) goto error; if(server_version) { logp("Server version: %s\n", server_version); // Servers before 1.3.2 did not tell us their versions. // 1.3.2 and above can do the automatic CA stuff that // follows. switch(ca_client_setup(asfd, confs)) { case 0: break; // All OK. case 1: // Certificate signed successfully. // Everything is OK, but we will reconnect now, // in order to use the new keys/certificates. goto reconnect; default: logp("Error with cert signing request\n"); goto error; } } set_non_blocking(asfd->fd); if(ssl_check_cert(asfd->ssl, NULL, confs)) { logp("check cert failed\n"); goto error; } if(extra_comms(as, confs, action, incexc)) { logp("extra comms failed\n"); goto error; } ret=CLIENT_OK; goto end; error: ret=CLIENT_ERROR; goto end; reconnect: ret=CLIENT_RECONNECT; goto end; end: free_w(&server_version); return ret; }
// FIX THIS: it only works with protocol1. int restore_interrupt(struct asfd *asfd, struct sbuf *sb, const char *msg, struct conf **confs) { int ret=0; struct cntr *cntr=get_cntr(confs[OPT_CNTR]); struct iobuf *rbuf=asfd->rbuf; if(get_e_protocol(confs[OPT_PROTOCOL])!=PROTO_1) return 0; if(!cntr) return 0; cntr_add(cntr, CMD_WARNING, 1); logp("WARNING: %s\n", msg); if(asfd->write_str(asfd, CMD_WARNING, msg)) goto end; // If it is file data, get the server // to interrupt the flow and move on. if(sb->path.cmd!=CMD_FILE && sb->path.cmd!=CMD_ENC_FILE && sb->path.cmd!=CMD_EFS_FILE && sb->path.cmd!=CMD_VSS && sb->path.cmd!=CMD_ENC_VSS && sb->path.cmd!=CMD_VSS_T && sb->path.cmd!=CMD_ENC_VSS_T) return 0; if(sb->protocol1 && !(sb->protocol1->datapth.buf)) return 0; if(sb->protocol2 && !(sb->path.buf)) return 0; if(asfd->write_str(asfd, CMD_INTERRUPT, sb->protocol1->datapth.buf)) goto end; // Read to the end file marker. while(1) { iobuf_free_content(rbuf); if(asfd->read(asfd)) goto end; if(!ret && rbuf->len) { if(rbuf->cmd==CMD_APPEND) continue; else if(rbuf->cmd==CMD_END_FILE) break; else { iobuf_log_unexpected(rbuf, __func__); goto end; } } } ret=0; end: iobuf_free_content(rbuf); return ret; }
static int run_list(struct asfd *asfd, struct sdirs *sdirs, struct conf **cconfs) { int ret=-1; char *cp=NULL; char *backupno=NULL; char *browsedir=NULL; char *listregex=NULL; struct iobuf *rbuf=asfd->rbuf; if(!client_can_generic(cconfs, OPT_CLIENT_CAN_LIST)) { logp("Not allowing list of %s\n", get_string(cconfs[OPT_CNAME])); asfd->write_str(asfd, CMD_GEN, "Client list is not allowed"); goto end; } if(!strncmp_w(rbuf->buf, "list ")) { if((cp=strchr(rbuf->buf, ':'))) { *cp='\0'; if(!(listregex=strdup_w(cp+1, __func__))) goto end; } if(!(backupno=strdup_w(rbuf->buf+strlen("list "), __func__))) goto end; } else if(!strncmp_w(rbuf->buf, "listb ")) { if((cp=strchr(rbuf->buf, ':'))) { *cp='\0'; if(!(browsedir=strdup_w(cp+1, __func__))) goto end; } strip_trailing_slashes(&browsedir); if(!(backupno=strdup_w(rbuf->buf+strlen("listb "), __func__))) goto end; } if(asfd->write_str(asfd, CMD_GEN, "ok")) goto end; iobuf_free_content(asfd->rbuf); if(list_server_init(asfd, sdirs, get_cntr(cconfs), get_protocol(cconfs), backupno, listregex, browsedir)) goto end; ret=do_list_server(); end: free_w(&backupno); free_w(&browsedir); free_w(&listregex); list_server_free(); return ret; }
static int changed_non_file(struct sbuf *p1b, struct manio *ucmanio, enum cmd cmd, struct conf **cconfs) { // As new_non_file. if(manio_write_sbuf(ucmanio, p1b)) return -1; cntr_add_changed(get_cntr(cconfs), cmd); sbuf_free_content(p1b); return 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; }
static int process_unchanged_file(struct sbuf *p1b, struct sbuf *cb, struct fzp *ucfp, struct conf **cconfs) { // Need to re-encode the p1b attribs to include compression and // other bits and pieces that are recorded on cb. iobuf_move(&p1b->protocol1->datapth, &cb->protocol1->datapth); iobuf_move(&p1b->protocol1->endfile, &cb->protocol1->endfile); p1b->compression=cb->compression; if(attribs_encode(p1b)) return -1; if(sbufl_to_manifest(p1b, ucfp)) return -1; cntr_add_same(get_cntr(cconfs[OPT_CNTR]), p1b->path.cmd); if(p1b->protocol1->endfile.buf) cntr_add_bytes( get_cntr(cconfs[OPT_CNTR]), strtoull(p1b->protocol1->endfile.buf, NULL, 10)); sbuf_free_content(cb); return 1; }
static int make_rev_delta(const char *src, const char *sig, const char *del, int compression, struct conf **cconfs) { int ret=-1; FILE *srcfp=NULL; FILE *delfp=NULL; FILE *sigp=NULL; gzFile srczp=NULL; gzFile delzp=NULL; rs_signature_t *sumset=NULL; //logp("make rev delta: %s %s %s\n", src, sig, del); if(!(sigp=open_file(sig, "rb"))) goto end; if(rs_loadsig_file(sigp, &sumset, NULL)!=RS_DONE || rs_build_hash_table(sumset)!=RS_DONE) goto end; //logp("make rev deltb: %s %s %s\n", src, sig, del); if(dpth_protocol1_is_compressed(compression, src)) srczp=gzopen_file(src, "rb"); else srcfp=open_file(src, "rb"); if(!srczp && !srcfp) goto end; if(get_int(cconfs[OPT_COMPRESSION])) delzp=gzopen_file(del, comp_level(cconfs)); else delfp=open_file(del, "wb"); if(!delzp && !delfp) goto end; if(rs_delta_gzfile(NULL, sumset, srcfp, srczp, delfp, delzp, NULL, get_cntr(cconfs[OPT_CNTR]))!=RS_DONE) goto end; ret=0; end: if(sumset) rs_free_sumset(sumset); gzclose_fp(&srczp); close_fp(&srcfp); close_fp(&sigp); if(gzclose_fp(&delzp)) { logp("error closing zp %s in %s\n", del, __func__); ret=-1; } if(close_fp(&delfp)) { logp("error closing fp %s in %s\n", del, __func__); ret=-1; } return ret; }
static int changed_non_file(struct sbuf *p1b, struct fzp *ucfp, enum cmd cmd, struct conf **cconfs) { // As new_non_file. if(sbufl_to_manifest(p1b, ucfp)) return -1; else cntr_add_changed(get_cntr(cconfs[OPT_CNTR]), cmd); sbuf_free_content(p1b); return 0; }
static int restore_sbuf(struct asfd *asfd, struct sbuf *sb, struct bu *bu, enum action act, struct sdirs *sdirs, enum cntr_status cntr_status, struct conf **cconfs, struct sbuf *need_data, const char *manifest, struct slist *slist) { //printf("%s: %s\n", act==ACTION_RESTORE?"restore":"verify", sb->path.buf); if(write_status(cntr_status, sb->path.buf, get_cntr(cconfs))) return -1; if(sb->path.cmd==CMD_HARD_LINK) { struct f_link *lp=NULL; struct f_link **bucket=NULL; if((lp=linkhash_search(&sb->statp, &bucket))) { // It is in the list of stuff that is in the manifest, // but was skipped on this restore. // Need to go through the manifest from the beginning, // and substitute in the data to restore to this // location. return hard_link_substitution(asfd, sb, lp, bu, act, sdirs, cntr_status, cconfs, manifest, slist); // FIX THIS: Would be nice to remember the new link // location so that further hard links would link to // it instead of doing the hard_link_substitution // business over again. } } if(get_protocol(cconfs)==PROTO_1) { return restore_sbuf_protocol1(asfd, sb, bu, act, sdirs, cntr_status, cconfs); } else { return restore_sbuf_protocol2(asfd, sb, act, cntr_status, get_cntr(cconfs), need_data); } }
static int ft_err(struct asfd *asfd, struct conf **confs, struct FF_PKT *ff, const char *msg) { int raise_error; const char *prefix=""; raise_error=get_int(confs[OPT_SCAN_PROBLEM_RAISES_ERROR]); if(raise_error) prefix="Err: "; if(logw(asfd, get_cntr(confs), "%s%s %s: %s\n", prefix, msg, ff->fname, strerror(errno))) return -1; if(raise_error) return -1; return 0; }
// FIX THIS: need to unit test this. static int do_conf_switch_to_orig_client(struct conf **globalcs, struct conf **cconfs, const char *orig_client, const char *buf) { int ret=-1; int loadrc; struct conf **sconfs=NULL; if(!(sconfs=confs_alloc()) || confs_init(sconfs)) goto end; if(set_string(sconfs[OPT_CNAME], orig_client)) goto end; logp("Client wants to switch to client: %s\n", get_string(sconfs[OPT_CNAME])); // Allow unit testing using a buffer. #ifdef UTEST if(buf) loadrc=conf_load_overrides_buf(globalcs, sconfs, buf); else #endif loadrc=conf_load_clientconfdir(globalcs, sconfs); if(loadrc) { logp("Could not load alternate config: %s", get_string(sconfs[OPT_CNAME])); goto end; } set_int(sconfs[OPT_SEND_CLIENT_CNTR], get_int(cconfs[OPT_SEND_CLIENT_CNTR])); if(!restore_client_allowed(cconfs, sconfs)) goto end; if(set_string(sconfs[OPT_RESTORE_PATH], get_string(cconfs[OPT_RESTORE_PATH]))) goto end; if(set_string(cconfs[OPT_RESTORE_PATH], NULL)) goto end; set_cntr(sconfs[OPT_CNTR], get_cntr(cconfs[OPT_CNTR])); set_cntr(cconfs[OPT_CNTR], NULL); confs_free_content(cconfs); confs_init(cconfs); confs_memcpy(cconfs, sconfs); confs_null(sconfs); if(set_string(cconfs[OPT_RESTORE_CLIENT], get_string(cconfs[OPT_CNAME]))) goto end; if(set_string(cconfs[OPT_ORIG_CLIENT], get_string(cconfs[OPT_CNAME]))) goto end; logp("Switched to client %s\n", get_string(cconfs[OPT_CNAME])); ret=0; end: confs_free(&sconfs); return ret; }
static int my_send_file(struct asfd *asfd, struct FF_PKT *ff, struct conf **confs) { static struct sbuf *sb=NULL; struct cntr *cntr=get_cntr(confs); if(!sb && !(sb=sbuf_alloc(get_protocol(confs)))) return -1; #ifdef HAVE_WIN32 if(ff->winattr & FILE_ATTRIBUTE_ENCRYPTED) { if(ff->type==FT_REG || ff->type==FT_DIR) return to_server(asfd, confs, ff, sb, CMD_EFS_FILE); return logw(asfd, cntr, "EFS type %d not yet supported: %s\n", ff->type, ff->fname); } #endif switch(ff->type) { case FT_REG: case FT_RAW: case FT_FIFO: return do_to_server(asfd, confs, ff, sb, filesymbol, in_exclude_comp(get_strlist(confs[OPT_EXCOM]), ff->fname, get_int(confs[OPT_COMPRESSION]))); case FT_DIR: case FT_REPARSE: case FT_JUNCTION: return to_server(asfd, confs, ff, sb, dirsymbol); case FT_LNK_S: return to_server(asfd, confs, ff, sb, CMD_SOFT_LINK); case FT_LNK_H: return to_server(asfd, confs, ff, sb, CMD_HARD_LINK); case FT_SPEC: return to_server(asfd, confs, ff, sb, CMD_SPECIAL); case FT_NOFSCHG: return ft_err(asfd, confs, ff, "Will not descend: " "file system change not allowed"); case FT_NOFOLLOW: return ft_err(asfd, confs, ff, "Could not follow link"); case FT_NOSTAT: return ft_err(asfd, confs, ff, "Could not stat"); case FT_NOOPEN: return ft_err(asfd, confs, ff, "Could not open directory"); default: return logw(asfd, cntr, "Err: Unknown file type %d: %s\n", ff->type, ff->fname); } }
static #endif int restore_file(struct asfd *asfd, struct bu *bu, struct sbuf *sb, enum action act, struct sdirs *sdirs, struct conf **cconfs) { int ret=-1; char *path=NULL; struct bu *b; struct bu *hlwarn=NULL; struct stat statp; struct cntr *cntr=NULL; if(cconfs) cntr=get_cntr(cconfs); // Go up the array until we find the file in the data directory. for(b=bu; b; b=b->next) { free_w(&path); if(!(path=prepend_s(b->data, sb->protocol1->datapth.buf))) goto end; if(lstat(path, &statp) || !S_ISREG(statp.st_mode)) continue; if(b!=bu && (bu->flags & BU_HARDLINKED)) hlwarn=b; if(process_data_dir_file(asfd, bu, b, path, sb, act, sdirs, cconfs)) goto end; // This warning must be done after everything else, // Because the client does not expect another cmd after // the warning. if(hlwarn) logw(asfd, cntr, "restore found %s in %s\n", iobuf_to_printable(&sb->path), hlwarn->basename); ret=0; // All OK. break; } if(!b) { logw(asfd, cntr, "restore could not find %s (%s)\n", iobuf_to_printable(&sb->path), iobuf_to_printable(&sb->protocol1->datapth)); ret=0; // Carry on to subsequent files. } end: free_w(&path); return ret; }
static int new_non_file(struct sbuf *p1b, struct manio *ucmanio, struct conf **cconfs) { // Is something that does not need more data backed up. // Like a directory or a link or something like that. // Goes into the unchanged file, so that it does not end up out of // order with normal files, which has to wait around for their data // to turn up. if(manio_write_sbuf(ucmanio, p1b)) return -1; cntr_add(get_cntr(cconfs), p1b->path.cmd, 0); sbuf_free_content(p1b); return 0; }
static int add_to_blks_list(struct asfd *asfd, struct conf **confs, struct slist *slist) { int just_opened=0; struct sbuf *sb=slist->last_requested; if(!sb) return 0; if(sb->protocol2->bfd.mode==BF_CLOSED) { char buf[32]; struct cntr *cntr=NULL; if(confs) cntr=get_cntr(confs); switch(rabin_open_file(sb, asfd, cntr, confs)) { case 1: // All OK. break; case 0: // Could not open file. Tell the server. base64_from_uint64(sb->protocol2->index, buf); if(asfd->write_str(asfd, CMD_INTERRUPT, buf)) return -1; if(slist_del_sbuf(slist, sb)) return -1; sbuf_free(&sb); return 0; default: return -1; } just_opened=1; } switch(blks_generate(sb, slist->blist, just_opened)) { case 0: // All OK. break; case 1: // File ended. if(rabin_close_file(sb, asfd)) { logp("Failed to close file %s\n", iobuf_to_printable(&sb->path)); return -1; } slist->last_requested=sb->next; break; default: return -1; } return 0; }
static int new_non_file(struct sbuf *p1b, struct fzp *ucfp, struct conf **cconfs) { // Is something that does not need more data backed up. // Like a directory or a link or something like that. // Goes into the unchanged file, so that it does not end up out of // order with normal files, which has to wait around for their data // to turn up. if(sbufl_to_manifest(p1b, ucfp)) return -1; else cntr_add(get_cntr(cconfs[OPT_CNTR]), p1b->path.cmd, 0); sbuf_free_content(p1b); return 0; }
static int do_to_server(struct asfd *asfd, struct conf **confs, struct FF_PKT *ff, struct sbuf *sb, enum cmd cmd, int compression) { #ifdef HAVE_WIN32 int split_vss=0; int strip_vss=0; if(get_protocol(confs)==PROTO_1) { split_vss=get_int(confs[OPT_SPLIT_VSS]); strip_vss=get_int(confs[OPT_STRIP_VSS]); } #endif struct cntr *cntr=get_cntr(confs); sb->compression=compression; sb->encryption=encryption; sb->statp=ff->statp; attribs_encode(sb); #ifdef HAVE_WIN32 if(split_vss && !strip_vss && cmd!=CMD_EFS_FILE && maybe_send_extrameta(asfd, ff->fname, cmd, sb, cntr, metasymbol)) return -1; #endif if(usual_stuff(asfd, cntr, ff->fname, ff->link, sb, cmd)) return -1; if(ff->type==FT_REG) cntr_add_val(cntr, CMD_BYTES_ESTIMATED, (uint64_t)ff->statp.st_size); #ifdef HAVE_WIN32 if(split_vss && !strip_vss && cmd!=CMD_EFS_FILE // FIX THIS: May have to check that it is not a directory here. && !S_ISDIR(sb->statp.st_mode) // does this work? && maybe_send_extrameta(asfd, ff->fname, cmd, sb, cntr, vss_trail_symbol)) return -1; return 0; #else return maybe_send_extrameta(asfd, ff->fname, cmd, sb, cntr, metasymbol); #endif }
void version_warn(struct asfd *asfd, struct conf **confs, struct conf **cconfs) { const char *cname=get_string(cconfs[OPT_CNAME]); const char *peer_version=get_string(cconfs[OPT_PEER_VERSION]); if(!peer_version || strcmp(peer_version, VERSION)) { char msg[256]=""; if(!peer_version || !*peer_version) snprintf(msg, sizeof(msg), "Client '%s' has an unknown version. Please upgrade.", cname?cname:"unknown"); else snprintf(msg, sizeof(msg), "Client '%s' version '%s' does not match server version '%s'. An upgrade is recommended.", cname?cname:"unknown", peer_version, VERSION); if(confs) logw(asfd, get_cntr(confs), "%s\n", msg); logp("WARNING: %s\n", msg); } }