📄 xdelta3-main.h
字号:
static char* ext_tmpfile = NULL;/* Like write(), but makes repeated calls to empty the buffer. */static intmain_pipe_write (int outfd, uint8_t *exist_buf, usize_t remain){ int ret; if ((ret = xd3_posix_io (outfd, exist_buf, remain, (xd3_posix_func*) &write, NULL))) { XPR(NT "pipe write failed: %s", xd3_mainerror (ret)); return ret; } return 0;}/* A simple error-reporting waitpid interface. */static intmain_waitpid_check(pid_t pid){ int status; int ret = 0; if (waitpid (pid, & status, 0) < 0) { ret = get_errno (); XPR(NT "compression subprocess: wait: %s\n", xd3_mainerror (ret)); } else if (! WIFEXITED (status)) { ret = ECHILD; XPR(NT "compression subprocess: signal %d\n", WIFSIGNALED (status) ? WTERMSIG (status) : WSTOPSIG (status)); } else if (WEXITSTATUS (status) != 0) { ret = ECHILD; XPR(NT "compression subprocess: exit %d\n", WEXITSTATUS (status)); } return ret;}/* Wait for any existing child processes to check for abnormal exit. */static intmain_external_compression_finish (void){ int i; int ret; for (i = 0; i < 2; i += 1) { if (! ext_subprocs[i]) { continue; } if ((ret = main_waitpid_check (ext_subprocs[i]))) { return ret; } } return 0;}/* This runs as a forked process of main_input_decompress_setup() to * copy input to the decompression process. First, the available * input is copied out of the existing buffer, then the buffer is * reused to continue reading from the compressed input file. */static intmain_pipe_copier (uint8_t *pipe_buf, usize_t pipe_bufsize, usize_t nread, main_file *ifile, int outfd){ int ret; for (;;) { if (nread > 0 && (ret = main_pipe_write (outfd, pipe_buf, nread))) { return ret; } if (nread < pipe_bufsize) { break; } if ((ret = main_file_read (ifile, pipe_buf, pipe_bufsize, & nread, "pipe read failed")) < 0) { return ret; } } return 0;}/* This function is called after we have read some amount of data from * the input file and detected a compressed input. Here we start a * decompression subprocess by forking twice. The first process runs * the decompression command, the second process copies data to the * input of the first. */static intmain_input_decompress_setup (const main_extcomp *decomp, main_file *ifile, uint8_t *input_buf, usize_t input_bufsize, uint8_t *pipe_buf, usize_t pipe_bufsize, usize_t pipe_avail, usize_t *nread){ /* The two pipes: input and output file descriptors. */ int outpipefd[2], inpipefd[2]; int input_fd = -1; /* The resulting input_fd (output of decompression). */ pid_t decomp_id, copier_id; /* The two subprocs. */ int ret; outpipefd[0] = outpipefd[1] = -1; inpipefd[0] = inpipefd[1] = -1; if (pipe (outpipefd) || pipe (inpipefd)) { XPR(NT "pipe failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } if ((decomp_id = fork ()) < 0) { XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } /* The first child runs the decompression process: */ if (decomp_id == 0) { /* Setup pipes: write to the outpipe, read from the inpipe. */ if (dup2 (outpipefd[PIPE_WRITE_FD], STDOUT_FILENO) < 0 || dup2 (inpipefd[PIPE_READ_FD], STDIN_FILENO) < 0 || close (outpipefd[PIPE_READ_FD]) || close (outpipefd[PIPE_WRITE_FD]) || close (inpipefd[PIPE_READ_FD]) || close (inpipefd[PIPE_WRITE_FD]) || execlp (decomp->decomp_cmdname, decomp->decomp_cmdname, decomp->decomp_options, NULL)) { XPR(NT "child process %s failed to execute: %s\n", decomp->decomp_cmdname, xd3_mainerror (get_errno ())); } _exit (127); } ext_subprocs[0] = decomp_id; if ((copier_id = fork ()) < 0) { XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } /* The second child runs the copier process: */ if (copier_id == 0) { int exitval = 0; if (close (inpipefd[PIPE_READ_FD]) || main_pipe_copier (pipe_buf, pipe_bufsize, pipe_avail, ifile, inpipefd[PIPE_WRITE_FD]) || close (inpipefd[PIPE_WRITE_FD])) { XPR(NT "child copier process failed: %s\n", xd3_mainerror (get_errno ())); exitval = 1; } _exit (exitval); } ext_subprocs[1] = copier_id; /* The parent closes both pipes after duplicating the output of * compression. */ input_fd = dup (outpipefd[PIPE_READ_FD]); if (input_fd < 0 || main_file_close (ifile) || close (outpipefd[PIPE_READ_FD]) || close (outpipefd[PIPE_WRITE_FD]) || close (inpipefd[PIPE_READ_FD]) || close (inpipefd[PIPE_WRITE_FD])) { XPR(NT "dup/close failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; }#if XD3_STDIO /* Note: fdopen() acquires the fd, closes it when finished. */ if ((ifile->file = fdopen (input_fd, "r")) == NULL) { XPR(NT "fdopen failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; }#elif XD3_POSIX ifile->file = input_fd;#endif ifile->compressor = decomp; /* Now the input file is decompressed. */ return main_file_read (ifile, input_buf, input_bufsize, nread, "input decompression failed"); pipe_cleanup: close (input_fd); close (outpipefd[PIPE_READ_FD]); close (outpipefd[PIPE_WRITE_FD]); close (inpipefd[PIPE_READ_FD]); close (inpipefd[PIPE_WRITE_FD]); return ret;}/* This routine is called when the first buffer of input data is read * by the main program (unless input decompression is disabled by * command-line option). If it recognizes the magic number of a known * input type it invokes decompression. * * Skips decompression if the decompression type or the file type is * RD_NONEXTERNAL. * * Behaves exactly like main_file_read, otherwise. * * This function uses a separate buffer to read the first small block * of input. If a compressed input is detected, the separate buffer * is passed to the pipe copier. This avoids using the same size * buffer in both cases. */static intmain_decompress_input_check (main_file *ifile, uint8_t *input_buf, usize_t input_size, usize_t *nread){ int ret; usize_t i; usize_t check_nread; uint8_t check_buf[XD3_ALLOCSIZE]; if ((ret = main_file_read (ifile, check_buf, min (input_size, XD3_ALLOCSIZE), & check_nread, "input read failed"))) { return ret; } for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1) { const main_extcomp *decomp = & extcomp_types[i]; if ((check_nread > decomp->magic_size) && /* The following expr skips decompression if we are trying * to read a VCDIFF input and that is the magic number. */ !((decomp->flags & RD_NONEXTERNAL) && (ifile->flags & RD_NONEXTERNAL)) && memcmp (check_buf, decomp->magic, decomp->magic_size) == 0) { if (! option_quiet) { XPR(NT "%s | %s %s\n", ifile->filename, decomp->decomp_cmdname, decomp->decomp_options); } return main_input_decompress_setup (decomp, ifile, input_buf, input_size, check_buf, XD3_ALLOCSIZE, check_nread, nread); } } /* Now read the rest of the input block. */ (*nread) = 0; if (check_nread == XD3_ALLOCSIZE) { ret = main_file_read (ifile, input_buf + XD3_ALLOCSIZE, input_size - XD3_ALLOCSIZE, nread, "input read failed"); } memcpy (input_buf, check_buf, check_nread); (*nread) += check_nread; return 0;}/* This is called when the source file needs to be decompressed. We * fork/exec a decompression command with the proper input and output * to a temporary file. */static intmain_decompress_source (main_file *sfile, xd3_source *source){ const main_extcomp *decomp = sfile->compressor; pid_t decomp_id; /* One subproc. */ int input_fd = -1; int output_fd = -1; int ret; char *tmpname = NULL; char *tmpdir = getenv ("TMPDIR"); static const char tmpl[] = "/xd3src.XXXXXX"; /* Make a template for mkstmp() */ if (tmpdir == NULL) { tmpdir = "/tmp"; } if ((tmpname = (char*) main_malloc (strlen (tmpdir) + sizeof (tmpl) + 1)) == NULL) { return ENOMEM; } sprintf (tmpname, "%s%s", tmpdir, tmpl); XD3_ASSERT (ext_tmpfile == NULL); ext_tmpfile = tmpname; /* Open the output FD. */ if ((output_fd = mkstemp (tmpname)) < 0) { XPR(NT "mkstemp failed: %s: %s", tmpname, xd3_mainerror (ret = get_errno ())); goto cleanup; } /* Copy the input FD, reset file position. */ XD3_ASSERT (main_file_isopen (sfile));#if XD3_STDIO if ((input_fd = dup (fileno (sfile->file))) < 0) { XPR(NT "dup failed: %s", xd3_mainerror (ret = get_errno ())); goto cleanup; } main_file_close (sfile); sfile->file = NULL;#elif XD3_POSIX input_fd = sfile->file; sfile->file = -1;#endif if ((ret = lseek (input_fd, SEEK_SET, 0)) != 0) { XPR(NT "lseek failed: : %s", xd3_mainerror (ret = get_errno ())); goto cleanup; } if ((decomp_id = fork ()) < 0) { XPR(NT "fork failed: %s", xd3_mainerror (ret = get_errno ())); goto cleanup; } /* The child runs the decompression process: */ if (decomp_id == 0) { /* Setup pipes: write to the output file, read from the pipe. */ if (dup2 (input_fd, STDIN_FILENO) < 0 || dup2 (output_fd, STDOUT_FILENO) < 0 || execlp (decomp->decomp_cmdname, decomp->decomp_cmdname, decomp->decomp_options, NULL)) { XPR(NT "child process %s failed to execute: %s\n", decomp->decomp_cmdname, xd3_mainerror (get_errno ())); } _exit (127); } close (input_fd); close (output_fd); input_fd = -1; output_fd = -1; /* Then wait for completion. */ if ((ret = main_waitpid_check (decomp_id))) { goto cleanup; } /* Open/stat the decompressed source file. */ if ((ret = main_file_open (sfile, tmpname, XO_READ))) { goto cleanup; } if ((ret = main_file_stat (sfile, & source->size, 1))) { goto cleanup; } return 0; cleanup: close (input_fd); close (output_fd); if (tmpname) { free (tmpname); } ext_tmpfile = NULL; return ret;}/* Initiate re-compression of the output stream. This is easier than * input decompression because we know beforehand that the stream will * be compressed, whereas the input has already been read when we * decide it should be decompressed. Thus, it only requires one * subprocess and one pipe. */static intmain_recompress_output (main_file *ofile){ pid_t recomp_id; /* One subproc. */ int pipefd[2]; /* One pipe. */ int output_fd = -1; int ret; const main_extcomp *recomp = ofile->compressor; pipefd[0] = pipefd[1] = -1; if (pipe (pipefd)) { XPR(NT "pipe failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } if ((recomp_id = fork ()) < 0) { XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; } /* The child runs the recompression process: */ if (recomp_id == 0) { /* Setup pipes: write to the output file, read from the pipe. */ if (dup2 (XFNO (ofile), STDOUT_FILENO) < 0 || dup2 (pipefd[PIPE_READ_FD], STDIN_FILENO) < 0 || close (pipefd[PIPE_READ_FD]) || close (pipefd[PIPE_WRITE_FD]) || execlp (recomp->recomp_cmdname, recomp->recomp_cmdname, recomp->recomp_options, NULL)) { XPR(NT "child process %s failed to execute: %s\n", recomp->recomp_cmdname, xd3_mainerror (get_errno ())); } _exit (127); } ext_subprocs[0] = recomp_id; /* The parent closes both pipes after duplicating the output-fd for * writing to the compression pipe. */ output_fd = dup (pipefd[PIPE_WRITE_FD]); if (output_fd < 0 || main_file_close (ofile) || close (pipefd[PIPE_READ_FD]) || close (pipefd[PIPE_WRITE_FD])) { XPR(NT "close failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; }#if XD3_STDIO /* Note: fdopen() acquires the fd, closes it when finished. */ if ((ofile->file = fdopen (output_fd, "w")) == NULL) { XPR(NT "fdopen failed: %s\n", xd3_mainerror (ret = get_errno ())); goto pipe_cleanup; }#elif XD3_POSIX ofile->file = output_fd;#endif /* Now the output file will be compressed. */ return 0; pipe_cleanup: close (output_fd); close (pipefd[PIPE_READ_FD]); close (pipefd[PIPE_WRITE_FD]); return ret;}#endif /* EXTERNAL_COMPRESSION *//* Identify the compressor that was used based on its ident string, * which is passed in the application header. */static const main_extcomp*main_ident_compressor (const char *ident){ usize_t i; for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1) { if (strcmp (extcomp_types[i].ident, ident) == 0) { return & extcomp_types[i]; } } return NULL;}/* Return the main_ex
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -