Contents of /trunk/mkinitrd-magellan/klibc/usr/gzip/gzip.c
Parent Directory | Revision Log
Revision 815 -
(show annotations)
(download)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 37435 byte(s)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 37435 byte(s)
-updated to klibc-1.5.15
1 | /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface |
2 | * Copyright (C) 1992-1993 Jean-loup Gailly |
3 | * The unzip code was written and put in the public domain by Mark Adler. |
4 | * Portions of the lzw code are derived from the public domain 'compress' |
5 | * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, |
6 | * Ken Turkowski, Dave Mack and Peter Jannesen. |
7 | * |
8 | * See the license_msg below and the file COPYING for the software license. |
9 | * See the file algorithm.doc for the compression algorithms and file formats. |
10 | */ |
11 | |
12 | static char *license_msg[] = { |
13 | " Copyright (C) 1992-1993 Jean-loup Gailly", |
14 | " This program is free software; you can redistribute it and/or modify", |
15 | " it under the terms of the GNU General Public License as published by", |
16 | " the Free Software Foundation; either version 2, or (at your option)", |
17 | " any later version.", |
18 | "", |
19 | " This program is distributed in the hope that it will be useful,", |
20 | " but WITHOUT ANY WARRANTY; without even the implied warranty of", |
21 | " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", |
22 | " GNU General Public License for more details.", |
23 | "", |
24 | " You should have received a copy of the GNU General Public License", |
25 | " along with this program; if not, write to the Free Software", |
26 | " Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.", |
27 | 0}; |
28 | |
29 | /* Compress files with zip algorithm and 'compress' interface. |
30 | * See usage() and help() functions below for all options. |
31 | * Outputs: |
32 | * file.gz: compressed file with same mode, owner, and utimes |
33 | * or stdout with -c option or if stdin used as input. |
34 | * If the output file name had to be truncated, the original name is kept |
35 | * in the compressed file. |
36 | * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-gz. |
37 | * |
38 | * Using gz on MSDOS would create too many file name conflicts. For |
39 | * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for |
40 | * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz. |
41 | * I also considered 12345678.txt -> 12345txt.gz but this truncates the name |
42 | * too heavily. There is no ideal solution given the MSDOS 8+3 limitation. |
43 | * |
44 | * For the meaning of all compilation flags, see comments in Makefile.in. |
45 | */ |
46 | |
47 | #ifdef RCSID |
48 | static char rcsid[] = "$Id: gzip.c,v 1.3 2005/02/12 21:03:28 olh Exp $"; |
49 | #endif |
50 | |
51 | #include <ctype.h> |
52 | #include <sys/types.h> |
53 | #include <signal.h> |
54 | #include <sys/stat.h> |
55 | #include <errno.h> |
56 | |
57 | #include "tailor.h" |
58 | #include "gzip.h" |
59 | #include "revision.h" |
60 | |
61 | #include <time.h> |
62 | #include <fcntl.h> |
63 | #include <unistd.h> |
64 | #include <stdlib.h> |
65 | |
66 | #include <utime.h> |
67 | |
68 | typedef void (*sig_type) OF((int)); |
69 | |
70 | #define RW_USER (S_IRUSR | S_IWUSR) /* creation mode for open() */ |
71 | |
72 | #ifndef MAX_PATH_LEN |
73 | # define MAX_PATH_LEN 1024 /* max pathname length */ |
74 | #endif |
75 | |
76 | /* global buffers */ |
77 | |
78 | DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA); |
79 | DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA); |
80 | DECLARE(ush, d_buf, DIST_BUFSIZE); |
81 | DECLARE(uch, window, 2L*WSIZE); |
82 | DECLARE(ush, tab_prefix, 1L<<BITS); |
83 | |
84 | /* local variables */ |
85 | |
86 | #ifndef SUPPORT_ZIP |
87 | #define decompress 1 |
88 | #else |
89 | int level = 6; /* compression level */ |
90 | #endif |
91 | |
92 | int to_stdout; /* output to stdout (-c) */ |
93 | #ifndef decompress |
94 | int decompress; /* decompress (-d) */ |
95 | #endif |
96 | int force; /* don't ask questions, compress links (-f) */ |
97 | int no_name = -1; /* don't save or restore the original file name */ |
98 | int no_time = -1; /* don't save or restore the original file time */ |
99 | int verbose; /* be verbose (-v) */ |
100 | int quiet; /* be very quiet (-q) */ |
101 | int test; /* test .gz file integrity */ |
102 | int foreground; /* set if program run in foreground */ |
103 | char *progname; /* program name */ |
104 | int method = DEFLATED;/* compression method */ |
105 | int exit_code = OK; /* program exit code */ |
106 | int save_orig_name; /* set if original name must be saved */ |
107 | int last_member; /* set for .zip and .Z files */ |
108 | int part_nb; /* number of parts in .gz file */ |
109 | time_t time_stamp; /* original time stamp (modification time) */ |
110 | long ifile_size; /* input file size, -1 for devices (debug only) */ |
111 | char *env; /* contents of GZIP env variable */ |
112 | char **args = NULL; /* argv pointer if GZIP env variable defined */ |
113 | char z_suffix[MAX_SUFFIX+1]; /* default suffix (can be set with --suffix) */ |
114 | int z_len; /* strlen(z_suffix) */ |
115 | |
116 | long header_bytes; /* number of bytes in gzip header */ |
117 | long bytes_in; /* number of input bytes */ |
118 | long bytes_out; /* number of output bytes */ |
119 | long total_in; /* input bytes for all files */ |
120 | long total_out; /* output bytes for all files */ |
121 | char ifname[MAX_PATH_LEN]; /* input file name */ |
122 | char ofname[MAX_PATH_LEN]; /* output file name */ |
123 | int remove_ofname; /* remove output file on error */ |
124 | struct stat istat; /* status for input file */ |
125 | int ifd; /* input file descriptor */ |
126 | int ofd; /* output file descriptor */ |
127 | unsigned insize; /* valid bytes in inbuf */ |
128 | unsigned inptr; /* index of next byte to be processed in inbuf */ |
129 | unsigned outcnt; /* bytes in output buffer */ |
130 | |
131 | /* local functions */ |
132 | |
133 | local void usage OF((void)); |
134 | local void help OF((void)); |
135 | local void license OF((void)); |
136 | local void version OF((void)); |
137 | local void treat_stdin OF((void)); |
138 | local void treat_file OF((char *iname)); |
139 | local int create_outfile OF((void)); |
140 | local int do_stat OF((char *name, struct stat *sbuf)); |
141 | local char *get_suffix OF((char *name)); |
142 | local int get_istat OF((char *iname, struct stat *sbuf)); |
143 | local int make_ofname OF((void)); |
144 | local int same_file OF((struct stat *stat1, struct stat *stat2)); |
145 | local int name_too_long OF((char *name, struct stat *statb)); |
146 | local void shorten_name OF((char *name)); |
147 | local int get_method OF((void)); |
148 | local int check_ofname OF((void)); |
149 | local void copy_stat OF((struct stat *ifstat)); |
150 | local void do_exit OF((int exitcode)); |
151 | int main OF((int argc, char **argv)); |
152 | int (*work) OF((int infile, int outfile)) |
153 | #ifdef SUPPORT_ZIP |
154 | = zip; /* function to call */ |
155 | #else |
156 | = unzip; |
157 | #endif |
158 | local void reset_times OF((char *name, struct stat *statb)); |
159 | |
160 | #define strequ(s1, s2) (strcmp((s1),(s2)) == 0) |
161 | |
162 | /* ======================================================================== */ |
163 | local void usage() |
164 | { |
165 | fprintf(stderr, "usage: %s [-cdfhlLnNtvV19] [-S suffix] [file ...]\n", |
166 | progname); |
167 | } |
168 | |
169 | /* ======================================================================== */ |
170 | local void help() |
171 | { |
172 | static char *help_msg[] = { |
173 | " -c --stdout write on standard output, keep original files unchanged", |
174 | " -d --decompress decompress", |
175 | " -f --force force overwrite of output file and compress links", |
176 | " -h --help give this help", |
177 | " -L --license display software license", |
178 | #ifdef UNDOCUMENTED |
179 | " -m --no-time do not save or restore the original modification time", |
180 | " -M --time save or restore the original modification time", |
181 | #endif |
182 | " -n --no-name do not save or restore the original name and time stamp", |
183 | " -N --name save or restore the original name and time stamp", |
184 | " -q --quiet suppress all warnings", |
185 | " -S .suf --suffix .suf use suffix .suf on compressed files", |
186 | " -t --test test compressed file integrity", |
187 | " -v --verbose verbose mode", |
188 | " -V --version display version number", |
189 | #ifdef SUPPORT_ZIP |
190 | " -1 --fast compress faster", |
191 | " -9 --best compress better", |
192 | " file... files to (de)compress. If none given, use standard input.", |
193 | #else |
194 | " file... files to decompress. If none given, use standard input.", |
195 | #endif |
196 | 0}; |
197 | char **p = help_msg; |
198 | |
199 | fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE); |
200 | usage(); |
201 | while (*p) fprintf(stderr, "%s\n", *p++); |
202 | } |
203 | |
204 | /* ======================================================================== */ |
205 | local void license() |
206 | { |
207 | char **p = license_msg; |
208 | |
209 | fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE); |
210 | while (*p) fprintf(stderr, "%s\n", *p++); |
211 | } |
212 | |
213 | /* ======================================================================== */ |
214 | local void version() |
215 | { |
216 | fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE); |
217 | |
218 | fprintf(stderr, "Compilation options: UTIME STDC_HEADERS" |
219 | #ifndef SUPPORT_ZIP |
220 | " DECOMPRESS_ONLY" |
221 | #endif |
222 | "\n"); |
223 | } |
224 | |
225 | /* ======================================================================== */ |
226 | int main (argc, argv) |
227 | int argc; |
228 | char **argv; |
229 | { |
230 | int file_count; /* number of files to precess */ |
231 | int proglen; /* length of progname */ |
232 | int optc; /* current option */ |
233 | |
234 | progname = basename(argv[0]); |
235 | proglen = strlen(progname); |
236 | |
237 | /* Add options in GZIP environment variable if there is one */ |
238 | env = add_envopt(&argc, &argv, OPTIONS_VAR); |
239 | if (env != NULL) args = argv; |
240 | |
241 | foreground = sysv_signal(SIGINT, SIG_IGN) != SIG_IGN; |
242 | if (foreground) { |
243 | (void) sysv_signal(SIGINT, (sig_type)abort_gzip); |
244 | } |
245 | #ifdef SIGTERM |
246 | if (sysv_signal(SIGTERM, SIG_IGN) != SIG_IGN) { |
247 | (void) sysv_signal(SIGTERM, (sig_type)abort_gzip); |
248 | } |
249 | #endif |
250 | #ifdef SIGHUP |
251 | if (sysv_signal(SIGHUP, SIG_IGN) != SIG_IGN) { |
252 | (void) sysv_signal(SIGHUP, (sig_type)abort_gzip); |
253 | } |
254 | #endif |
255 | |
256 | #ifndef GNU_STANDARD |
257 | /* For compatibility with old compress, use program name as an option. |
258 | * If you compile with -DGNU_STANDARD, this program will behave as |
259 | * gzip even if it is invoked under the name gunzip or zcat. |
260 | * |
261 | * Systems which do not support links can still use -d or -dc. |
262 | * Ignore an .exe extension for MSDOS, OS/2 and VMS. |
263 | */ |
264 | #ifndef decompress |
265 | if ( strncmp(progname, "un", 2) == 0 /* ungzip, uncompress */ |
266 | || strncmp(progname, "gun", 3) == 0) { /* gunzip */ |
267 | decompress = 1; |
268 | } |
269 | #endif |
270 | if (strequ(progname+1, "cat") /* zcat, pcat, gcat */ |
271 | || strequ(progname, "gzcat")) { /* gzcat */ |
272 | #ifndef decompress |
273 | decompress = 1; |
274 | #endif |
275 | to_stdout = 1; |
276 | } |
277 | #endif |
278 | |
279 | strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix)-1); |
280 | z_len = strlen(z_suffix); |
281 | |
282 | while ((optc = getopt(argc, argv, "cdfhH?LmMnNqrS:tvV123456789")) != EOF) { |
283 | switch (optc) { |
284 | case 'c': |
285 | to_stdout = 1; break; |
286 | case 'd': |
287 | #ifndef decompress |
288 | decompress = 1; |
289 | #endif |
290 | break; |
291 | case 'f': |
292 | force++; break; |
293 | case 'h': case 'H': case '?': |
294 | help(); do_exit(OK); break; |
295 | case 'L': |
296 | license(); do_exit(OK); break; |
297 | case 'm': /* undocumented, may change later */ |
298 | no_time = 1; break; |
299 | case 'M': /* undocumented, may change later */ |
300 | no_time = 0; break; |
301 | case 'n': |
302 | no_name = no_time = 1; break; |
303 | case 'N': |
304 | no_name = no_time = 0; break; |
305 | case 'q': |
306 | quiet = 1; verbose = 0; break; |
307 | case 'S': |
308 | z_len = strlen(optarg); |
309 | strcpy(z_suffix, optarg); |
310 | break; |
311 | case 't': |
312 | test = to_stdout = 1; |
313 | #ifndef decompress |
314 | decompress = 1; |
315 | #endif |
316 | break; |
317 | case 'v': |
318 | verbose++; quiet = 0; break; |
319 | case 'V': |
320 | version(); do_exit(OK); break; |
321 | #ifdef SUPPORT_ZIP |
322 | case '1': case '2': case '3': case '4': |
323 | case '5': case '6': case '7': case '8': case '9': |
324 | level = optc - '0'; |
325 | break; |
326 | #endif |
327 | default: |
328 | /* Error message already emitted by getopt_long. */ |
329 | usage(); |
330 | do_exit(ERROR); |
331 | } |
332 | } /* loop on all arguments */ |
333 | |
334 | /* By default, save name and timestamp on compression but do not |
335 | * restore them on decompression. |
336 | */ |
337 | if (no_time < 0) no_time = decompress; |
338 | if (no_name < 0) no_name = decompress; |
339 | |
340 | file_count = argc - optind; |
341 | |
342 | if ((z_len == 0 && !decompress) || z_len > MAX_SUFFIX) { |
343 | fprintf(stderr, "%s: incorrect suffix '%s'\n", |
344 | progname, optarg); |
345 | do_exit(ERROR); |
346 | } |
347 | |
348 | /* Allocate all global buffers (for DYN_ALLOC option) */ |
349 | ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA); |
350 | ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA); |
351 | ALLOC(ush, d_buf, DIST_BUFSIZE); |
352 | ALLOC(uch, window, 2L*WSIZE); |
353 | ALLOC(ush, tab_prefix, 1L<<BITS); |
354 | |
355 | /* And get to work */ |
356 | if (file_count != 0) { |
357 | while (optind < argc) { |
358 | treat_file(argv[optind++]); |
359 | } |
360 | } else { /* Standard input */ |
361 | treat_stdin(); |
362 | } |
363 | do_exit(exit_code); |
364 | return exit_code; /* just to avoid lint warning */ |
365 | } |
366 | |
367 | /* ======================================================================== |
368 | * Compress or decompress stdin |
369 | */ |
370 | local void treat_stdin() |
371 | { |
372 | if (!force && |
373 | isatty(fileno((FILE *)(decompress ? stdin : stdout)))) { |
374 | /* Do not send compressed data to the terminal or read it from |
375 | * the terminal. We get here when user invoked the program |
376 | * without parameters, so be helpful. According to the GNU standards: |
377 | * |
378 | * If there is one behavior you think is most useful when the output |
379 | * is to a terminal, and another that you think is most useful when |
380 | * the output is a file or a pipe, then it is usually best to make |
381 | * the default behavior the one that is useful with output to a |
382 | * terminal, and have an option for the other behavior. |
383 | * |
384 | * Here we use the --force option to get the other behavior. |
385 | */ |
386 | fprintf(stderr, |
387 | "%s: compressed data not %s a terminal. Use -f to force %scompression.\n", |
388 | progname, decompress ? "read from" : "written to", |
389 | decompress ? "de" : ""); |
390 | fprintf(stderr,"For help, type: %s -h\n", progname); |
391 | do_exit(ERROR); |
392 | } |
393 | |
394 | strcpy(ifname, "stdin"); |
395 | strcpy(ofname, "stdout"); |
396 | |
397 | /* Get the time stamp on the input file. */ |
398 | time_stamp = 0; /* time unknown by default */ |
399 | |
400 | if (!no_time) { |
401 | if (fstat(fileno(stdin), &istat) != 0) { |
402 | error("fstat(stdin)"); |
403 | } |
404 | time_stamp = istat.st_mtime; |
405 | } |
406 | ifile_size = -1L; /* convention for unknown size */ |
407 | |
408 | clear_bufs(); /* clear input and output buffers */ |
409 | to_stdout = 1; |
410 | part_nb = 0; |
411 | |
412 | if (decompress) { |
413 | method = get_method(); |
414 | if (method < 0) { |
415 | do_exit(exit_code); /* error message already emitted */ |
416 | } |
417 | } |
418 | |
419 | /* Actually do the compression/decompression. Loop over zipped members. |
420 | */ |
421 | for (;;) { |
422 | if ((*work)(fileno(stdin), fileno(stdout)) != OK) return; |
423 | |
424 | if (!decompress || last_member || inptr == insize) break; |
425 | /* end of file */ |
426 | |
427 | method = get_method(); |
428 | if (method < 0) return; /* error message already emitted */ |
429 | bytes_out = 0; /* required for length check */ |
430 | } |
431 | |
432 | if (verbose) { |
433 | if (test) { |
434 | fprintf(stderr, " OK\n"); |
435 | |
436 | } else if (!decompress) { |
437 | display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr); |
438 | fprintf(stderr, "\n"); |
439 | #ifdef DISPLAY_STDIN_RATIO |
440 | } else { |
441 | display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr); |
442 | fprintf(stderr, "\n"); |
443 | #endif |
444 | } |
445 | } |
446 | } |
447 | |
448 | /* ======================================================================== |
449 | * Compress or decompress the given file |
450 | */ |
451 | local void treat_file(iname) |
452 | char *iname; |
453 | { |
454 | /* Accept "-" as synonym for stdin */ |
455 | if (strequ(iname, "-")) { |
456 | int cflag = to_stdout; |
457 | treat_stdin(); |
458 | to_stdout = cflag; |
459 | return; |
460 | } |
461 | |
462 | /* Check if the input file is present, set ifname and istat: */ |
463 | if (get_istat(iname, &istat) != OK) return; |
464 | |
465 | /* If the input name is that of a directory, recurse or ignore: */ |
466 | if (S_ISDIR(istat.st_mode)) { |
467 | WARN((stderr,"%s: %s is a directory -- ignored\n", progname, ifname)); |
468 | return; |
469 | } |
470 | if (!S_ISREG(istat.st_mode)) { |
471 | WARN((stderr, |
472 | "%s: %s is not a directory or a regular file - ignored\n", |
473 | progname, ifname)); |
474 | return; |
475 | } |
476 | if (istat.st_nlink > 1 && !to_stdout && !force) { |
477 | WARN((stderr, "%s: %s has %d other link%c -- unchanged\n", |
478 | progname, ifname, |
479 | (int)istat.st_nlink - 1, istat.st_nlink > 2 ? 's' : ' ')); |
480 | return; |
481 | } |
482 | |
483 | ifile_size = istat.st_size; |
484 | time_stamp = no_time ? 0 : istat.st_mtime; |
485 | |
486 | /* Generate output file name. For -r and (-t or -l), skip files |
487 | * without a valid gzip suffix (check done in make_ofname). |
488 | */ |
489 | if (to_stdout && !test) { |
490 | strcpy(ofname, "stdout"); |
491 | |
492 | } else if (make_ofname() != OK) { |
493 | return; |
494 | } |
495 | |
496 | /* Open the input file and determine compression method. The mode |
497 | * parameter is ignored but required by some systems (VMS) and forbidden |
498 | * on other systems (MacOS). |
499 | */ |
500 | ifd = open(ifname, !decompress ? O_RDONLY : O_RDONLY, |
501 | RW_USER); |
502 | if (ifd == -1) { |
503 | fprintf(stderr, "%s: ", progname); |
504 | perror(ifname); |
505 | exit_code = ERROR; |
506 | return; |
507 | } |
508 | clear_bufs(); /* clear input and output buffers */ |
509 | part_nb = 0; |
510 | |
511 | if (decompress) { |
512 | method = get_method(); /* updates ofname if original given */ |
513 | if (method < 0) { |
514 | close(ifd); |
515 | return; /* error message already emitted */ |
516 | } |
517 | } |
518 | |
519 | /* If compressing to a file, check if ofname is not ambiguous |
520 | * because the operating system truncates names. Otherwise, generate |
521 | * a new ofname and save the original name in the compressed file. |
522 | */ |
523 | if (to_stdout) { |
524 | ofd = fileno(stdout); |
525 | /* keep remove_ofname as zero */ |
526 | } else { |
527 | if (create_outfile() != OK) return; |
528 | |
529 | if (!decompress && save_orig_name && !verbose && !quiet) { |
530 | fprintf(stderr, "%s: %s compressed to %s\n", |
531 | progname, ifname, ofname); |
532 | } |
533 | } |
534 | /* Keep the name even if not truncated except with --no-name: */ |
535 | if (!save_orig_name) save_orig_name = !no_name; |
536 | |
537 | if (verbose) { |
538 | fprintf(stderr, "%s:\t%s", ifname, (int)strlen(ifname) >= 15 ? |
539 | "" : ((int)strlen(ifname) >= 7 ? "\t" : "\t\t")); |
540 | } |
541 | |
542 | /* Actually do the compression/decompression. Loop over zipped members. |
543 | */ |
544 | for (;;) { |
545 | if ((*work)(ifd, ofd) != OK) { |
546 | method = -1; /* force cleanup */ |
547 | break; |
548 | } |
549 | if (!decompress || last_member || inptr == insize) break; |
550 | /* end of file */ |
551 | |
552 | method = get_method(); |
553 | if (method < 0) break; /* error message already emitted */ |
554 | bytes_out = 0; /* required for length check */ |
555 | } |
556 | |
557 | close(ifd); |
558 | if (!to_stdout && close(ofd)) { |
559 | write_error(); |
560 | } |
561 | if (method == -1) { |
562 | if (!to_stdout) unlink (ofname); |
563 | return; |
564 | } |
565 | /* Display statistics */ |
566 | if(verbose) { |
567 | if (test) { |
568 | fprintf(stderr, " OK"); |
569 | } else if (decompress) { |
570 | display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr); |
571 | } else { |
572 | display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr); |
573 | } |
574 | if (!test && !to_stdout) { |
575 | fprintf(stderr, " -- replaced with %s", ofname); |
576 | } |
577 | fprintf(stderr, "\n"); |
578 | } |
579 | /* Copy modes, times, ownership, and remove the input file */ |
580 | if (!to_stdout) { |
581 | copy_stat(&istat); |
582 | } |
583 | } |
584 | |
585 | /* ======================================================================== |
586 | * Create the output file. Return OK or ERROR. |
587 | * Try several times if necessary to avoid truncating the z_suffix. For |
588 | * example, do not create a compressed file of name "1234567890123." |
589 | * Sets save_orig_name to true if the file name has been truncated. |
590 | * IN assertions: the input file has already been open (ifd is set) and |
591 | * ofname has already been updated if there was an original name. |
592 | * OUT assertions: ifd and ofd are closed in case of error. |
593 | */ |
594 | local int create_outfile() |
595 | { |
596 | struct stat ostat; /* stat for ofname */ |
597 | int flags = O_WRONLY | O_CREAT | O_EXCL; |
598 | |
599 | for (;;) { |
600 | /* Make sure that ofname is not an existing file */ |
601 | if (check_ofname() != OK) { |
602 | close(ifd); |
603 | return ERROR; |
604 | } |
605 | /* Create the output file */ |
606 | remove_ofname = 1; |
607 | ofd = open(ofname, flags, RW_USER); |
608 | if (ofd == -1) { |
609 | perror(ofname); |
610 | close(ifd); |
611 | exit_code = ERROR; |
612 | return ERROR; |
613 | } |
614 | |
615 | /* Check for name truncation on new file (1234567890123.gz) */ |
616 | if (fstat(ofd, &ostat) != 0) { |
617 | fprintf(stderr, "%s: ", progname); |
618 | perror(ofname); |
619 | close(ifd); close(ofd); |
620 | unlink(ofname); |
621 | exit_code = ERROR; |
622 | return ERROR; |
623 | } |
624 | if (!name_too_long(ofname, &ostat)) return OK; |
625 | |
626 | if (decompress) { |
627 | /* name might be too long if an original name was saved */ |
628 | WARN((stderr, "%s: %s: warning, name truncated\n", |
629 | progname, ofname)); |
630 | return OK; |
631 | } |
632 | close(ofd); |
633 | unlink(ofname); |
634 | shorten_name(ofname); |
635 | } |
636 | } |
637 | |
638 | /* ======================================================================== |
639 | * Use lstat if available, except for -c or -f. Use stat otherwise. |
640 | * This allows links when not removing the original file. |
641 | */ |
642 | local int do_stat(name, sbuf) |
643 | char *name; |
644 | struct stat *sbuf; |
645 | { |
646 | errno = 0; |
647 | if (!to_stdout && !force) { |
648 | return lstat(name, sbuf); |
649 | } |
650 | return stat(name, sbuf); |
651 | } |
652 | |
653 | /* ======================================================================== |
654 | * Return a pointer to the 'z' suffix of a file name, or NULL. For all |
655 | * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are |
656 | * accepted suffixes, in addition to the value of the --suffix option. |
657 | * ".tgz" is a useful convention for tar.z files on systems limited |
658 | * to 3 characters extensions. On such systems, ".?z" and ".??z" are |
659 | * also accepted suffixes. For Unix, we do not want to accept any |
660 | * .??z suffix as indicating a compressed file; some people use .xyz |
661 | * to denote volume data. |
662 | * On systems allowing multiple versions of the same file (such as VMS), |
663 | * this function removes any version suffix in the given name. |
664 | */ |
665 | local char *get_suffix(name) |
666 | char *name; |
667 | { |
668 | int nlen, slen; |
669 | char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */ |
670 | static char *known_suffixes[] = |
671 | {z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z", |
672 | NULL}; |
673 | char **suf = known_suffixes; |
674 | |
675 | if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */ |
676 | |
677 | nlen = strlen(name); |
678 | if (nlen <= MAX_SUFFIX+2) { |
679 | strcpy(suffix, name); |
680 | } else { |
681 | strcpy(suffix, name+nlen-MAX_SUFFIX-2); |
682 | } |
683 | strlwr(suffix); |
684 | slen = strlen(suffix); |
685 | do { |
686 | int s = strlen(*suf); |
687 | if (slen > s && suffix[slen-s-1] != PATH_SEP |
688 | && strequ(suffix + slen - s, *suf)) { |
689 | return name+nlen-s; |
690 | } |
691 | } while (*++suf != NULL); |
692 | |
693 | return NULL; |
694 | } |
695 | |
696 | |
697 | /* ======================================================================== |
698 | * Set ifname to the input file name (with a suffix appended if necessary) |
699 | * and istat to its stats. For decompression, if no file exists with the |
700 | * original name, try adding successively z_suffix, .gz, .z, -z and .Z. |
701 | * For MSDOS, we try only z_suffix and z. |
702 | * Return OK or ERROR. |
703 | */ |
704 | local int get_istat(iname, sbuf) |
705 | char *iname; |
706 | struct stat *sbuf; |
707 | { |
708 | int ilen; /* strlen(ifname) */ |
709 | static char *suffixes[] = {z_suffix, ".gz", ".z", "-z", ".Z", NULL}; |
710 | char **suf = suffixes; |
711 | char *s; |
712 | |
713 | strcpy(ifname, iname); |
714 | |
715 | /* If input file exists, return OK. */ |
716 | if (do_stat(ifname, sbuf) == 0) return OK; |
717 | |
718 | if (!decompress || errno != ENOENT) { |
719 | perror(ifname); |
720 | exit_code = ERROR; |
721 | return ERROR; |
722 | } |
723 | /* file.ext doesn't exist, try adding a suffix (after removing any |
724 | * version number for VMS). |
725 | */ |
726 | s = get_suffix(ifname); |
727 | if (s != NULL) { |
728 | perror(ifname); /* ifname already has z suffix and does not exist */ |
729 | exit_code = ERROR; |
730 | return ERROR; |
731 | } |
732 | ilen = strlen(ifname); |
733 | if (strequ(z_suffix, ".gz")) suf++; |
734 | |
735 | /* Search for all suffixes */ |
736 | do { |
737 | s = *suf; |
738 | strcat(ifname, s); |
739 | if (do_stat(ifname, sbuf) == 0) return OK; |
740 | ifname[ilen] = '\0'; |
741 | } while (*++suf != NULL); |
742 | |
743 | /* No suffix found, complain using z_suffix: */ |
744 | strcat(ifname, z_suffix); |
745 | perror(ifname); |
746 | exit_code = ERROR; |
747 | return ERROR; |
748 | } |
749 | |
750 | /* ======================================================================== |
751 | * Generate ofname given ifname. Return OK, or WARNING if file must be skipped. |
752 | * Sets save_orig_name to true if the file name has been truncated. |
753 | */ |
754 | local int make_ofname() |
755 | { |
756 | char *suff; /* ofname z suffix */ |
757 | |
758 | strcpy(ofname, ifname); |
759 | /* strip a version number if any and get the gzip suffix if present: */ |
760 | suff = get_suffix(ofname); |
761 | |
762 | if (decompress) { |
763 | if (suff == NULL) { |
764 | /* Whith -t or -l, try all files (even without .gz suffix) |
765 | * except with -r (behave as with just -dr). |
766 | */ |
767 | if (test) return OK; |
768 | |
769 | /* Avoid annoying messages with -r */ |
770 | if (verbose || !quiet) { |
771 | WARN((stderr,"%s: %s: unknown suffix -- ignored\n", |
772 | progname, ifname)); |
773 | } |
774 | return WARNING; |
775 | } |
776 | /* Make a special case for .tgz and .taz: */ |
777 | strlwr(suff); |
778 | if (strequ(suff, ".tgz") || strequ(suff, ".taz")) { |
779 | strcpy(suff, ".tar"); |
780 | } else { |
781 | *suff = '\0'; /* strip the z suffix */ |
782 | } |
783 | /* ofname might be changed later if infile contains an original name */ |
784 | |
785 | } else if (suff != NULL) { |
786 | /* Avoid annoying messages with -r (see treat_dir()) */ |
787 | if (verbose || !quiet) { |
788 | fprintf(stderr, "%s: %s already has %s suffix -- unchanged\n", |
789 | progname, ifname, suff); |
790 | } |
791 | if (exit_code == OK) exit_code = WARNING; |
792 | return WARNING; |
793 | } else { |
794 | save_orig_name = 0; |
795 | strcat(ofname, z_suffix); |
796 | |
797 | } /* decompress ? */ |
798 | return OK; |
799 | } |
800 | |
801 | |
802 | /* ======================================================================== |
803 | * Check the magic number of the input file and update ofname if an |
804 | * original name was given and to_stdout is not set. |
805 | * Return the compression method, -1 for error, -2 for warning. |
806 | * Set inptr to the offset of the next byte to be processed. |
807 | * Updates time_stamp if there is one and --no-time is not used. |
808 | * This function may be called repeatedly for an input file consisting |
809 | * of several contiguous gzip'ed members. |
810 | * IN assertions: there is at least one remaining compressed member. |
811 | * If the member is a zip file, it must be the only one. |
812 | */ |
813 | local int get_method() |
814 | { |
815 | uch flags; /* compression flags */ |
816 | char magic[2]; /* magic header */ |
817 | ulg stamp; /* time stamp */ |
818 | |
819 | /* If --force and --stdout, zcat == cat, so do not complain about |
820 | * premature end of file: use try_byte instead of get_byte. |
821 | */ |
822 | if (force && to_stdout) { |
823 | magic[0] = (char)try_byte(); |
824 | magic[1] = (char)try_byte(); |
825 | /* If try_byte returned EOF, magic[1] == 0xff */ |
826 | } else { |
827 | magic[0] = (char)get_byte(); |
828 | magic[1] = (char)get_byte(); |
829 | } |
830 | method = -1; /* unknown yet */ |
831 | part_nb++; /* number of parts in gzip file */ |
832 | header_bytes = 0; |
833 | last_member = RECORD_IO; |
834 | /* assume multiple members in gzip file except for record oriented I/O */ |
835 | |
836 | if (memcmp(magic, GZIP_MAGIC, 2) == 0 |
837 | || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) { |
838 | |
839 | method = (int)get_byte(); |
840 | if (method != DEFLATED) { |
841 | fprintf(stderr, |
842 | "%s: %s: unknown method %d -- get newer version of gzip\n", |
843 | progname, ifname, method); |
844 | exit_code = ERROR; |
845 | return -1; |
846 | } |
847 | work = unzip; |
848 | flags = (uch)get_byte(); |
849 | |
850 | if ((flags & ENCRYPTED) != 0) { |
851 | fprintf(stderr, |
852 | "%s: %s is encrypted -- get newer version of gzip\n", |
853 | progname, ifname); |
854 | exit_code = ERROR; |
855 | return -1; |
856 | } |
857 | if ((flags & CONTINUATION) != 0) { |
858 | fprintf(stderr, |
859 | "%s: %s is a a multi-part gzip file -- get newer version of gzip\n", |
860 | progname, ifname); |
861 | exit_code = ERROR; |
862 | if (force <= 1) return -1; |
863 | } |
864 | if ((flags & RESERVED) != 0) { |
865 | fprintf(stderr, |
866 | "%s: %s has flags 0x%x -- get newer version of gzip\n", |
867 | progname, ifname, flags); |
868 | exit_code = ERROR; |
869 | if (force <= 1) return -1; |
870 | } |
871 | stamp = (ulg)get_byte(); |
872 | stamp |= ((ulg)get_byte()) << 8; |
873 | stamp |= ((ulg)get_byte()) << 16; |
874 | stamp |= ((ulg)get_byte()) << 24; |
875 | if (stamp != 0 && !no_time) time_stamp = stamp; |
876 | |
877 | (void)get_byte(); /* Ignore extra flags for the moment */ |
878 | (void)get_byte(); /* Ignore OS type for the moment */ |
879 | |
880 | if ((flags & CONTINUATION) != 0) { |
881 | unsigned part = (unsigned)get_byte(); |
882 | part |= ((unsigned)get_byte())<<8; |
883 | if (verbose) { |
884 | fprintf(stderr,"%s: %s: part number %u\n", |
885 | progname, ifname, part); |
886 | } |
887 | } |
888 | if ((flags & EXTRA_FIELD) != 0) { |
889 | unsigned len = (unsigned)get_byte(); |
890 | len |= ((unsigned)get_byte())<<8; |
891 | if (verbose) { |
892 | fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n", |
893 | progname, ifname, len); |
894 | } |
895 | while (len--) (void)get_byte(); |
896 | } |
897 | |
898 | /* Get original file name if it was truncated */ |
899 | if ((flags & ORIG_NAME) != 0) { |
900 | if (no_name || to_stdout || part_nb > 1) { |
901 | /* Discard the old name */ |
902 | char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */ |
903 | do {c=get_byte();} while (c != 0); |
904 | } else { |
905 | /* Copy the base name. Keep a directory prefix intact. */ |
906 | char *p = basename(ofname); |
907 | for (;;) { |
908 | *p = (char)get_char(); |
909 | if (*p++ == '\0') break; |
910 | if (p >= ofname+sizeof(ofname)) { |
911 | error("corrupted input -- file name too large"); |
912 | } |
913 | } |
914 | } /* no_name || to_stdout */ |
915 | } /* ORIG_NAME */ |
916 | |
917 | /* Discard file comment if any */ |
918 | if ((flags & COMMENT) != 0) { |
919 | while (get_char() != 0) /* null */ ; |
920 | } |
921 | if (part_nb == 1) { |
922 | header_bytes = inptr + 2*sizeof(long); /* include crc and size */ |
923 | } |
924 | } else if (force && to_stdout) { /* pass input unchanged */ |
925 | method = STORED; |
926 | work = copy; |
927 | inptr = 0; |
928 | last_member = 1; |
929 | } |
930 | if (method >= 0) return method; |
931 | |
932 | if (part_nb == 1) { |
933 | fprintf(stderr, "\n%s: %s: not in gzip format\n", progname, ifname); |
934 | exit_code = ERROR; |
935 | return -1; |
936 | } else { |
937 | WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n", |
938 | progname, ifname)); |
939 | return -2; |
940 | } |
941 | } |
942 | |
943 | |
944 | /* ======================================================================== |
945 | * Return true if the two stat structures correspond to the same file. |
946 | */ |
947 | local int same_file(stat1, stat2) |
948 | struct stat *stat1; |
949 | struct stat *stat2; |
950 | { |
951 | return stat1->st_ino == stat2->st_ino |
952 | && stat1->st_dev == stat2->st_dev |
953 | #ifdef NO_ST_INO |
954 | /* Can't rely on st_ino and st_dev, use other fields: */ |
955 | && stat1->st_mode == stat2->st_mode |
956 | && stat1->st_uid == stat2->st_uid |
957 | && stat1->st_gid == stat2->st_gid |
958 | && stat1->st_size == stat2->st_size |
959 | && stat1->st_atime == stat2->st_atime |
960 | && stat1->st_mtime == stat2->st_mtime |
961 | && stat1->st_ctime == stat2->st_ctime |
962 | #endif |
963 | ; |
964 | } |
965 | |
966 | /* ======================================================================== |
967 | * Return true if a file name is ambiguous because the operating system |
968 | * truncates file names. |
969 | */ |
970 | local int name_too_long(name, statb) |
971 | char *name; /* file name to check */ |
972 | struct stat *statb; /* stat buf for this file name */ |
973 | { |
974 | int s = strlen(name); |
975 | char c = name[s-1]; |
976 | struct stat tstat; /* stat for truncated name */ |
977 | int res; |
978 | |
979 | tstat = *statb; /* Just in case OS does not fill all fields */ |
980 | name[s-1] = '\0'; |
981 | res = stat(name, &tstat) == 0 && same_file(statb, &tstat); |
982 | name[s-1] = c; |
983 | Trace((stderr, " too_long(%s) => %d\n", name, res)); |
984 | return res; |
985 | } |
986 | |
987 | /* ======================================================================== |
988 | * Shorten the given name by one character, or replace a .tar extension |
989 | * with .tgz. Truncate the last part of the name which is longer than |
990 | * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name |
991 | * has only parts shorter than MIN_PART truncate the longest part. |
992 | * For decompression, just remove the last character of the name. |
993 | * |
994 | * IN assertion: for compression, the suffix of the given name is z_suffix. |
995 | */ |
996 | local void shorten_name(name) |
997 | char *name; |
998 | { |
999 | int len; /* length of name without z_suffix */ |
1000 | char *trunc = NULL; /* character to be truncated */ |
1001 | int plen; /* current part length */ |
1002 | int min_part = MIN_PART; /* current minimum part length */ |
1003 | char *p; |
1004 | |
1005 | len = strlen(name); |
1006 | if (decompress) { |
1007 | if (len <= 1) error("name too short"); |
1008 | name[len-1] = '\0'; |
1009 | return; |
1010 | } |
1011 | p = get_suffix(name); |
1012 | if (p == NULL) error("can't recover suffix\n"); |
1013 | *p = '\0'; |
1014 | save_orig_name = 1; |
1015 | |
1016 | /* compress 1234567890.tar to 1234567890.tgz */ |
1017 | if (len > 4 && strequ(p-4, ".tar")) { |
1018 | strcpy(p-4, ".tgz"); |
1019 | return; |
1020 | } |
1021 | /* Try keeping short extensions intact: |
1022 | * 1234.678.012.gz -> 123.678.012.gz |
1023 | */ |
1024 | do { |
1025 | p = strrchr(name, PATH_SEP); |
1026 | p = p ? p+1 : name; |
1027 | while (*p) { |
1028 | plen = strcspn(p, "."); |
1029 | p += plen; |
1030 | if (plen > min_part) trunc = p-1; |
1031 | if (*p) p++; |
1032 | } |
1033 | } while (trunc == NULL && --min_part != 0); |
1034 | |
1035 | if (trunc != NULL) { |
1036 | do { |
1037 | trunc[0] = trunc[1]; |
1038 | } while (*trunc++); |
1039 | trunc--; |
1040 | } else { |
1041 | trunc = strrchr(name, '.'); |
1042 | if (trunc == NULL) error("internal error in shorten_name"); |
1043 | if (trunc[1] == '\0') trunc--; /* force truncation */ |
1044 | } |
1045 | strcpy(trunc, z_suffix); |
1046 | } |
1047 | |
1048 | /* ======================================================================== |
1049 | * If compressing to a file, check if ofname is not ambiguous |
1050 | * because the operating system truncates names. Otherwise, generate |
1051 | * a new ofname and save the original name in the compressed file. |
1052 | * If the compressed file already exists, ask for confirmation. |
1053 | * The check for name truncation is made dynamically, because different |
1054 | * file systems on the same OS might use different truncation rules (on SVR4 |
1055 | * s5 truncates to 14 chars and ufs does not truncate). |
1056 | * This function returns -1 if the file must be skipped, and |
1057 | * updates save_orig_name if necessary. |
1058 | * IN assertions: save_orig_name is already set if ofname has been |
1059 | * already truncated because of NO_MULTIPLE_DOTS. The input file has |
1060 | * already been open and istat is set. |
1061 | */ |
1062 | local int check_ofname() |
1063 | { |
1064 | struct stat ostat; /* stat for ofname */ |
1065 | |
1066 | #ifdef ENAMETOOLONG |
1067 | /* Check for strictly conforming Posix systems (which return ENAMETOOLONG |
1068 | * instead of silently truncating filenames). |
1069 | */ |
1070 | errno = 0; |
1071 | while (stat(ofname, &ostat) != 0) { |
1072 | if (errno != ENAMETOOLONG) return 0; /* ofname does not exist */ |
1073 | shorten_name(ofname); |
1074 | } |
1075 | #else |
1076 | if (stat(ofname, &ostat) != 0) return 0; |
1077 | #endif |
1078 | /* Check for name truncation on existing file. Do this even on systems |
1079 | * defining ENAMETOOLONG, because on most systems the strict Posix |
1080 | * behavior is disabled by default (silent name truncation allowed). |
1081 | */ |
1082 | if (!decompress && name_too_long(ofname, &ostat)) { |
1083 | shorten_name(ofname); |
1084 | if (stat(ofname, &ostat) != 0) return 0; |
1085 | } |
1086 | |
1087 | /* Check that the input and output files are different (could be |
1088 | * the same by name truncation or links). |
1089 | */ |
1090 | if (same_file(&istat, &ostat)) { |
1091 | if (strequ(ifname, ofname)) { |
1092 | fprintf(stderr, "%s: %s: cannot %scompress onto itself\n", |
1093 | progname, ifname, decompress ? "de" : ""); |
1094 | } else { |
1095 | fprintf(stderr, "%s: %s and %s are the same file\n", |
1096 | progname, ifname, ofname); |
1097 | } |
1098 | exit_code = ERROR; |
1099 | return ERROR; |
1100 | } |
1101 | /* Ask permission to overwrite the existing file */ |
1102 | if (!force) { |
1103 | #if 0 |
1104 | char response[80]; |
1105 | strcpy(response,"n"); |
1106 | fprintf(stderr, "%s: %s already exists;", progname, ofname); |
1107 | if (foreground && isatty(fileno(stdin))) { |
1108 | fprintf(stderr, " do you wish to overwrite (y or n)? "); |
1109 | (void)fgets(response, sizeof(response)-1, stdin); |
1110 | } |
1111 | if (tolow(*response) != 'y') { |
1112 | fprintf(stderr, "\tnot overwritten\n"); |
1113 | #endif |
1114 | if (exit_code == OK) exit_code = WARNING; |
1115 | return ERROR; |
1116 | #if 0 |
1117 | } |
1118 | #endif |
1119 | } |
1120 | (void) chmod(ofname, 0777); |
1121 | if (unlink(ofname)) { |
1122 | fprintf(stderr, "%s: ", progname); |
1123 | perror(ofname); |
1124 | exit_code = ERROR; |
1125 | return ERROR; |
1126 | } |
1127 | return OK; |
1128 | } |
1129 | |
1130 | |
1131 | /* ======================================================================== |
1132 | * Set the access and modification times from the given stat buffer. |
1133 | */ |
1134 | local void reset_times (name, statb) |
1135 | char *name; |
1136 | struct stat *statb; |
1137 | { |
1138 | struct utimbuf timep; |
1139 | |
1140 | /* Copy the time stamp */ |
1141 | timep.actime = statb->st_atime; |
1142 | timep.modtime = statb->st_mtime; |
1143 | |
1144 | /* Some systems (at least OS/2) do not support utime on directories */ |
1145 | if (utime(name, &timep) && !S_ISDIR(statb->st_mode)) { |
1146 | WARN((stderr, "%s: ", progname)); |
1147 | if (!quiet) perror(ofname); |
1148 | } |
1149 | } |
1150 | |
1151 | |
1152 | /* ======================================================================== |
1153 | * Copy modes, times, ownership from input file to output file. |
1154 | * IN assertion: to_stdout is false. |
1155 | */ |
1156 | local void copy_stat(ifstat) |
1157 | struct stat *ifstat; |
1158 | { |
1159 | if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp) { |
1160 | ifstat->st_mtime = time_stamp; |
1161 | if (verbose > 1) { |
1162 | fprintf(stderr, "%s: time stamp restored\n", ofname); |
1163 | } |
1164 | } |
1165 | reset_times(ofname, ifstat); |
1166 | |
1167 | /* Copy the protection modes */ |
1168 | if (chmod(ofname, ifstat->st_mode & 07777)) { |
1169 | WARN((stderr, "%s: ", progname)); |
1170 | if (!quiet) perror(ofname); |
1171 | } |
1172 | |
1173 | chown(ofname, ifstat->st_uid, ifstat->st_gid); /* Copy ownership */ |
1174 | |
1175 | remove_ofname = 0; |
1176 | /* It's now safe to remove the input file: */ |
1177 | (void) chmod(ifname, 0777); |
1178 | if (unlink(ifname)) { |
1179 | WARN((stderr, "%s: ", progname)); |
1180 | if (!quiet) perror(ifname); |
1181 | } |
1182 | } |
1183 | |
1184 | /* ======================================================================== |
1185 | * Free all dynamically allocated variables and exit with the given code. |
1186 | */ |
1187 | local void do_exit(exitcode) |
1188 | int exitcode; |
1189 | { |
1190 | static int in_exit = 0; |
1191 | |
1192 | if (in_exit) exit(exitcode); |
1193 | in_exit = 1; |
1194 | if (env != NULL) free(env), env = NULL; |
1195 | if (args != NULL) free((char*)args), args = NULL; |
1196 | FREE(inbuf); |
1197 | FREE(outbuf); |
1198 | FREE(d_buf); |
1199 | FREE(window); |
1200 | FREE(tab_prefix); |
1201 | exit(exitcode); |
1202 | } |
1203 | |
1204 | /* ======================================================================== |
1205 | * Signal and error handler. |
1206 | */ |
1207 | void abort_gzip() |
1208 | { |
1209 | if (remove_ofname) { |
1210 | close(ofd); |
1211 | unlink (ofname); |
1212 | } |
1213 | do_exit(ERROR); |
1214 | } |