diff options
author | josh.macdonald <jmacd@users.noreply.github.com> | 2010-07-01 03:37:15 +0000 |
---|---|---|
committer | josh.macdonald <jmacd@users.noreply.github.com> | 2010-07-01 03:37:15 +0000 |
commit | debec7aae3d3d3e5b1b2da62a9417ab3a0c72c00 (patch) | |
tree | 59f621dc4ee725e571266d0f4f0db0cb243d9c9f | |
parent | 07cacc99dc5a2f9e5fd7197e1675fd923750d9e4 (diff) |
Add -F command and properly handle trailing garbage. Manually tested.
-rw-r--r-- | xdelta3/xdelta3-main.h | 191 |
1 files changed, 144 insertions, 47 deletions
diff --git a/xdelta3/xdelta3-main.h b/xdelta3/xdelta3-main.h index 5429ad4..447651a 100644 --- a/xdelta3/xdelta3-main.h +++ b/xdelta3/xdelta3-main.h | |||
@@ -314,8 +314,10 @@ static usize_t option_srcwinsz = XD3_DEFAULT_SRCWINSZ; | |||
314 | static usize_t option_sprevsz = XD3_DEFAULT_SPREVSZ; | 314 | static usize_t option_sprevsz = XD3_DEFAULT_SPREVSZ; |
315 | 315 | ||
316 | /* These variables are supressed to avoid their use w/o support. main() warns | 316 | /* These variables are supressed to avoid their use w/o support. main() warns |
317 | * appropriately. */ | 317 | * appropriately when external compression is not enabled. */ |
318 | #if EXTERNAL_COMPRESSION | 318 | #if EXTERNAL_COMPRESSION |
319 | static int num_subprocs = 0; | ||
320 | static int option_force2 = 0; | ||
319 | static int option_decompress_inputs = 1; | 321 | static int option_decompress_inputs = 1; |
320 | static int option_recompress_outputs = 1; | 322 | static int option_recompress_outputs = 1; |
321 | #endif | 323 | #endif |
@@ -358,19 +360,17 @@ static xd3_stream *merge_stream = NULL; | |||
358 | * false just so the program knows the mapping of IDENT->NAME. */ | 360 | * false just so the program knows the mapping of IDENT->NAME. */ |
359 | static main_extcomp extcomp_types[] = | 361 | static main_extcomp extcomp_types[] = |
360 | { | 362 | { |
361 | { "bzip2", "-cf", "bzip2", "-dcf", "B", "BZh", 3, 0 }, | 363 | { "bzip2", "-c", "bzip2", "-dc", "B", "BZh", 3, 0 }, |
362 | { "gzip", "-cf", "gzip", "-dcf", "G", "\037\213", 2, 0 }, | 364 | { "gzip", "-c", "gzip", "-dc", "G", "\037\213", 2, 0 }, |
363 | { "compress", "-cf", "uncompress", "-cf", "Z", "\037\235", 2, 0 }, | 365 | { "compress", "-c", "uncompress", "-c", "Z", "\037\235", 2, 0 }, |
364 | 366 | ||
365 | /* TODO: add commandline support for magic-less formats */ | 367 | /* TODO: add commandline support for magic-less formats */ |
366 | /*{ "lzma", "-cf", "lzma", "-dcf", "M", "]\000", 2, 0 },*/ | 368 | /*{ "lzma", "-c", "lzma", "-dc", "M", "]\000", 2, 0 },*/ |
367 | 369 | ||
368 | /* Xz is lzma with a magic number http://tukaani.org/xz/ */ | 370 | /* Xz is lzma with a magic number http://tukaani.org/xz/ */ |
369 | { "xz", "-cf", "xz", "-dcf", "Y", "\xfd\x37\x7a\x58\x5a\x00", 2, 0 }, | 371 | { "xz", "-c", "xz", "-dc", "Y", "\xfd\x37\x7a\x58\x5a\x00", 2, 0 }, |
370 | }; | 372 | }; |
371 | 373 | ||
372 | // }; | ||
373 | |||
374 | static int main_input (xd3_cmd cmd, main_file *ifile, | 374 | static int main_input (xd3_cmd cmd, main_file *ifile, |
375 | main_file *ofile, main_file *sfile); | 375 | main_file *ofile, main_file *sfile); |
376 | static void main_get_appheader (xd3_stream *stream, main_file *ifile, | 376 | static void main_get_appheader (xd3_stream *stream, main_file *ifile, |
@@ -459,8 +459,10 @@ reset_defaults(void) | |||
459 | option_use_appheader = 1; | 459 | option_use_appheader = 1; |
460 | option_use_checksum = 1; | 460 | option_use_checksum = 1; |
461 | #if EXTERNAL_COMPRESSION | 461 | #if EXTERNAL_COMPRESSION |
462 | option_force2 = 0; | ||
462 | option_decompress_inputs = 1; | 463 | option_decompress_inputs = 1; |
463 | option_recompress_outputs = 1; | 464 | option_recompress_outputs = 1; |
465 | num_subprocs = 0; | ||
464 | #endif | 466 | #endif |
465 | #if VCDIFF_TOOLS | 467 | #if VCDIFF_TOOLS |
466 | option_print_cpymode = 1; | 468 | option_print_cpymode = 1; |
@@ -974,7 +976,7 @@ xd3_posix_io (int fd, uint8_t *buf, usize_t size, | |||
974 | { | 976 | { |
975 | return ret; | 977 | return ret; |
976 | } | 978 | } |
977 | result = 0; | 979 | continue; |
978 | } | 980 | } |
979 | 981 | ||
980 | if (nread != NULL && result == 0) { break; } | 982 | if (nread != NULL && result == 0) { break; } |
@@ -1106,12 +1108,6 @@ main_file_seek (main_file *xfile, xoff_t pos) | |||
1106 | # endif | 1108 | # endif |
1107 | #endif | 1109 | #endif |
1108 | 1110 | ||
1109 | if (ret) | ||
1110 | { | ||
1111 | XPR(NT "seek to %"Q"u failed: %s: %s\n", | ||
1112 | pos, xfile->filename, xd3_mainerror (ret)); | ||
1113 | } | ||
1114 | |||
1115 | return ret; | 1111 | return ret; |
1116 | } | 1112 | } |
1117 | 1113 | ||
@@ -2088,6 +2084,7 @@ main_merge_output (xd3_stream *stream, main_file *ofile) | |||
2088 | * input-decompression pipe. | 2084 | * input-decompression pipe. |
2089 | */ | 2085 | */ |
2090 | 2086 | ||
2087 | #include <signal.h> | ||
2091 | #include <unistd.h> | 2088 | #include <unistd.h> |
2092 | #include <sys/stat.h> | 2089 | #include <sys/stat.h> |
2093 | #include <sys/wait.h> | 2090 | #include <sys/wait.h> |
@@ -2095,11 +2092,14 @@ main_merge_output (xd3_stream *stream, main_file *ofile) | |||
2095 | /* Remember which pipe FD is which. */ | 2092 | /* Remember which pipe FD is which. */ |
2096 | #define PIPE_READ_FD 0 | 2093 | #define PIPE_READ_FD 0 |
2097 | #define PIPE_WRITE_FD 1 | 2094 | #define PIPE_WRITE_FD 1 |
2098 | 2095 | #define MAX_SUBPROCS 4 /* max(source + copier + output, | |
2099 | static pid_t ext_subprocs[2]; | 2096 | source + copier + input + copier). */ |
2097 | static pid_t ext_subprocs[MAX_SUBPROCS]; | ||
2100 | static char* ext_tmpfile = NULL; | 2098 | static char* ext_tmpfile = NULL; |
2101 | 2099 | ||
2102 | /* Like write(), but makes repeated calls to empty the buffer. */ | 2100 | /* Like write(), applies to a fd instead of a main_file, for the pipe |
2101 | * copier subprocess. Does not print an error, to facilitate ignoring | ||
2102 | * trailing garbage, see main_pipe_copier(). */ | ||
2103 | static int | 2103 | static int |
2104 | main_pipe_write (int outfd, uint8_t *exist_buf, usize_t remain) | 2104 | main_pipe_write (int outfd, uint8_t *exist_buf, usize_t remain) |
2105 | { | 2105 | { |
@@ -2108,7 +2108,6 @@ main_pipe_write (int outfd, uint8_t *exist_buf, usize_t remain) | |||
2108 | if ((ret = xd3_posix_io (outfd, exist_buf, remain, | 2108 | if ((ret = xd3_posix_io (outfd, exist_buf, remain, |
2109 | (xd3_posix_func*) &write, NULL))) | 2109 | (xd3_posix_func*) &write, NULL))) |
2110 | { | 2110 | { |
2111 | XPR(NT "pipe write failed: %s", xd3_mainerror (ret)); | ||
2112 | return ret; | 2111 | return ret; |
2113 | } | 2112 | } |
2114 | 2113 | ||
@@ -2125,18 +2124,24 @@ main_waitpid_check(pid_t pid) | |||
2125 | if (waitpid (pid, & status, 0) < 0) | 2124 | if (waitpid (pid, & status, 0) < 0) |
2126 | { | 2125 | { |
2127 | ret = get_errno (); | 2126 | ret = get_errno (); |
2128 | XPR(NT "compression subprocess: wait: %s\n", xd3_mainerror (ret)); | 2127 | XPR(NT "external compression [pid %d] wait: %s\n", |
2128 | pid, xd3_mainerror (ret)); | ||
2129 | } | 2129 | } |
2130 | else if (! WIFEXITED (status)) | 2130 | else if (! WIFEXITED (status)) |
2131 | { | 2131 | { |
2132 | ret = ECHILD; | 2132 | ret = ECHILD; |
2133 | XPR(NT "compression subprocess: signal %d\n", | 2133 | XPR(NT "external compression [pid %d] signal %d\n", |
2134 | WIFSIGNALED (status) ? WTERMSIG (status) : WSTOPSIG (status)); | 2134 | pid, WIFSIGNALED (status) ? WTERMSIG (status) : WSTOPSIG (status)); |
2135 | } | 2135 | } |
2136 | else if (WEXITSTATUS (status) != 0) | 2136 | else if (WEXITSTATUS (status) != 0) |
2137 | { | 2137 | { |
2138 | ret = ECHILD; | 2138 | ret = ECHILD; |
2139 | XPR(NT "compression subprocess: exit %d\n", WEXITSTATUS (status)); | 2139 | if (option_verbose > 1) |
2140 | { | ||
2141 | /* Presumably, the error was printed by the subprocess. */ | ||
2142 | XPR(NT "external compression [pid %d] exit %d\n", | ||
2143 | pid, WEXITSTATUS (status)); | ||
2144 | } | ||
2140 | } | 2145 | } |
2141 | 2146 | ||
2142 | return ret; | 2147 | return ret; |
@@ -2149,7 +2154,7 @@ main_external_compression_finish (void) | |||
2149 | int i; | 2154 | int i; |
2150 | int ret; | 2155 | int ret; |
2151 | 2156 | ||
2152 | for (i = 0; i < 2; i += 1) | 2157 | for (i = 0; i < num_subprocs; i += 1) |
2153 | { | 2158 | { |
2154 | if (! ext_subprocs[i]) { continue; } | 2159 | if (! ext_subprocs[i]) { continue; } |
2155 | 2160 | ||
@@ -2174,15 +2179,55 @@ main_pipe_copier (uint8_t *pipe_buf, | |||
2174 | int outfd) | 2179 | int outfd) |
2175 | { | 2180 | { |
2176 | int ret; | 2181 | int ret; |
2182 | xoff_t garbage = 0; | ||
2183 | |||
2184 | /* Prevent SIGPIPE signals, allow EPIPE return values instead. This | ||
2185 | * is safe to comment-out, except that the -F flag will not work | ||
2186 | * properly (the parent would need to treat WTERMSIG(status) == | ||
2187 | * SIGPIPE). */ | ||
2188 | struct sigaction sa; | ||
2189 | sa.sa_handler = SIG_IGN; | ||
2190 | sigaction (SIGPIPE, &sa, NULL); | ||
2177 | 2191 | ||
2178 | for (;;) | 2192 | for (;;) |
2179 | { | 2193 | { |
2194 | /* force_drain will be set when option_force and EPIPE cause us | ||
2195 | * to skip data. This is reset each time through the loop, so | ||
2196 | * the break condition below works. */ | ||
2197 | int force_drain = 0; | ||
2180 | if (nread > 0 && (ret = main_pipe_write (outfd, pipe_buf, nread))) | 2198 | if (nread > 0 && (ret = main_pipe_write (outfd, pipe_buf, nread))) |
2181 | { | 2199 | { |
2182 | return ret; | 2200 | if (option_force && ret == EPIPE) |
2201 | { | ||
2202 | /* This causes the loop to continue reading until nread | ||
2203 | * == 0. */ | ||
2204 | garbage += nread; | ||
2205 | force_drain = 1; | ||
2206 | } | ||
2207 | else if (ret == EPIPE) | ||
2208 | { | ||
2209 | XPR(NT "external compression closed the pipe\n"); | ||
2210 | if (option_verbose) | ||
2211 | { | ||
2212 | if (!option_force2) | ||
2213 | { | ||
2214 | XPR(NT "use -F to force the subprocess\n"); | ||
2215 | } | ||
2216 | if (!option_force) | ||
2217 | { | ||
2218 | XPR(NT "use -f to force this process\n"); | ||
2219 | } | ||
2220 | } | ||
2221 | return ret; | ||
2222 | } | ||
2223 | else | ||
2224 | { | ||
2225 | XPR(NT "pipe write failed: %s\n", xd3_mainerror (ret)); | ||
2226 | return ret; | ||
2227 | } | ||
2183 | } | 2228 | } |
2184 | 2229 | ||
2185 | if (nread < pipe_bufsize) | 2230 | if (nread < pipe_bufsize && !force_drain) |
2186 | { | 2231 | { |
2187 | break; | 2232 | break; |
2188 | } | 2233 | } |
@@ -2194,6 +2239,11 @@ main_pipe_copier (uint8_t *pipe_buf, | |||
2194 | } | 2239 | } |
2195 | } | 2240 | } |
2196 | 2241 | ||
2242 | if (garbage != 0) | ||
2243 | { | ||
2244 | XPR(NT "trailing garbage ignored in %s (%"Q"u bytes)\n", | ||
2245 | ifile->filename, garbage); | ||
2246 | } | ||
2197 | return 0; | 2247 | return 0; |
2198 | } | 2248 | } |
2199 | 2249 | ||
@@ -2236,6 +2286,11 @@ main_input_decompress_setup (const main_extcomp *decomp, | |||
2236 | /* The first child runs the decompression process: */ | 2286 | /* The first child runs the decompression process: */ |
2237 | if (decomp_id == 0) | 2287 | if (decomp_id == 0) |
2238 | { | 2288 | { |
2289 | if (option_verbose > 2) | ||
2290 | { | ||
2291 | XPR(NT "external decompression pid %d\n", getpid ()); | ||
2292 | } | ||
2293 | |||
2239 | /* Setup pipes: write to the outpipe, read from the inpipe. */ | 2294 | /* Setup pipes: write to the outpipe, read from the inpipe. */ |
2240 | if (dup2 (outpipefd[PIPE_WRITE_FD], STDOUT_FILENO) < 0 || | 2295 | if (dup2 (outpipefd[PIPE_WRITE_FD], STDOUT_FILENO) < 0 || |
2241 | dup2 (inpipefd[PIPE_READ_FD], STDIN_FILENO) < 0 || | 2296 | dup2 (inpipefd[PIPE_READ_FD], STDIN_FILENO) < 0 || |
@@ -2244,7 +2299,9 @@ main_input_decompress_setup (const main_extcomp *decomp, | |||
2244 | close (inpipefd[PIPE_READ_FD]) || | 2299 | close (inpipefd[PIPE_READ_FD]) || |
2245 | close (inpipefd[PIPE_WRITE_FD]) || | 2300 | close (inpipefd[PIPE_WRITE_FD]) || |
2246 | execlp (decomp->decomp_cmdname, decomp->decomp_cmdname, | 2301 | execlp (decomp->decomp_cmdname, decomp->decomp_cmdname, |
2247 | decomp->decomp_options, NULL)) | 2302 | decomp->decomp_options, |
2303 | option_force2 ? "-f" : NULL, | ||
2304 | NULL)) | ||
2248 | { | 2305 | { |
2249 | XPR(NT "child process %s failed to execute: %s\n", | 2306 | XPR(NT "child process %s failed to execute: %s\n", |
2250 | decomp->decomp_cmdname, xd3_mainerror (get_errno ())); | 2307 | decomp->decomp_cmdname, xd3_mainerror (get_errno ())); |
@@ -2253,7 +2310,8 @@ main_input_decompress_setup (const main_extcomp *decomp, | |||
2253 | _exit (127); | 2310 | _exit (127); |
2254 | } | 2311 | } |
2255 | 2312 | ||
2256 | ext_subprocs[0] = decomp_id; | 2313 | XD3_ASSERT(num_subprocs < MAX_SUBPROCS); |
2314 | ext_subprocs[num_subprocs++] = decomp_id; | ||
2257 | 2315 | ||
2258 | if ((copier_id = fork ()) < 0) | 2316 | if ((copier_id = fork ()) < 0) |
2259 | { | 2317 | { |
@@ -2266,6 +2324,11 @@ main_input_decompress_setup (const main_extcomp *decomp, | |||
2266 | { | 2324 | { |
2267 | int exitval = 0; | 2325 | int exitval = 0; |
2268 | 2326 | ||
2327 | if (option_verbose > 2) | ||
2328 | { | ||
2329 | XPR(NT "child pipe-copier pid %d\n", getpid ()); | ||
2330 | } | ||
2331 | |||
2269 | if (close (inpipefd[PIPE_READ_FD]) || | 2332 | if (close (inpipefd[PIPE_READ_FD]) || |
2270 | main_pipe_copier (pipe_buf, pipe_bufsize, pipe_avail, | 2333 | main_pipe_copier (pipe_buf, pipe_bufsize, pipe_avail, |
2271 | ifile, inpipefd[PIPE_WRITE_FD]) || | 2334 | ifile, inpipefd[PIPE_WRITE_FD]) || |
@@ -2279,7 +2342,8 @@ main_input_decompress_setup (const main_extcomp *decomp, | |||
2279 | _exit (exitval); | 2342 | _exit (exitval); |
2280 | } | 2343 | } |
2281 | 2344 | ||
2282 | ext_subprocs[1] = copier_id; | 2345 | XD3_ASSERT(num_subprocs < MAX_SUBPROCS); |
2346 | ext_subprocs[num_subprocs++] = copier_id; | ||
2283 | 2347 | ||
2284 | /* The parent closes both pipes after duplicating the output of | 2348 | /* The parent closes both pipes after duplicating the output of |
2285 | * compression. */ | 2349 | * compression. */ |
@@ -2369,7 +2433,7 @@ main_secondary_decompress_check (main_file *file, | |||
2369 | for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1) | 2433 | for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1) |
2370 | { | 2434 | { |
2371 | const main_extcomp *decomp = & extcomp_types[i]; | 2435 | const main_extcomp *decomp = & extcomp_types[i]; |
2372 | 2436 | ||
2373 | if (check_nread > decomp->magic_size) | 2437 | if (check_nread > decomp->magic_size) |
2374 | { | 2438 | { |
2375 | /* The following expr checks if we are trying to read a | 2439 | /* The following expr checks if we are trying to read a |
@@ -2396,9 +2460,10 @@ main_secondary_decompress_check (main_file *file, | |||
2396 | { | 2460 | { |
2397 | if (! option_quiet) | 2461 | if (! option_quiet) |
2398 | { | 2462 | { |
2399 | XPR(NT "externally compressed input: %s %s < %s\n", | 2463 | XPR(NT "externally compressed input: %s %s%s < %s\n", |
2400 | decompressor->decomp_cmdname, | 2464 | decompressor->decomp_cmdname, |
2401 | decompressor->decomp_options, | 2465 | decompressor->decomp_options, |
2466 | (option_force2 ? " -f" : ""), | ||
2402 | file->filename); | 2467 | file->filename); |
2403 | } | 2468 | } |
2404 | 2469 | ||
@@ -2459,13 +2524,20 @@ main_recompress_output (main_file *ofile) | |||
2459 | /* The child runs the recompression process: */ | 2524 | /* The child runs the recompression process: */ |
2460 | if (recomp_id == 0) | 2525 | if (recomp_id == 0) |
2461 | { | 2526 | { |
2527 | if (option_verbose > 2) | ||
2528 | { | ||
2529 | XPR(NT "external recompression pid %d\n", getpid ()); | ||
2530 | } | ||
2531 | |||
2462 | /* Setup pipes: write to the output file, read from the pipe. */ | 2532 | /* Setup pipes: write to the output file, read from the pipe. */ |
2463 | if (dup2 (XFNO (ofile), STDOUT_FILENO) < 0 || | 2533 | if (dup2 (XFNO (ofile), STDOUT_FILENO) < 0 || |
2464 | dup2 (pipefd[PIPE_READ_FD], STDIN_FILENO) < 0 || | 2534 | dup2 (pipefd[PIPE_READ_FD], STDIN_FILENO) < 0 || |
2465 | close (pipefd[PIPE_READ_FD]) || | 2535 | close (pipefd[PIPE_READ_FD]) || |
2466 | close (pipefd[PIPE_WRITE_FD]) || | 2536 | close (pipefd[PIPE_WRITE_FD]) || |
2467 | execlp (recomp->recomp_cmdname, recomp->recomp_cmdname, | 2537 | execlp (recomp->recomp_cmdname, recomp->recomp_cmdname, |
2468 | recomp->recomp_options, NULL)) | 2538 | recomp->recomp_options, |
2539 | option_force2 ? "-f" : NULL, | ||
2540 | NULL)) | ||
2469 | { | 2541 | { |
2470 | XPR(NT "child process %s failed to execute: %s\n", | 2542 | XPR(NT "child process %s failed to execute: %s\n", |
2471 | recomp->recomp_cmdname, xd3_mainerror (get_errno ())); | 2543 | recomp->recomp_cmdname, xd3_mainerror (get_errno ())); |
@@ -2474,7 +2546,8 @@ main_recompress_output (main_file *ofile) | |||
2474 | _exit (127); | 2546 | _exit (127); |
2475 | } | 2547 | } |
2476 | 2548 | ||
2477 | ext_subprocs[0] = recomp_id; | 2549 | XD3_ASSERT(num_subprocs < MAX_SUBPROCS); |
2550 | ext_subprocs[num_subprocs++] = recomp_id; | ||
2478 | 2551 | ||
2479 | /* The parent closes both pipes after duplicating the output-fd for | 2552 | /* The parent closes both pipes after duplicating the output-fd for |
2480 | * writing to the compression pipe. */ | 2553 | * writing to the compression pipe. */ |
@@ -2816,10 +2889,11 @@ main_open_output (xd3_stream *stream, main_file *ofile) | |||
2816 | { | 2889 | { |
2817 | if (! option_quiet) | 2890 | if (! option_quiet) |
2818 | { | 2891 | { |
2819 | XPR(NT "externally compressed output: %s %s > %s\n", | 2892 | XPR(NT "externally compressed output: %s %s%s > %s\n", |
2820 | ofile->compressor->recomp_cmdname, | 2893 | ofile->compressor->recomp_cmdname, |
2821 | ofile->compressor->recomp_options, | 2894 | ofile->compressor->recomp_options, |
2822 | ofile->filename); | 2895 | (option_force2 ? " -f" : ""), |
2896 | ofile->filename); | ||
2823 | } | 2897 | } |
2824 | 2898 | ||
2825 | if ((ret = main_recompress_output (ofile))) | 2899 | if ((ret = main_recompress_output (ofile))) |
@@ -3162,9 +3236,6 @@ main_read_seek_source (xd3_stream *stream, | |||
3162 | } | 3236 | } |
3163 | } | 3237 | } |
3164 | 3238 | ||
3165 | /* There's a chance here, that an genuine lseek error will cause | ||
3166 | * xdelta3 to shift into non-seekable mode, entering a degraded | ||
3167 | * condition. */ | ||
3168 | if (sfile->seek_failed || ret != 0) | 3239 | if (sfile->seek_failed || ret != 0) |
3169 | { | 3240 | { |
3170 | /* For an unseekable file (or other seek error, does it | 3241 | /* For an unseekable file (or other seek error, does it |
@@ -3173,7 +3244,7 @@ main_read_seek_source (xd3_stream *stream, | |||
3173 | { | 3244 | { |
3174 | /* Could assert !IS_ENCODE(), this shouldn't happen | 3245 | /* Could assert !IS_ENCODE(), this shouldn't happen |
3175 | * because of do_src_fifo during encode. */ | 3246 | * because of do_src_fifo during encode. */ |
3176 | if (option_verbose) | 3247 | if (!option_quiet) |
3177 | { | 3248 | { |
3178 | XPR(NT "source can't seek backwards; requested block offset " | 3249 | XPR(NT "source can't seek backwards; requested block offset " |
3179 | "%"Q"u source position is %"Q"u\n", | 3250 | "%"Q"u source position is %"Q"u\n", |
@@ -3186,11 +3257,19 @@ main_read_seek_source (xd3_stream *stream, | |||
3186 | return XD3_TOOFARBACK; | 3257 | return XD3_TOOFARBACK; |
3187 | } | 3258 | } |
3188 | 3259 | ||
3189 | if (option_verbose > 2 || (option_verbose > 1 && !sfile->seek_failed)) | 3260 | /* There's a chance here, that an genuine lseek error will cause |
3261 | * xdelta3 to shift into non-seekable mode, entering a degraded | ||
3262 | * condition. */ | ||
3263 | if (!sfile->seek_failed && option_verbose) | ||
3190 | { | 3264 | { |
3191 | XPR(NT "non-seekable source skipping %"Q"u bytes @ %"Q"u\n", | 3265 | XPR(NT "source can't seek, will use FIFO for %s\n", |
3192 | pos - sfile->source_position, | 3266 | sfile->filename); |
3193 | sfile->source_position); | 3267 | |
3268 | if (option_verbose > 1) | ||
3269 | { | ||
3270 | XPR(NT "seek error at offset %"Q"u: %s\n", | ||
3271 | pos, xd3_mainerror (ret)); | ||
3272 | } | ||
3194 | } | 3273 | } |
3195 | 3274 | ||
3196 | sfile->seek_failed = 1; | 3275 | sfile->seek_failed = 1; |
@@ -3215,6 +3294,13 @@ main_read_seek_source (xd3_stream *stream, | |||
3215 | 3294 | ||
3216 | XD3_ASSERT (is_new); | 3295 | XD3_ASSERT (is_new); |
3217 | 3296 | ||
3297 | if (option_verbose > 1) | ||
3298 | { | ||
3299 | XPR(NT "non-seekable source skipping %"Q"u bytes @ %"Q"u\n", | ||
3300 | pos - sfile->source_position, | ||
3301 | sfile->source_position); | ||
3302 | } | ||
3303 | |||
3218 | if ((ret = main_read_primary_input (sfile, | 3304 | if ((ret = main_read_primary_input (sfile, |
3219 | (uint8_t*) blru->blk, | 3305 | (uint8_t*) blru->blk, |
3220 | source->blksize, | 3306 | source->blksize, |
@@ -3974,7 +4060,7 @@ main (int argc, char **argv) | |||
3974 | #endif | 4060 | #endif |
3975 | { | 4061 | { |
3976 | static const char *flags = | 4062 | static const char *flags = |
3977 | "0123456789cdefhnqvDJNORTVs:m:B:C:E:F:I:L:O:M:P:W:A::S::"; | 4063 | "0123456789cdefhnqvDFJNORTVs:m:B:C:E:I:L:O:M:P:W:A::S::"; |
3978 | xd3_cmd cmd; | 4064 | xd3_cmd cmd; |
3979 | main_file ifile; | 4065 | main_file ifile; |
3980 | main_file ofile; | 4066 | main_file ofile; |
@@ -4149,6 +4235,14 @@ main (int argc, char **argv) | |||
4149 | option_level = ret - '0'; | 4235 | option_level = ret - '0'; |
4150 | break; | 4236 | break; |
4151 | case 'f': option_force = 1; break; | 4237 | case 'f': option_force = 1; break; |
4238 | case 'F': | ||
4239 | #if EXTERNAL_COMPRESSION | ||
4240 | option_force2 = 1; | ||
4241 | #else | ||
4242 | XPR(NT "warning: -F option ignored, " | ||
4243 | "external compression support was not compiled\n"); | ||
4244 | break; | ||
4245 | #endif | ||
4152 | case 'v': option_verbose += 1; option_quiet = 0; break; | 4246 | case 'v': option_verbose += 1; option_quiet = 0; break; |
4153 | case 'q': option_quiet = 1; option_verbose = 0; break; | 4247 | case 'q': option_quiet = 1; option_verbose = 0; break; |
4154 | case 'c': option_stdout = 1; break; | 4248 | case 'c': option_stdout = 1; break; |
@@ -4423,7 +4517,10 @@ main_help (void) | |||
4423 | DP(RINT " -d decompress\n"); | 4517 | DP(RINT " -d decompress\n"); |
4424 | DP(RINT " -e compress%s\n", | 4518 | DP(RINT " -e compress%s\n", |
4425 | XD3_ENCODER ? "" : " [Not compiled]"); | 4519 | XD3_ENCODER ? "" : " [Not compiled]"); |
4426 | DP(RINT " -f force overwrite\n"); | 4520 | DP(RINT " -f force (overwrite, ignore trailing garbage)\n"); |
4521 | #if EXTERNAL_COMPRESSION | ||
4522 | DP(RINT " -F force the external-compression subprocess\n"); | ||
4523 | #endif | ||
4427 | DP(RINT " -h show help\n"); | 4524 | DP(RINT " -h show help\n"); |
4428 | DP(RINT " -q be quiet\n"); | 4525 | DP(RINT " -q be quiet\n"); |
4429 | DP(RINT " -v be verbose (max 2)\n"); | 4526 | DP(RINT " -v be verbose (max 2)\n"); |