// FIX THIS: Maybe should be in bfile.c. enum ofr_e open_for_restore(struct asfd *asfd, BFILE *bfd, const char *path, struct sbuf *sb, int vss_restore, struct cntr *cntr, enum protocol protocol) { static int flags; if(bfd->mode!=BF_CLOSED) { #ifdef HAVE_WIN32 if(bfd->path && !strcmp(bfd->path, path)) { // Already open after restoring the VSS data. // Time now for the actual file data. return OFR_OK; } else { #endif if(bfd->close(bfd, asfd)) { logp("error closing %s in %s()\n", path, __func__); return OFR_ERROR; } #ifdef HAVE_WIN32 } #endif } bfile_init(bfd, sb->winattr, cntr); #ifdef HAVE_WIN32 bfd->set_win32_api(bfd, vss_restore); #endif if(S_ISDIR(sb->statp.st_mode)) { // Windows directories are treated as having file data. flags=O_WRONLY|O_BINARY; mkdir(path, 0777); } else flags=O_WRONLY|O_BINARY|O_CREAT|O_TRUNC; if(bfd->open(bfd, asfd, path, flags, S_IRUSR | S_IWUSR)) { berrno be; berrno_init(&be); char msg[256]=""; snprintf(msg, sizeof(msg), "Could not open for writing %s: %s", path, berrno_bstrerror(&be, errno)); if(restore_interrupt(asfd, sb, msg, cntr, protocol)) return OFR_ERROR; return OFR_CONTINUE; } // Add attributes to bfd so that they can be set when it is closed. bfd->winattr=sb->winattr; memcpy(&bfd->statp, &sb->statp, sizeof(struct stat)); return OFR_OK; }
static int send_file(struct asfd *asfd, struct sbuf *sb, int patches, const char *best, uint64_t *bytes, struct cntr *cntr) { int ret=0; static BFILE *bfd=NULL; if(!bfd && !(bfd=bfile_alloc())) return -1; bfile_init(bfd, 0, cntr); if(bfd->open_for_send(bfd, asfd, best, sb->winattr, 1 /* no O_NOATIME */, cntr, PROTO_1)) return -1; //logp("sending: %s\n", best); if(asfd->write(asfd, &sb->path)) ret=-1; else if(patches) { // If we did some patches, the resulting file // is not gzipped. Gzip it during the send. ret=send_whole_file_gzl(asfd, best, sb->protocol1->datapth.buf, 1, bytes, NULL, cntr, 9, bfd, NULL, 0); } else { // If it was encrypted, it may or may not have been compressed // before encryption. Send it as it as, and let the client // sort it out. if(sbuf_is_encrypted(sb)) { ret=send_whole_filel(asfd, sb->path.cmd, best, sb->protocol1->datapth.buf, 1, bytes, cntr, bfd, NULL, 0); } // It might have been stored uncompressed. Gzip it during // the send. If the client knew what kind of file it would be // receiving, this step could disappear. else if(!dpth_protocol1_is_compressed(sb->compression, sb->protocol1->datapth.buf)) { ret=send_whole_file_gzl(asfd, best, sb->protocol1->datapth.buf, 1, bytes, NULL, cntr, 9, bfd, NULL, 0); } else { // If we did not do some patches, the resulting // file might already be gzipped. Send it as it is. ret=send_whole_filel(asfd, sb->path.cmd, best, sb->protocol1->datapth.buf, 1, bytes, cntr, bfd, NULL, 0); } } bfd->close(bfd, asfd); return ret; }
/* These receive_a_file() and send_file() functions are for use by extra_comms and the CA stuff, rather than backups/restores. */ int receive_a_file(struct asfd *asfd, const char *path, struct conf **confs) { int ret=-1; BFILE *bfd=NULL; unsigned long long rcvdbytes=0; unsigned long long sentbytes=0; if(!(bfd=bfile_alloc())) goto end; bfile_init(bfd, 0, confs); #ifdef HAVE_WIN32 bfd->set_win32_api(bfd, 0); #endif if(bfd->open(bfd, asfd, path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR)) { berrno be; berrno_init(&be); logp("Could not open for writing %s: %s\n", path, berrno_bstrerror(&be, errno)); goto end; } ret=transfer_gzfile_in(asfd, path, bfd, &rcvdbytes, &sentbytes, confs); if(bfd->close(bfd, asfd)) { logp("error closing %s in receive_a_file\n", path); goto end; } logp("Received: %s\n", path); ret=0; end: bfd->close(bfd, asfd); bfile_free(&bfd); 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; }
// FIX THIS: Maybe should be in bfile.c. enum ofr_e open_for_restore(struct asfd *asfd, BFILE *bfd, const char *path, struct sbuf *sb, int vss_restore, struct cntr *cntr, enum protocol protocol) { static int flags; if(bfd->mode!=BF_CLOSED) { #ifdef HAVE_WIN32 if(bfd->path && !strcmp(bfd->path, path)) { // Already open after restoring the VSS data. // Time now for the actual file data. return OFR_OK; } else { #endif if(bfd->close(bfd, asfd)) { logp("error closing %s in %s()\n", path, __func__); return OFR_ERROR; } #ifdef HAVE_WIN32 } #endif } #ifdef HAVE_WIN32 // Some massive hacks to work around times that winattr was not // getting set correctly inside server side backups. // The EFS one will stop burp segfaulting when restoring affected // EFS files. if(sb->path.cmd==CMD_EFS_FILE) sb->winattr |= FILE_ATTRIBUTE_ENCRYPTED; if(S_ISDIR(sb->statp.st_mode)) sb->winattr |= FILE_ATTRIBUTE_DIRECTORY; #endif bfile_init(bfd, sb->winattr, cntr); #ifdef HAVE_WIN32 bfd->set_win32_api(bfd, vss_restore); #endif if(S_ISDIR(sb->statp.st_mode)) { // Windows directories are treated as having file data. flags=O_WRONLY|O_BINARY; mkdir(path, 0777); } else flags=O_WRONLY|O_BINARY|O_CREAT|O_TRUNC; if(bfd->open(bfd, asfd, path, flags, S_IRUSR | S_IWUSR)) { berrno be; berrno_init(&be); char msg[256]=""; snprintf(msg, sizeof(msg), "Could not open for writing %s: %s", path, berrno_bstrerror(&be, errno)); if(restore_interrupt(asfd, sb, msg, cntr, protocol)) return OFR_ERROR; return OFR_CONTINUE; } // Add attributes to bfd so that they can be set when it is closed. bfd->winattr=sb->winattr; memcpy(&bfd->statp, &sb->statp, sizeof(struct stat)); return OFR_OK; }
static int do_send_file(struct asfd *asfd, struct sbuf *sb, int patches, const char *best, struct cntr *cntr) { enum send_e ret=SEND_FATAL; struct BFILE bfd; uint64_t bytes=0; // Unused. bfile_init(&bfd, 0, cntr); if(bfd.open_for_send(&bfd, asfd, best, sb->winattr, 1 /* no O_NOATIME */, cntr, PROTO_1)) return SEND_FATAL; if(asfd->write(asfd, &sb->path)) ret=SEND_FATAL; else if(patches) { // If we did some patches, the resulting file // is not gzipped. Gzip it during the send. ret=send_whole_file_gzl( asfd, sb->protocol1->datapth.buf, /*quick_read*/1, &bytes, /*encpassword*/NULL, cntr, /*compression*/9, &bfd, /*extrameta*/NULL, /*elen*/0, /*key_deriv*/ENCRYPTION_UNSET, /*salt*/0 ); } else { // If it was encrypted, it may or may not have been compressed // before encryption. Send it as it as, and let the client // sort it out. if(sbuf_is_encrypted(sb)) { ret=send_whole_filel(asfd, #ifdef HAVE_WIN32 sb->path.cmd #endif sb->protocol1->datapth.buf, 1, &bytes, cntr, &bfd, NULL, 0); } // It might have been stored uncompressed. Gzip it during // the send. If the client knew what kind of file it would be // receiving, this step could disappear. else if(!dpth_protocol1_is_compressed(sb->compression, sb->protocol1->datapth.buf)) { ret=send_whole_file_gzl( asfd, sb->protocol1->datapth.buf, /*quick_read*/1, &bytes, /*encpassword*/NULL, cntr, /*compression*/9, &bfd, /*extrameta*/NULL, /*elen*/0, /*key_deriv*/ENCRYPTION_UNSET, /*salt*/0 ); } else { // If we did not do some patches, the resulting // file might already be gzipped. Send it as it is. ret=send_whole_filel(asfd, #ifdef HAVE_WIN32 sb->path.cmd #endif sb->protocol1->datapth.buf, 1, &bytes, cntr, &bfd, NULL, 0); } } bfd.close(&bfd, asfd); switch(ret) { case SEND_OK: case SEND_ERROR: // Carry on. return 0; case SEND_FATAL: default: return -1; } }