📄 restore.c
字号:
cur_find_res->next = sorted_files; sorted_files = cur_find_res; } sort_find_result("hkdlp", &sorted_files); /* now we have an in-order list of the files we need to concatenate */ cur_find_res = sorted_files; for(cur_find_res=sorted_files; cur_find_res; cur_find_res=cur_find_res->next){ dumpfile_t *cur_file = NULL; cur_out = (open_output_t*)cur_find_res->user_ptr; cur_file = cur_out->file; /* if we requested a particular file, do only that one */ if(only_file && !headers_equal(cur_file, only_file, 1)){ continue; } if(cur_file->type == F_SPLIT_DUMPFILE) { /* is it a continuation of one we've been writing? */ if(main_file && cur_file->partnum > lastpartnum && headers_equal(cur_file, main_file, 1)){ char *cur_filename; char *main_filename; /* effectively changing filehandles */ aclose(cur_out->outfd); cur_out->outfd = outfd; cur_filename = make_filename(cur_file); main_filename = make_filename(main_file); g_fprintf(stderr, _("Merging %s with %s\n"), cur_filename, main_filename); append_file_to_fd(cur_filename, outfd); if(unlink(cur_filename) < 0){ g_fprintf(stderr, _("Failed to unlink %s: %s\n"), cur_filename, strerror(errno)); } amfree(cur_filename); amfree(main_filename); } /* or a new file? */ else { if(outfd >= 0) aclose(outfd); amfree(main_file); main_file = alloc(SIZEOF(dumpfile_t)); memcpy(main_file, cur_file, SIZEOF(dumpfile_t)); outfd = cur_out->outfd; if(outfd < 0) { char *cur_filename = make_filename(cur_file); open(cur_filename, O_RDWR|O_APPEND); if (outfd < 0) { error(_("Couldn't open %s for appending: %s"), cur_filename, strerror(errno)); /*NOTREACHED*/ } amfree(cur_filename); } } lastpartnum = cur_file->partnum; } else { aclose(cur_out->outfd); } } if(outfd >= 0) { aclose(outfd); } amfree(main_file); free_find_result(&sorted_files); } /* * Now that the split dump closure is done, free up resources we don't * need anymore. */ for(cur_out=open_outputs; cur_out; cur_out=cur_out->next){ dumpfile_t *cur_file = NULL; amfree(prev); cur_file = cur_out->file; /* if we requested a particular file, do only that one */ if(only_file && !headers_equal(cur_file, only_file, 1)){ continue; } if(!reassemble) { aclose(cur_out->outfd); } if(cur_out->comp_enc_pid > 0){ waitpid(cur_out->comp_enc_pid, &compress_status, 0); } amfree(cur_out->file); prev = cur_out; } open_outputs = NULL;}/* * Turn a fileheader into a string suited for use on the filesystem. */char *make_filename( dumpfile_t *file){ char number[NUM_STR_SIZE]; char part[NUM_STR_SIZE]; char totalparts[NUM_STR_SIZE]; char *sfn = NULL; char *fn = NULL; char *pad = NULL; size_t padlen = 0; g_snprintf(number, SIZEOF(number), "%d", file->dumplevel); g_snprintf(part, SIZEOF(part), "%d", file->partnum); if(file->totalparts < 0) { g_snprintf(totalparts, SIZEOF(totalparts), "UNKNOWN"); } else { g_snprintf(totalparts, SIZEOF(totalparts), "%d", file->totalparts); } padlen = strlen(totalparts) + 1 - strlen(part); pad = alloc(padlen); memset(pad, '0', padlen); pad[padlen - 1] = '\0'; g_snprintf(part, SIZEOF(part), "%s%d", pad, file->partnum); sfn = sanitise_filename(file->disk); fn = vstralloc(file->name, ".", sfn, ".", file->datestamp, ".", number, NULL); if (file->partnum > 0) { vstrextend(&fn, ".", part, NULL); } amfree(sfn); amfree(pad); return fn;}/* Returns 1 if the dump file matches the hostname and diskname * regular expressions given on the command line, 0 otherwise. As a * special case, empty regexs and NULLs are considered equivalent to * ".*": they match everything. * * @param file: the file to examine * @param datestamp: the datestamp regex, or NULL for any * @param hostname: the hostname regex, or NULL for any * @param diskname: the diskname regex, or NULL for any * @param level: the level regex, or NULL for any * @returns: 1 if the dump file matches */static intdisk_match( dumpfile_t *file, char * datestamp, char * hostname, char * diskname, char * level){ char level_str[NUM_STR_SIZE]; g_snprintf(level_str, SIZEOF(level_str), "%d", file->dumplevel); if(file->type != F_DUMPFILE && file->type != F_SPLIT_DUMPFILE) return 0; if((!hostname || *hostname == '\0' || match_host(hostname, file->name)) && (!diskname || *diskname == '\0' || match_disk(diskname, file->disk)) && (!datestamp || *datestamp == '\0' || match_datestamp(datestamp, file->datestamp)) && (!level || *level == '\0' || match_level(level, level_str))) return 1; else return 0;}/* * Reads the first block of a holding disk file. */static gbooleanread_holding_disk_header( dumpfile_t * file, int tapefd, rst_flags_t * flags){ ssize_t bytes_read; char *buffer; size_t blocksize; if(flags->blocksize > 0) blocksize = (size_t)flags->blocksize; else blocksize = DISK_BLOCK_BYTES; buffer = alloc(blocksize); bytes_read = fullread(tapefd, buffer, blocksize); if(bytes_read < 0) { g_fprintf(stderr, _("%s: error reading file header: %s\n"), get_pname(), strerror(errno)); file->type = F_UNKNOWN; } else if((size_t)bytes_read < DISK_BLOCK_BYTES) { if(bytes_read == 0) { g_fprintf(stderr, _("%s: missing file header block\n"), get_pname()); } else { g_fprintf(stderr, plural(_("%s: short file header block: %zd byte"), _("%s: short file header block: %zd bytes\n"), bytes_read), get_pname(), (size_t)bytes_read); } file->type = F_UNKNOWN; } else { parse_file_header(buffer, file, (size_t)bytes_read); } amfree(buffer); return (file->type != F_UNKNOWN && file->type != F_EMPTY && file->type != F_WEIRD);}/* * Restore the current file from tape. Depending on the settings of * the command line flags, the file might need to be compressed or * uncompressed. If so, a pipe through compress or uncompress is set * up. The final output usually goes to a file named host.disk.date.lev, * but with the -p flag the output goes to stdout (and presumably is * piped to restore). *//* FIXME: Mondo function that needs refactoring. */void restore(RestoreSource * source, rst_flags_t * flags){ int dest = -1, out; int file_is_compressed; int is_continuation = 0; int check_for_aborted = 0; char *tmp_filename = NULL, *final_filename = NULL; struct stat statinfo; open_output_t *myout = NULL, *oldout = NULL; dumplist_t *tempdump = NULL, *fileentry = NULL; char *buffer; int need_compress=0, need_uncompress=0, need_decrypt=0; int stage=0; struct pipeline { int pipe[2]; } pipes[3]; char * filename; filename = make_filename(source->header); memset(pipes, -1, SIZEOF(pipes)); if(already_have_dump(source->header)){ g_fprintf(stderr, _(" *** Duplicate file %s, one is probably an aborted write\n"), filename); check_for_aborted = 1; } /* store a shorthand record of this dump */ tempdump = malloc(SIZEOF(dumplist_t)); tempdump->file = malloc(SIZEOF(dumpfile_t)); tempdump->next = NULL; memcpy(tempdump->file, source->header, SIZEOF(dumpfile_t)); /* * If we're appending chunked files to one another, and if this is a * continuation of a file we just restored, and we've still got the * output handle from that previous restore, we're golden. Phew. */ if(flags->inline_assemble && source->header->type == F_SPLIT_DUMPFILE){ myout = open_outputs; while(myout != NULL){ if(myout->file->type == F_SPLIT_DUMPFILE && headers_equal(source->header, myout->file, 1)){ if(source->header->partnum == myout->lastpartnum + 1){ is_continuation = 1; break; } } myout = myout->next; } if(myout != NULL) myout->lastpartnum = source->header->partnum; else if(source->header->partnum != 1){ g_fprintf(stderr, _("%s: Chunk out of order, will save to disk and append to output.\n"), get_pname()); flags->pipe_to_fd = -1; flags->compress = 0; flags->leave_comp = 1; } if(myout == NULL){ myout = alloc(SIZEOF(open_output_t)); memset(myout, 0, SIZEOF(open_output_t)); } } else{ myout = alloc(SIZEOF(open_output_t)); memset(myout, 0, SIZEOF(open_output_t)); } if(is_continuation && flags->pipe_to_fd == -1){ char *filename; filename = make_filename(myout->file); g_fprintf(stderr, _("%s: appending to %s\n"), get_pname(), filename); amfree(filename); } /* adjust compression flag */ file_is_compressed = source->header->compressed; if(!flags->compress && file_is_compressed && !known_compress_type(source->header)) { g_fprintf(stderr, _("%s: unknown compression suffix %s, can't uncompress\n"), get_pname(), source->header->comp_suffix); flags->compress = 1; } /* set up final destination file */ if(is_continuation && myout != NULL) { out = myout->outfd; } else { if(flags->pipe_to_fd != -1) { dest = flags->pipe_to_fd; } else { char *filename_ext = NULL; if(flags->compress) { filename_ext = file_is_compressed ? source->header->comp_suffix : COMPRESS_SUFFIX; } else if(flags->raw) { filename_ext = ".RAW"; } else { filename_ext = ""; } filename_ext = stralloc2(filename, filename_ext); tmp_filename = stralloc(filename_ext); if(flags->restore_dir != NULL) { char *tmpstr = vstralloc(flags->restore_dir, "/", tmp_filename, NULL); amfree(tmp_filename); tmp_filename = tmpstr; } final_filename = tmp_filename; tmp_filename = vstralloc(final_filename, ".tmp", NULL); if((dest = open(tmp_filename, (O_CREAT | O_RDWR | O_TRUNC), CREAT_MODE)) < 0) { error(_("could not create output file %s: %s"), tmp_filename, strerror(errno)); /*NOTREACHED*/ } amfree(filename_ext); } out = dest; } /* * If -r or -h, write the header before compress or uncompress pipe. * Only write DISK_BLOCK_BYTES, regardless of how much was read. * This makes the output look like a holding disk image, and also * makes it easier to remove the header (e.g. in amrecover) since * it has a fixed size. */ if(flags->raw || (flags->headers && !is_continuation)) { ssize_t w; dumpfile_t tmp_hdr; if(flags->compress && !file_is_compressed) { source->header->compressed = 1; g_snprintf(source->header->uncompress_cmd, SIZEOF(source->header->uncompress_cmd), " %s %s |", UNCOMPRESS_PATH,#ifdef UNCOMPRESS_OPT UNCOMPRESS_OPT#else ""#endif ); strncpy(source->header->comp_suffix, COMPRESS_SUFFIX, SIZEOF(source->header->comp_suffix)-1); source->header->comp_suffix[SIZEOF(source->header->comp_suffix)-1] = '\0'; } memcpy(&tmp_hdr, source->header, SIZEOF(dumpfile_t)); /* remove CONT_FILENAME from header */ memset(source->header->cont_filename, '\0', SIZEOF(source->header->cont_filename)); source->header->blocksize = DISK_BLOCK_BYTES; /* * Dumb down split file headers as well, so that older versions of * things like amrecover won't gag on them. */ if(source->header->type == F_SPLIT_DUMPFILE && flags->mask_splits){ source->header->type = F_DUMPFILE; } buffer = alloc(DISK_BLOCK_BYTES); buffer = build_header(source->header, DISK_BLOCK_BYTES); if((w = fullwrite(out, buffer, DISK_BLOCK_BYTES)) != DISK_BLOCK_BYTES) { if(w < 0) { error(_("write error: %s"), strerror(errno)); /*NOTREACHED*/ } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -