static int send_file(const char *fname, int patches, const char *best, const char *datapth, unsigned long long *bytes, char cmd, int64_t winattr, int compression, struct cntr *cntr, struct config *cconf) { int ret=0; size_t datalen=0; FILE *fp=NULL; if(open_file_for_send(NULL, &fp, best, winattr, &datalen, cntr)) return -1; //logp("sending: %s\n", best); if(async_write(cmd, fname, strlen(fname))) 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_gz(best, datapth, 1, bytes, NULL, cntr, 9, NULL, fp, NULL, 0, -1); } 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(cmd==CMD_ENC_FILE || cmd==CMD_ENC_METADATA || cmd==CMD_ENC_VSS || cmd==CMD_ENC_VSS_T || cmd==CMD_EFS_FILE) { ret=send_whole_file(cmd, best, datapth, 1, bytes, cntr, NULL, fp, NULL, 0, -1); } // 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_is_compressed(compression, datapth)) { ret=send_whole_file_gz(best, datapth, 1, bytes, NULL, cntr, 9, NULL, fp, NULL, 0, -1); } else { // If we did not do some patches, the resulting // file might already be gzipped. Send it as it is. ret=send_whole_file(cmd, best, datapth, 1, bytes, cntr, NULL, fp, NULL, 0, -1); } } close_file_for_send(NULL, &fp); return ret; }
/* Windows will use this function, when sending a certificate signing request. It is not using the Windows API stuff because it needs to arrive on the server side without any junk in it. */ int send_a_file(const char *path, struct cntr *p1cntr) { int ret=0; FILE *fp=NULL; unsigned long long bytes=0; if(open_file_for_send(NULL, &fp, path, 0, p1cntr) || send_whole_file_gz(path, "datapth", 0, &bytes, NULL, p1cntr, 9, // compression NULL, fp, NULL, 0)) { ret=-1; goto end; } logp("Sent %s\n", path); end: close_file_for_send(NULL, &fp); return ret; }
static int do_backup_phase2_client(struct config *conf, int resume, struct cntr *p1cntr, struct cntr *cntr) { int ret=0; int quit=0; char cmd; char *buf=NULL; size_t len=0; char attribs[MAXSTRING]; // For efficiency, open Windows files for the VSS data, and do not // close them until another time around the loop, when the actual // data is read. BFILE bfd; // Windows VSS headers tell us how much file // data to expect. size_t datalen=0; #ifdef HAVE_WIN32 binit(&bfd, 0); #endif struct sbuf sb; init_sbuf(&sb); if(!resume) { // Only do this bit if the server did not tell us to resume. if(async_write_str(CMD_GEN, "backupphase2") || async_read_expect(CMD_GEN, "ok")) return -1; } else if(conf->send_client_counters) { // On resume, the server might update the client with the // counters. if(recv_counters(p1cntr, cntr)) return -1; } while(!quit) { if(async_read(&cmd, &buf, &len)) { ret=-1; quit++; } else if(buf) { //logp("now: %c:%s\n", cmd, buf); if(cmd==CMD_DATAPTH) { sb.datapth=buf; buf=NULL; continue; } else if(cmd==CMD_STAT) { // Ignore the stat data - we will fill it // in again. Some time may have passed by now, // and it is best to make it as fresh as // possible. free(buf); buf=NULL; continue; } else if(cmd==CMD_FILE || cmd==CMD_ENC_FILE || cmd==CMD_METADATA || cmd==CMD_ENC_METADATA || cmd==CMD_VSS || cmd==CMD_ENC_VSS || cmd==CMD_VSS_T || cmd==CMD_ENC_VSS_T || cmd==CMD_EFS_FILE) { int forget=0; int64_t winattr=0; struct stat statbuf; char *extrameta=NULL; size_t elen=0; unsigned long long bytes=0; FILE *fp=NULL; int compression=conf->compression; sb.path=buf; buf=NULL; #ifdef HAVE_WIN32 if(win32_lstat(sb.path, &statbuf, &winattr)) #else if(lstat(sb.path, &statbuf)) #endif { logw(cntr, "Path has vanished: %s", sb.path); if(forget_file(&sb, cmd, cntr)) { ret=-1; quit++; } free_sbuf(&sb); continue; } if(conf->min_file_size && statbuf.st_size< (boffset_t)conf->min_file_size && (cmd==CMD_FILE || cmd==CMD_ENC_FILE || cmd==CMD_EFS_FILE)) { logw(cntr, "File size decreased below min_file_size after initial scan: %c:%s", cmd, sb.path); forget++; } else if(conf->max_file_size && statbuf.st_size> (boffset_t)conf->max_file_size && (cmd==CMD_FILE || cmd==CMD_ENC_FILE || cmd==CMD_EFS_FILE)) { logw(cntr, "File size increased above max_file_size after initial scan: %c:%s", cmd, sb.path); forget++; } if(!forget) { compression=in_exclude_comp(conf->excom, conf->excmcount, sb.path, conf->compression); encode_stat(attribs, &statbuf, winattr, compression); if(open_file_for_send( #ifdef HAVE_WIN32 &bfd, NULL, #else NULL, &fp, #endif sb.path, winattr, &datalen, cntr)) forget++; } if(forget) { if(forget_file(&sb, cmd, cntr)) { ret=-1; quit++; } free_sbuf(&sb); continue; } if(cmd==CMD_METADATA || cmd==CMD_ENC_METADATA || cmd==CMD_VSS || cmd==CMD_ENC_VSS #ifdef HAVE_WIN32 || conf->strip_vss #endif ) { if(get_extrameta( #ifdef HAVE_WIN32 &bfd, #else NULL, #endif sb.path, &statbuf, &extrameta, &elen, winattr, cntr, &datalen)) { logw(cntr, "Meta data error for %s", sb.path); free_sbuf(&sb); close_file_for_send(&bfd, &fp); continue; } if(extrameta) { #ifdef HAVE_WIN32 if(conf->strip_vss) { free(extrameta); extrameta=NULL; elen=0; } #endif } else { logw(cntr, "No meta data after all: %s", sb.path); free_sbuf(&sb); close_file_for_send(&bfd, &fp); continue; } } if(cmd==CMD_FILE && sb.datapth) { unsigned long long sentbytes=0; // Need to do sig/delta stuff. if(async_write_str(CMD_DATAPTH, sb.datapth) || async_write_str(CMD_STAT, attribs) || async_write_str(CMD_FILE, sb.path) || load_signature_and_send_delta( &bfd, fp, &bytes, &sentbytes, cntr, datalen)) { logp("error in sig/delta for %s (%s)\n", sb.path, sb.datapth); ret=-1; quit++; } else { do_filecounter(cntr, CMD_FILE_CHANGED, 1); do_filecounter_bytes(cntr, bytes); do_filecounter_sentbytes(cntr, sentbytes); } } else { //logp("need to send whole file: %s\n", // sb.path); // send the whole file. if((async_write_str(CMD_STAT, attribs) || async_write_str(cmd, sb.path)) || send_whole_file_w(cmd, sb.path, NULL, 0, &bytes, conf->encryption_password, cntr, compression, &bfd, fp, extrameta, elen, datalen)) { ret=-1; quit++; } else { do_filecounter(cntr, cmd, 1); do_filecounter_bytes(cntr, bytes); do_filecounter_sentbytes(cntr, bytes); } } #ifdef HAVE_WIN32 // If using Windows do not close bfd - it needs // to stay open to read VSS/file data/VSS. // It will get closed either when given a // different file path, or when this function // exits. //if(cmd!=CMD_VSS // && cmd!=CMD_ENC_VSS) // close_file_for_send(&bfd, NULL); #else close_file_for_send(NULL, &fp); #endif free_sbuf(&sb); if(extrameta) free(extrameta); } else if(cmd==CMD_WARNING) { do_filecounter(cntr, cmd, 0); free(buf); buf=NULL; } else if(cmd==CMD_GEN && !strcmp(buf, "backupphase2end")) { if(async_write_str(CMD_GEN, "okbackupphase2end")) ret=-1; quit++; } else { logp("unexpected cmd from server: %c %s\n", cmd, buf); ret=-1; quit++; free(buf); buf=NULL; } } } #ifdef HAVE_WIN32 // It is possible for a bfd to still be open. close_file_for_send(&bfd, NULL); #endif return ret; }
static int do_backup_phase2_client(struct config *conf, int resume, struct cntr *cntr) { int ret=0; int quit=0; char cmd; char *buf=NULL; size_t len=0; char attribs[MAXSTRING]; struct sbuf sb; init_sbuf(&sb); if(!resume) { // Only do this bit if the server did not tell us to resume. if(async_write_str(CMD_GEN, "backupphase2") || async_read_expect(CMD_GEN, "ok")) return -1; } while(!quit) { if(async_read(&cmd, &buf, &len)) { ret=-1; quit++; } else if(buf) { //logp("now: %c:%s\n", cmd, buf); if(cmd==CMD_DATAPTH) { sb.datapth=buf; buf=NULL; continue; } else if(cmd==CMD_STAT) { // Ignore the stat data - we will fill it // in again. Some time may have passed by now, // and it is best to make it as fresh as // possible. free(buf); buf=NULL; continue; } else if(cmd==CMD_FILE || cmd==CMD_ENC_FILE || cmd==CMD_METADATA || cmd==CMD_ENC_METADATA || cmd==CMD_EFS_FILE) { int forget=0; int64_t winattr=0; struct stat statbuf; char *extrameta=NULL; size_t elen=0; unsigned long long bytes=0; BFILE bfd; FILE *fp=NULL; sb.path=buf; buf=NULL; #ifdef HAVE_WIN32 if(win32_lstat(sb.path, &statbuf, &winattr)) #else if(lstat(sb.path, &statbuf)) #endif { logw(cntr, "Path has vanished: %s", sb.path); if(forget_file(&sb, cmd, cntr)) { ret=-1; quit++; } free_sbuf(&sb); continue; } if(conf->min_file_size && statbuf.st_size<(boffset_t)conf->min_file_size) { logw(cntr, "File size decreased below min_file_size after initial scan: %s", sb.path); forget++; } else if(conf->max_file_size && statbuf.st_size>(boffset_t)conf->max_file_size) { logw(cntr, "File size increased above max_file_size after initial scan: %s", sb.path); forget++; } if(!forget) { encode_stat(attribs, &statbuf, winattr); if(open_file_for_send(&bfd, &fp, sb.path, winattr, cntr)) forget++; } if(forget) { if(forget_file(&sb, cmd, cntr)) { ret=-1; quit++; } free_sbuf(&sb); continue; } if(cmd==CMD_METADATA || cmd==CMD_ENC_METADATA) { if(get_extrameta(sb.path, &statbuf, &extrameta, &elen, cntr)) { logw(cntr, "Meta data error for %s", sb.path); free_sbuf(&sb); close_file_for_send(&bfd, &fp); continue; } if(!extrameta) { logw(cntr, "No meta data after all: %s", sb.path); free_sbuf(&sb); close_file_for_send(&bfd, &fp); continue; } } if(cmd==CMD_FILE && sb.datapth) { unsigned long long sentbytes=0; // Need to do sig/delta stuff. if(async_write_str(CMD_DATAPTH, sb.datapth) || async_write_str(CMD_STAT, attribs) || async_write_str(CMD_FILE, sb.path) || load_signature_and_send_delta( &bfd, fp, &bytes, &sentbytes, cntr)) { logp("error in sig/delta for %s (%s)\n", sb.path, sb.datapth); ret=-1; quit++; } else { do_filecounter(cntr, CMD_FILE_CHANGED, 1); do_filecounter_bytes(cntr, bytes); do_filecounter_sentbytes(cntr, sentbytes); } } else { //logp("need to send whole file: %s\n", // sb.path); // send the whole file. if(async_write_str(CMD_STAT, attribs) || async_write_str(cmd, sb.path) || send_whole_file_w(cmd, sb.path, NULL, 0, &bytes, conf->encryption_password, cntr, conf->compression, &bfd, fp, extrameta, elen)) { ret=-1; quit++; } else { do_filecounter(cntr, cmd, 1); do_filecounter_bytes(cntr, bytes); do_filecounter_sentbytes(cntr, bytes); } } close_file_for_send(&bfd, &fp); free_sbuf(&sb); if(extrameta) free(extrameta); } else if(cmd==CMD_WARNING) { do_filecounter(cntr, cmd, 0); free(buf); buf=NULL; } else if(cmd==CMD_GEN && !strcmp(buf, "backupphase2end")) { if(async_write_str(CMD_GEN, "okbackupphase2end")) ret=-1; quit++; } else { logp("unexpected cmd from server: %c %s\n", cmd, buf); ret=-1; quit++; free(buf); buf=NULL; } } } return ret; }