static int restore_ent(const char *client, struct sbuf *sb, struct sbuf ***sblist, int *scount, struct bu *arr, int a, int i, const char *tmppath1, const char *tmppath2, enum action act, char status, struct config *cconf, struct cntr *cntr, struct cntr *p1cntr) { int s=0; int ret=0; // Check if we have any directories waiting to be restored. for(s=(*scount)-1; s>=0; s--) { if(is_subdir((*sblist)[s]->path, sb->path)) { // We are still in a subdir. //printf(" subdir (%s %s)\n", // (*sblist)[s]->path, sb->path); break; } else { // Can now restore sblist[s] because nothing else is // fiddling in a subdirectory. if(restore_sbuf((*sblist)[s], arr, a, i, tmppath1, tmppath2, act, client, status, p1cntr, cntr, cconf)) { ret=-1; break; } else if(del_from_sbuf_arr(sblist, scount)) { ret=-1; break; } } } /* If it is a directory, need to remember it and restore it later, so that the permissions come out right. */ /* Meta data of directories will also have the stat stuff set to be a directory, so will also come out at the end. */ if(!ret && S_ISDIR(sb->statp.st_mode)) { if(add_to_sbuf_arr(sblist, sb, scount)) ret=-1; // Wipe out sb, without freeing up all the strings inside it, // which have been added to sblist. init_sbuf(sb); } else if(!ret && restore_sbuf(sb, arr, a, i, tmppath1, tmppath2, act, client, status, p1cntr, cntr, cconf)) ret=-1; return ret; }
static int restore_remaining_dirs(struct asfd *asfd, struct slist *slist, enum action act, enum cstat_status status, struct conf *conf, int *need_data) { struct sbuf *sb; // Restore any directories that are left in the list. for(sb=slist->head; sb; sb=sb->next) { //printf("remaining dir: %s\n", sb->path.buf); if(restore_sbuf(asfd, sb, act, status, conf, need_data)) return -1; } return 0; }
// 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; }
static int restore_ent(struct asfd *asfd, struct sbuf **sb, struct slist *slist, enum action act, enum cstat_status status, struct conf *conf, int *need_data, int *last_ent_was_dir) { int ret=-1; struct sbuf *xb; if(!(*sb)->path.buf) { logp("Got NULL path!\n"); return -1; } //printf("want to restore: %s\n", (*sb)->path.buf); // Check if we have any directories waiting to be restored. while((xb=slist->head)) { if(is_subdir(xb->path.buf, (*sb)->path.buf)) { // We are still in a subdir. break; } else { //printf("do dir: %s\n", xb->path.buf); // Can now restore because nothing else is // fiddling in a subdirectory. if(restore_sbuf(asfd, xb, act, status, conf, need_data)) goto end; slist->head=xb->next; sbuf_free(&xb); } } // If it is a directory, need to remember it and restore it later, so // that the permissions come out right. // Meta data of directories will also have the stat stuff set to be a // directory, so will also come out at the end. // FIX THIS: for Windows, need to read and remember the blocks that // go with the directories. Probably have to do the same for metadata // that goes with directories. if(S_ISDIR((*sb)->statp.st_mode)) { // Add to the head of the list instead of the tail. (*sb)->next=slist->head; slist->head=*sb; *last_ent_was_dir=1; // Allocate a new sb. if(!(*sb=sbuf_alloc(conf))) goto end; } else { *last_ent_was_dir=0; if(restore_sbuf(asfd, *sb, act, status, conf, need_data)) goto end; } ret=0; end: 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, enum action act, const char *client, struct cntr *p1cntr, struct cntr *cntr, struct config *cconf, bool all) { 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("out of memory"); ret=-1; } else if(!(logfp=open_file(logpath, "ab")) || set_logfp(logfp)) { char msg[256]=""; snprintf(msg, sizeof(msg), "could not open log file: %s", logpath); log_and_send(msg); ret=-1; } else if(!(zp=gzopen_file(manifest, "rb"))) { log_and_send("could not open manifest"); ret=-1; } else { char cmd; int quit=0; size_t len=0; struct sbuf sb; // For out-of-sequence directory restoring so that the // timestamps come out right: int s=0; 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(check_regex(regex, sb.path)) { // Check if we have any directories waiting // to be restored. for(s=scount-1; s>=0; s--) { if(is_subdir(sblist[s]->path, sb.path)) { // We are still in a subdir. //printf(" subdir (%s %s)\n", sblist[s]->path, sb.path); break; } else { // Can now restore sblist[s] // because nothing else is // fiddling in a subdirectory. if(restore_sbuf(sblist[s], arr, a, i, tmppath1, tmppath2, act, client, status, p1cntr, cntr, cconf)) { ret=-1; quit++; break; } else if(del_from_sbuf_arr( &sblist, &scount)) { ret=-1; quit++; break; } } } /* If it is a directory, need to remember it and restore it later, so that the permissions come out right. */ /* Meta data of directories will also have the stat stuff set to be a directory, so will also come out at the end. */ if(!ret && S_ISDIR(sb.statp.st_mode)) { if(add_to_sbuf_arr(&sblist, &sb, &scount)) { ret=-1; quit++; } // Wipe out sb, without freeing up // all the strings inside it, which // have been added to sblist. init_sbuf(&sb); } else if(!ret && restore_sbuf(&sb, arr, a, i, tmppath1, tmppath2, act, client, status, p1cntr, cntr, cconf)) { 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 && !all) ret=do_restore_end(act, cntr); print_endcounter(cntr); print_filecounters(p1cntr, cntr, act, 0); reset_filecounter(p1cntr); reset_filecounter(cntr); } set_logfp(NULL); compress_file(logpath, logpathz, cconf); if(manifest) free(manifest); if(datadir) free(datadir); if(logpath) free(logpath); if(logpathz) free(logpathz); return ret; }
int restore_ent(struct asfd *asfd, struct sbuf **sb, struct slist *slist, struct bu *bu, enum action act, struct sdirs *sdirs, enum cntr_status cntr_status, struct conf **cconfs, struct sbuf *need_data, int *last_ent_was_dir, const char *manifest) { int ret=-1; struct sbuf *xb; if(!(*sb)->path.buf) { logp("Got NULL path!\n"); return -1; } // Check if we have any directories waiting to be restored. while((xb=slist->head)) { if(is_subdir(xb->path.buf, (*sb)->path.buf)) { // We are still in a subdir. break; } else { // Can now restore xb because nothing else is fiddling // in a subdirectory. if(restore_sbuf(asfd, xb, bu, act, sdirs, cntr_status, cconfs, need_data, manifest, slist)) goto end; slist->head=xb->next; sbuf_free(&xb); } } /* If it is a directory, need to remember it and restore it later, so that the permissions come out right. */ /* Meta data of directories will also have the stat stuff set to be a directory, so will also come out at the end. */ /* FIX THIS: for Windows, need to read and remember the blocks that go with the directories. Probably have to do the same for metadata that goes with directories. */ if(S_ISDIR((*sb)->statp.st_mode)) { // Add to the head of the list instead of the tail. (*sb)->next=slist->head; slist->head=*sb; *last_ent_was_dir=1; // Allocate a new sb. if(!(*sb=sbuf_alloc(get_protocol(cconfs)))) goto end; } else { *last_ent_was_dir=0; if(restore_sbuf(asfd, *sb, bu, act, sdirs, cntr_status, cconfs, need_data, manifest, slist)) goto end; } ret=0; end: return ret; }
// Used when restoring a hard link that we have not restored the destination // for. Read through the manifest from the beginning and substitute the path // and data to the new location. static int hard_link_substitution(struct asfd *asfd, struct sbuf *sb, struct f_link *lp, struct bu *bu, enum action act, struct sdirs *sdirs, enum cntr_status cntr_status, struct conf **cconfs, const char *manifest, struct slist *slist) { int ret=-1; struct sbuf *need_data=NULL; int last_ent_was_dir=0; struct sbuf *hb=NULL; struct manio *manio=NULL; struct blk *blk=NULL; int pcmp; enum protocol protocol=get_protocol(cconfs); struct cntr *cntr=get_cntr(cconfs); if(!(manio=manio_open(manifest, "rb", protocol)) || !(need_data=sbuf_alloc(protocol)) || !(hb=sbuf_alloc(protocol))) goto end; if(protocol==PROTO_2) { if(!(blk=blk_alloc())) goto end; } while(1) { switch(manio_read_with_blk(manio, hb, need_data->path.buf?blk:NULL, sdirs)) { case 0: break; // Keep going. case 1: ret=0; goto end; // Finished OK. default: goto end; // Error; } if(protocol==PROTO_2) { if(hb->endfile.buf) { sbuf_free_content(hb); continue; } if(blk->data) { if(protocol2_extra_restore_stream_bits(asfd, blk, slist, act, need_data, last_ent_was_dir, cntr)) goto end; continue; } sbuf_free_content(need_data); } pcmp=pathcmp(lp->name, hb->path.buf); if(!pcmp && (sbuf_is_filedata(hb) || sbuf_is_vssdata(hb))) { // Copy the path from sb to hb. free_w(&hb->path.buf); if(!(hb->path.buf=strdup_w(sb->path.buf, __func__))) goto end; // Should now be able to restore the original data // to the new location. ret=restore_sbuf(asfd, hb, bu, act, sdirs, cntr_status, cconfs, need_data, manifest, slist); // May still need to get protocol2 data. if(!ret && need_data->path.buf) continue; break; } sbuf_free_content(hb); // Break out once we have gone past the entry that we are // interested in. if(pcmp<0) break; } end: blk_free(&blk); sbuf_free(&hb); manio_close(&manio); return ret; }