| GCC Code Coverage Report | |||||||||||||||||||||
        
  | 
    |||||||||||||||||||||
| Line | Branch | Exec | Source | 
1  | 
    /* $OpenBSD: main.c,v 1.94 2016/09/03 13:26:50 tedu Exp $ */  | 
    ||
2  | 
    |||
3  | 
    /*  | 
    ||
4  | 
    * Copyright (c) 1992, 1993  | 
    ||
5  | 
    * The Regents of the University of California. All rights reserved.  | 
    ||
6  | 
    * Copyright (c) 1997-2002 Michael Shalayeff  | 
    ||
7  | 
    *  | 
    ||
8  | 
    * Redistribution and use in source and binary forms, with or without  | 
    ||
9  | 
    * modification, are permitted provided that the following conditions  | 
    ||
10  | 
    * are met:  | 
    ||
11  | 
    * 1. Redistributions of source code must retain the above copyright  | 
    ||
12  | 
    * notice, this list of conditions and the following disclaimer.  | 
    ||
13  | 
    * 2. Redistributions in binary form must reproduce the above copyright  | 
    ||
14  | 
    * notice, this list of conditions and the following disclaimer in the  | 
    ||
15  | 
    * documentation and/or other materials provided with the distribution.  | 
    ||
16  | 
    * 3. Neither the name of the University nor the names of its contributors  | 
    ||
17  | 
    * may be used to endorse or promote products derived from this software  | 
    ||
18  | 
    * without specific prior written permission.  | 
    ||
19  | 
    *  | 
    ||
20  | 
    * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR  | 
    ||
21  | 
    * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES  | 
    ||
22  | 
    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  | 
    ||
23  | 
    * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,  | 
    ||
24  | 
    * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES  | 
    ||
25  | 
    * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR  | 
    ||
26  | 
    * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  | 
    ||
27  | 
    * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,  | 
    ||
28  | 
    * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  | 
    ||
29  | 
    * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF  | 
    ||
30  | 
    * THE POSSIBILITY OF SUCH DAMAGE.  | 
    ||
31  | 
    */  | 
    ||
32  | 
    |||
33  | 
    #include <sys/time.h>  | 
    ||
34  | 
    #include <sys/stat.h>  | 
    ||
35  | 
    |||
36  | 
    #include <getopt.h>  | 
    ||
37  | 
    #include <err.h>  | 
    ||
38  | 
    #include <errno.h>  | 
    ||
39  | 
    #include <fts.h>  | 
    ||
40  | 
    #include <libgen.h>  | 
    ||
41  | 
    #include <stdio.h>  | 
    ||
42  | 
    #include <stdlib.h>  | 
    ||
43  | 
    #include <stdbool.h>  | 
    ||
44  | 
    #include <string.h>  | 
    ||
45  | 
    #include <unistd.h>  | 
    ||
46  | 
    #include <limits.h>  | 
    ||
47  | 
    #include <fcntl.h>  | 
    ||
48  | 
    #include <paths.h>  | 
    ||
49  | 
    #include "compress.h"  | 
    ||
50  | 
    |||
51  | 
    #define min(a,b) ((a) < (b)? (a) : (b))  | 
    ||
52  | 
    |||
53  | 
    int cat, decomp, pipin, force, verbose, testmode, list, recurse, storename;  | 
    ||
54  | 
    extern char *__progname;  | 
    ||
55  | 
    |||
56  | 
    const struct compressor { | 
    ||
57  | 
    const char *name;  | 
    ||
58  | 
    const char *suffix;  | 
    ||
59  | 
    const u_char *magic;  | 
    ||
60  | 
    const char *comp_opts;  | 
    ||
61  | 
    const char *decomp_opts;  | 
    ||
62  | 
    const char *cat_opts;  | 
    ||
63  | 
    void *(*ropen)(int, char *, int);  | 
    ||
64  | 
    int (*read)(void *, char *, int);  | 
    ||
65  | 
    #ifndef SMALL  | 
    ||
66  | 
    void *(*wopen)(int, char *, int, u_int32_t);  | 
    ||
67  | 
    int (*write)(void *, const char *, int);  | 
    ||
68  | 
    #endif  | 
    ||
69  | 
    int (*close)(void *, struct z_info *, const char *, struct stat *);  | 
    ||
70  | 
    } c_table[] = { | 
    ||
71  | 
    #define M_DEFLATE (&c_table[0])  | 
    ||
72  | 
    	{ | 
    ||
73  | 
    "deflate",  | 
    ||
74  | 
    ".gz",  | 
    ||
75  | 
    "\037\213",  | 
    ||
76  | 
    "123456789ab:cdfhLlNnOo:qrS:tVv",  | 
    ||
77  | 
    "cfhLlNno:qrtVv",  | 
    ||
78  | 
    "fhqr",  | 
    ||
79  | 
    gz_ropen,  | 
    ||
80  | 
    gz_read,  | 
    ||
81  | 
    #ifndef SMALL  | 
    ||
82  | 
    gz_wopen,  | 
    ||
83  | 
    gz_write,  | 
    ||
84  | 
    #endif  | 
    ||
85  | 
    gz_close  | 
    ||
86  | 
    },  | 
    ||
87  | 
    #define M_COMPRESS (&c_table[1])  | 
    ||
88  | 
    #ifndef SMALL  | 
    ||
89  | 
    	{ | 
    ||
90  | 
    "compress",  | 
    ||
91  | 
    ".Z",  | 
    ||
92  | 
    "\037\235",  | 
    ||
93  | 
    "123456789ab:cdfghlNnOo:qrS:tv",  | 
    ||
94  | 
    "cfhlNno:qrtv",  | 
    ||
95  | 
    "fghqr",  | 
    ||
96  | 
    z_ropen,  | 
    ||
97  | 
    zread,  | 
    ||
98  | 
    z_wopen,  | 
    ||
99  | 
    zwrite,  | 
    ||
100  | 
    z_close  | 
    ||
101  | 
    },  | 
    ||
102  | 
    #endif /* SMALL */  | 
    ||
103  | 
      { NULL } | 
    ||
104  | 
    };  | 
    ||
105  | 
    |||
106  | 
    #ifndef SMALL  | 
    ||
107  | 
    const struct compressor null_method = { | 
    ||
108  | 
    "null",  | 
    ||
109  | 
    ".nul",  | 
    ||
110  | 
    "XX",  | 
    ||
111  | 
    "123456789ab:cdfghlNnOo:qrS:tv",  | 
    ||
112  | 
    "cfhlNno:qrtv",  | 
    ||
113  | 
    "fghqr",  | 
    ||
114  | 
    null_ropen,  | 
    ||
115  | 
    null_read,  | 
    ||
116  | 
    null_wopen,  | 
    ||
117  | 
    null_write,  | 
    ||
118  | 
    null_close  | 
    ||
119  | 
    };  | 
    ||
120  | 
    #endif /* SMALL */  | 
    ||
121  | 
    |||
122  | 
    int permission(const char *);  | 
    ||
123  | 
    __dead void usage(int);  | 
    ||
124  | 
    int docompress(const char *, char *, const struct compressor *,  | 
    ||
125  | 
    int, struct stat *);  | 
    ||
126  | 
    int dodecompress(const char *, char *, struct stat *);  | 
    ||
127  | 
    const struct compressor *check_method(int);  | 
    ||
128  | 
    const char *check_suffix(const char *);  | 
    ||
129  | 
    char *set_outfile(const char *, char *, size_t);  | 
    ||
130  | 
    void list_stats(const char *, const struct compressor *, struct z_info *);  | 
    ||
131  | 
    void verbose_info(const char *, off_t, off_t, u_int32_t);  | 
    ||
132  | 
    |||
133  | 
    const struct option longopts[] = { | 
    ||
134  | 
    #ifndef SMALL  | 
    ||
135  | 
    	{ "ascii",	no_argument,		0, 'a' }, | 
    ||
136  | 
    	{ "stdout",	no_argument,		0, 'c' }, | 
    ||
137  | 
    	{ "to-stdout",	no_argument,		0, 'c' }, | 
    ||
138  | 
    	{ "decompress",	no_argument,		0, 'd' }, | 
    ||
139  | 
    	{ "uncompress",	no_argument,		0, 'd' }, | 
    ||
140  | 
    	{ "force",	no_argument,		0, 'f' }, | 
    ||
141  | 
    	{ "help",	no_argument,		0, 'h' }, | 
    ||
142  | 
    	{ "list",	no_argument,		0, 'l' }, | 
    ||
143  | 
    	{ "license",	no_argument,		0, 'L' }, | 
    ||
144  | 
    	{ "no-name",	no_argument,		0, 'n' }, | 
    ||
145  | 
    	{ "name",	no_argument,		0, 'N' }, | 
    ||
146  | 
    	{ "quiet",	no_argument,		0, 'q' }, | 
    ||
147  | 
    	{ "recursive",	no_argument,		0, 'r' }, | 
    ||
148  | 
    	{ "suffix",	required_argument,	0, 'S' }, | 
    ||
149  | 
    	{ "test",	no_argument,		0, 't' }, | 
    ||
150  | 
    	{ "verbose",	no_argument,		0, 'v' }, | 
    ||
151  | 
    	{ "version",	no_argument,		0, 'V' }, | 
    ||
152  | 
    	{ "fast",	no_argument,		0, '1' }, | 
    ||
153  | 
    	{ "best",	no_argument,		0, '9' }, | 
    ||
154  | 
    #endif /* SMALL */  | 
    ||
155  | 
    	{ NULL } | 
    ||
156  | 
    };  | 
    ||
157  | 
    |||
158  | 
    int  | 
    ||
159  | 
    main(int argc, char *argv[])  | 
    ||
160  | 
    { | 
    ||
161  | 
    FTS *ftsp;  | 
    ||
162  | 
    FTSENT *entry;  | 
    ||
163  | 
    const struct compressor *method;  | 
    ||
164  | 
    const char *optstr, *s;  | 
    ||
165  | 
    1260  | 
    char *p, *infile;  | 
    |
166  | 
    630  | 
    char outfile[PATH_MAX], _infile[PATH_MAX], suffix[16];  | 
    |
167  | 
    int bits, ch, error, rc, cflag, oflag;  | 
    ||
168  | 
    |||
169  | 
    ✗✓ | 630  | 
    	if (pledge("stdio rpath wpath cpath fattr chown flock", NULL) == -1) | 
    
170  | 
    err(1, "pledge");  | 
    ||
171  | 
    |||
172  | 
    bits = cflag = oflag = 0;  | 
    ||
173  | 
    630  | 
    storename = -1;  | 
    |
174  | 
    630  | 
    p = __progname;  | 
    |
175  | 
    ✓✗ | 630  | 
    	if (p[0] == 'g') { | 
    
176  | 
    method = M_DEFLATE;  | 
    ||
177  | 
    bits = 6;  | 
    ||
178  | 
    630  | 
    p++;  | 
    |
179  | 
    630  | 
    	} else { | 
    |
180  | 
    #ifdef SMALL  | 
    ||
181  | 
    method = M_DEFLATE;  | 
    ||
182  | 
    #else  | 
    ||
183  | 
    method = M_COMPRESS;  | 
    ||
184  | 
    #endif /* SMALL */  | 
    ||
185  | 
    }  | 
    ||
186  | 
    630  | 
    optstr = method->comp_opts;  | 
    |
187  | 
    |||
188  | 
    630  | 
    decomp = 0;  | 
    |
189  | 
    630  | 
    pmode = MODE_COMP;  | 
    |
190  | 
    ✗✓ | 630  | 
    	if (!strcmp(p, "zcat")) { | 
    
191  | 
    decomp++;  | 
    ||
192  | 
    cflag = 1;  | 
    ||
193  | 
    pmode = MODE_CAT;  | 
    ||
194  | 
    	} else { | 
    ||
195  | 
    ✓✓✓✗ | 
    658  | 
    		if (p[0] == 'u' && p[1] == 'n') { | 
    
196  | 
    28  | 
    p += 2;  | 
    |
197  | 
    28  | 
    decomp++;  | 
    |
198  | 
    28  | 
    pmode = MODE_DECOMP;  | 
    |
199  | 
    28  | 
    }  | 
    |
200  | 
    |||
201  | 
    ✗✓✗✗ | 
    630  | 
    if (strcmp(p, "zip") &&  | 
    
202  | 
    strcmp(p, "compress"))  | 
    ||
203  | 
    errx(1, "unknown program name");  | 
    ||
204  | 
    }  | 
    ||
205  | 
    |||
206  | 
    630  | 
    strlcpy(suffix, method->suffix, sizeof(suffix));  | 
    |
207  | 
    |||
208  | 
    ✓✗✗✓ | 
    1260  | 
    	if (method == M_DEFLATE && (p = getenv("GZIP")) != NULL) { | 
    
209  | 
    char *evbuf, *last, **nargv = NULL;  | 
    ||
210  | 
    int argc_extra = 0, nargc = 0;  | 
    ||
211  | 
    |||
212  | 
    if ((evbuf = strdup(p)) == NULL)  | 
    ||
213  | 
    err(1, NULL);  | 
    ||
214  | 
    for ((p = strtok_r(evbuf, " ", &last)); p != NULL;  | 
    ||
215  | 
    		    (p = strtok_r(NULL, " ", &last))) { | 
    ||
216  | 
    			if (nargc + 1 >= argc_extra) { | 
    ||
217  | 
    argc_extra += 1024;  | 
    ||
218  | 
    nargv = reallocarray(nargv,  | 
    ||
219  | 
    argc + argc_extra + 1, sizeof(char *));  | 
    ||
220  | 
    if (nargv == NULL)  | 
    ||
221  | 
    err(1, NULL);  | 
    ||
222  | 
    }  | 
    ||
223  | 
    nargv[++nargc] = p;  | 
    ||
224  | 
    }  | 
    ||
225  | 
    		if (nargv != NULL) { | 
    ||
226  | 
    nargv[0] = *argv++;  | 
    ||
227  | 
    while ((nargv[++nargc] = *argv++))  | 
    ||
228  | 
    ;  | 
    ||
229  | 
    argv = nargv;  | 
    ||
230  | 
    argc = nargc;  | 
    ||
231  | 
    }  | 
    ||
232  | 
    }  | 
    ||
233  | 
    |||
234  | 
    630  | 
    optstr += pmode;  | 
    |
235  | 
    ✓✓ | 3506  | 
    while ((ch = getopt_long(argc, argv, optstr, longopts, NULL)) != -1)  | 
    
236  | 
    ✗✗✗✗ ✗✗✗✗ ✗✗✗✓ ✓✓✗✗ ✗✗✗✗ ✗✗✓✗ ✓✗✗✗ ✗  | 
    1123  | 
    		switch (ch) { | 
    
237  | 
    case '1':  | 
    ||
238  | 
    case '2':  | 
    ||
239  | 
    case '3':  | 
    ||
240  | 
    case '4':  | 
    ||
241  | 
    case '5':  | 
    ||
242  | 
    case '6':  | 
    ||
243  | 
    case '7':  | 
    ||
244  | 
    case '8':  | 
    ||
245  | 
    case '9':  | 
    ||
246  | 
    method = M_DEFLATE;  | 
    ||
247  | 
    strlcpy(suffix, method->suffix, sizeof(suffix));  | 
    ||
248  | 
    bits = ch - '0';  | 
    ||
249  | 
    break;  | 
    ||
250  | 
    case 'a':  | 
    ||
251  | 
    			warnx("option -a is ignored on this system"); | 
    ||
252  | 
    break;  | 
    ||
253  | 
    case 'b':  | 
    ||
254  | 
    bits = strtol(optarg, &p, 10);  | 
    ||
255  | 
    /*  | 
    ||
256  | 
    * POSIX 1002.3 says 9 <= bits <= 14 for portable  | 
    ||
257  | 
    * apps, but says the implementation may allow  | 
    ||
258  | 
    * greater.  | 
    ||
259  | 
    */  | 
    ||
260  | 
    if (*p)  | 
    ||
261  | 
    errx(1, "illegal bit count -- %s", optarg);  | 
    ||
262  | 
    break;  | 
    ||
263  | 
    case 'c':  | 
    ||
264  | 
    cflag = 1;  | 
    ||
265  | 
    27  | 
    break;  | 
    |
266  | 
    case 'd': /* Backward compatible. */  | 
    ||
267  | 
    18  | 
    decomp++;  | 
    |
268  | 
    18  | 
    break;  | 
    |
269  | 
    case 'f':  | 
    ||
270  | 
    10  | 
    force++;  | 
    |
271  | 
    10  | 
    break;  | 
    |
272  | 
    case 'g':  | 
    ||
273  | 
    method = M_DEFLATE;  | 
    ||
274  | 
    strlcpy(suffix, method->suffix, sizeof(suffix));  | 
    ||
275  | 
    bits = 6;  | 
    ||
276  | 
    break;  | 
    ||
277  | 
    case 'l':  | 
    ||
278  | 
    list++;  | 
    ||
279  | 
    testmode = 1;  | 
    ||
280  | 
    decomp++;  | 
    ||
281  | 
    break;  | 
    ||
282  | 
    case 'n':  | 
    ||
283  | 
    storename = 0;  | 
    ||
284  | 
    break;  | 
    ||
285  | 
    case 'N':  | 
    ||
286  | 
    storename = 1;  | 
    ||
287  | 
    break;  | 
    ||
288  | 
    #ifndef SMALL  | 
    ||
289  | 
    case 'O':  | 
    ||
290  | 
    method = M_COMPRESS;  | 
    ||
291  | 
    strlcpy(suffix, method->suffix, sizeof(suffix));  | 
    ||
292  | 
    break;  | 
    ||
293  | 
    #endif /* SMALL */  | 
    ||
294  | 
    case 'o':  | 
    ||
295  | 
    if (strlcpy(outfile, optarg,  | 
    ||
296  | 
    sizeof(outfile)) >= sizeof(outfile))  | 
    ||
297  | 
    errx(1, "-o argument is too long");  | 
    ||
298  | 
    oflag = 1;  | 
    ||
299  | 
    break;  | 
    ||
300  | 
    case 'q':  | 
    ||
301  | 
    verbose = -1;  | 
    ||
302  | 
    break;  | 
    ||
303  | 
    case 'S':  | 
    ||
304  | 
    p = suffix;  | 
    ||
305  | 
    if (optarg[0] != '.')  | 
    ||
306  | 
    *p++ = '.';  | 
    ||
307  | 
    strlcpy(p, optarg, sizeof(suffix) - (p - suffix));  | 
    ||
308  | 
    p = optarg;  | 
    ||
309  | 
    break;  | 
    ||
310  | 
    case 't':  | 
    ||
311  | 
    533  | 
    testmode = 1;  | 
    |
312  | 
    533  | 
    decomp++;  | 
    |
313  | 
    533  | 
    break;  | 
    |
314  | 
    case 'V':  | 
    ||
315  | 
    exit (0);  | 
    ||
316  | 
    case 'v':  | 
    ||
317  | 
    535  | 
    verbose++;  | 
    |
318  | 
    535  | 
    break;  | 
    |
319  | 
    case 'L':  | 
    ||
320  | 
    exit (0);  | 
    ||
321  | 
    case 'r':  | 
    ||
322  | 
    recurse++;  | 
    ||
323  | 
    break;  | 
    ||
324  | 
    |||
325  | 
    case 'h':  | 
    ||
326  | 
    usage(0);  | 
    ||
327  | 
    break;  | 
    ||
328  | 
    default:  | 
    ||
329  | 
    usage(1);  | 
    ||
330  | 
    }  | 
    ||
331  | 
    630  | 
    argc -= optind;  | 
    |
332  | 
    630  | 
    argv += optind;  | 
    |
333  | 
    |||
334  | 
    ✓✓✓✓ | 
    700  | 
    if (cflag || testmode || (!oflag && argc == 0))  | 
    
335  | 
    ✗✓ | 600  | 
    		if (pledge("stdio rpath flock cpath wpath", NULL) == -1) | 
    
336  | 
    err(1, "pledge");  | 
    ||
337  | 
    |||
338  | 
    ✓✓ | 630  | 
    	if (argc == 0) { | 
    
339  | 
    66  | 
    argv = calloc(2, sizeof(char *));  | 
    |
340  | 
    ✗✓ | 66  | 
    if (argv == NULL)  | 
    
341  | 
    err(1, NULL);  | 
    ||
342  | 
    66  | 
    argv[0] = "-";  | 
    |
343  | 
    argc = 1;  | 
    ||
344  | 
    66  | 
    }  | 
    |
345  | 
    ✗✓✗✗ | 
    630  | 
    if (oflag && (recurse || argc > 1))  | 
    
346  | 
    errx(1, "-o option may only be used with a single input file");  | 
    ||
347  | 
    |||
348  | 
    ✗✓ | 630  | 
    if ((cat && argc) + testmode + oflag > 1)  | 
    
349  | 
    errx(1, "may not mix -o, -c, or -t options");  | 
    ||
350  | 
    /*  | 
    ||
351  | 
    * By default, when compressing store the original name and timestamp  | 
    ||
352  | 
    * in the header. Do not restore these when decompressing unless  | 
    ||
353  | 
    * the -N option is given.  | 
    ||
354  | 
    */  | 
    ||
355  | 
    ✓✗ | 630  | 
    if (storename == -1)  | 
    
356  | 
    630  | 
    storename = !decomp;  | 
    |
357  | 
    |||
358  | 
    ✗✓ | 630  | 
    if ((ftsp = fts_open(argv, FTS_PHYSICAL|FTS_NOCHDIR, 0)) == NULL)  | 
    
359  | 
    err(1, NULL);  | 
    ||
360  | 
    ✓✓ | 2530  | 
    	for (rc = SUCCESS; (entry = fts_read(ftsp)) != NULL;) { | 
    
361  | 
    635  | 
    cat = cflag;  | 
    |
362  | 
    635  | 
    pipin = 0;  | 
    |
363  | 
    635  | 
    infile = entry->fts_path;  | 
    |
364  | 
    ✓✓✓✗ | 
    701  | 
    		if (infile[0] == '-' && infile[1] == '\0') { | 
    
365  | 
    infile = "stdin";  | 
    ||
366  | 
    66  | 
    pipin++;  | 
    |
367  | 
    ✓✗ | 66  | 
    if (!oflag)  | 
    
368  | 
    66  | 
    cat = 1;  | 
    |
369  | 
    }  | 
    ||
370  | 
    else  | 
    ||
371  | 
    ✗✗✗✗ ✗✓  | 
    569  | 
    			switch (entry->fts_info) { | 
    
372  | 
    case FTS_D:  | 
    ||
373  | 
    				if (!recurse) { | 
    ||
374  | 
    					warnx("%s is a directory: ignored", | 
    ||
375  | 
    infile);  | 
    ||
376  | 
    fts_set(ftsp, entry, FTS_SKIP);  | 
    ||
377  | 
    }  | 
    ||
378  | 
    continue;  | 
    ||
379  | 
    case FTS_DP:  | 
    ||
380  | 
    continue;  | 
    ||
381  | 
    case FTS_NS:  | 
    ||
382  | 
    /*  | 
    ||
383  | 
    * If file does not exist and has no suffix,  | 
    ||
384  | 
    * tack on the default suffix and try that.  | 
    ||
385  | 
    */  | 
    ||
386  | 
    				if (entry->fts_errno == ENOENT) { | 
    ||
387  | 
    p = strrchr(entry->fts_accpath, '.');  | 
    ||
388  | 
    if ((p == NULL ||  | 
    ||
389  | 
    strcmp(p, suffix) != 0) &&  | 
    ||
390  | 
    snprintf(_infile, sizeof(_infile),  | 
    ||
391  | 
    "%s%s", infile, suffix) <  | 
    ||
392  | 
    sizeof(_infile) &&  | 
    ||
393  | 
    stat(_infile, entry->fts_statp) ==  | 
    ||
394  | 
    0 &&  | 
    ||
395  | 
    					    S_ISREG(entry->fts_statp->st_mode)) { | 
    ||
396  | 
    infile = _infile;  | 
    ||
397  | 
    break;  | 
    ||
398  | 
    }  | 
    ||
399  | 
    }  | 
    ||
400  | 
    case FTS_ERR:  | 
    ||
401  | 
    case FTS_DNR:  | 
    ||
402  | 
    				warnx("%s: %s", infile, | 
    ||
403  | 
    strerror(entry->fts_errno));  | 
    ||
404  | 
    rc = rc ? rc : WARNING;  | 
    ||
405  | 
    continue;  | 
    ||
406  | 
    default:  | 
    ||
407  | 
    ✗✓ | 569  | 
    if (!S_ISREG(entry->fts_statp->st_mode) &&  | 
    
408  | 
    !(S_ISLNK(entry->fts_statp->st_mode) &&  | 
    ||
409  | 
    				    cat)) { | 
    ||
410  | 
    					warnx("%s not a regular file%s", | 
    ||
411  | 
    infile, cat ? "" : ": unchanged");  | 
    ||
412  | 
    rc = rc ? rc : WARNING;  | 
    ||
413  | 
    continue;  | 
    ||
414  | 
    }  | 
    ||
415  | 
    break;  | 
    ||
416  | 
    }  | 
    ||
417  | 
    |||
418  | 
    ✓✓✗✓ | 
    655  | 
    		if (!decomp && !pipin && (s = check_suffix(infile)) != NULL) { | 
    
419  | 
    			warnx("%s already has %s suffix -- unchanged", | 
    ||
420  | 
    infile, s);  | 
    ||
421  | 
    rc = rc ? rc : WARNING;  | 
    ||
422  | 
    continue;  | 
    ||
423  | 
    }  | 
    ||
424  | 
    |||
425  | 
    ✓✗ | 635  | 
    		if (!oflag) { | 
    
426  | 
    ✓✓ | 635  | 
    if (cat)  | 
    
427  | 
    76  | 
    strlcpy(outfile, "stdout", sizeof(outfile));  | 
    |
428  | 
    ✓✓ | 559  | 
    			else if (decomp) { | 
    
429  | 
    ✗✓ | 1098  | 
    if (set_outfile(infile, outfile,  | 
    
430  | 
    549  | 
    				    sizeof outfile) == NULL) { | 
    |
431  | 
    					if (!recurse) { | 
    ||
432  | 
    						warnx("%s: unknown suffix: " | 
    ||
433  | 
    "ignored", infile);  | 
    ||
434  | 
    rc = rc ? rc : WARNING;  | 
    ||
435  | 
    }  | 
    ||
436  | 
    continue;  | 
    ||
437  | 
    }  | 
    ||
438  | 
    			} else { | 
    ||
439  | 
    ✗✓ | 20  | 
    if (snprintf(outfile, sizeof(outfile),  | 
    
440  | 
    10  | 
    				    "%s%s", infile, suffix) >= sizeof(outfile)) { | 
    |
441  | 
    					warnx("%s%s: name too long", | 
    ||
442  | 
    infile, suffix);  | 
    ||
443  | 
    rc = rc ? rc : WARNING;  | 
    ||
444  | 
    continue;  | 
    ||
445  | 
    }  | 
    ||
446  | 
    }  | 
    ||
447  | 
    }  | 
    ||
448  | 
    |||
449  | 
    ✓✓ | 635  | 
    if (verbose > 0 && !pipin && !list)  | 
    
450  | 
    525  | 
    fprintf(stderr, "%s:\t", infile);  | 
    |
451  | 
    |||
452  | 
    ✓✓ | 635  | 
    if (decomp)  | 
    
453  | 
    571  | 
    error = dodecompress(infile, outfile, entry->fts_statp);  | 
    |
454  | 
    else  | 
    ||
455  | 
    64  | 
    error = docompress(infile, outfile, method, bits, entry->fts_statp);  | 
    |
456  | 
    |||
457  | 
    ✓✓✓ | 635  | 
    		switch (error) { | 
    
458  | 
    case SUCCESS:  | 
    ||
459  | 
    ✓✓ | 240  | 
    			if (!cat && !testmode) { | 
    
460  | 
    ✗✓ | 150  | 
    if (!pipin && unlink(infile) && verbose >= 0)  | 
    
461  | 
    					warn("input: %s", infile); | 
    ||
462  | 
    }  | 
    ||
463  | 
    break;  | 
    ||
464  | 
    case WARNING:  | 
    ||
465  | 
    505  | 
    rc = rc ? rc : WARNING;  | 
    |
466  | 
    505  | 
    break;  | 
    |
467  | 
    default:  | 
    ||
468  | 
    rc = FAILURE;  | 
    ||
469  | 
    10  | 
    break;  | 
    |
470  | 
    }  | 
    ||
471  | 
    }  | 
    ||
472  | 
    ✗✓ | 630  | 
    if (list)  | 
    
473  | 
    list_stats(NULL, NULL, NULL);  | 
    ||
474  | 
    fts_close(ftsp);  | 
    ||
475  | 
    exit(rc);  | 
    ||
476  | 
    }  | 
    ||
477  | 
    |||
478  | 
    int  | 
    ||
479  | 
    docompress(const char *in, char *out, const struct compressor *method,  | 
    ||
480  | 
    int bits, struct stat *sb)  | 
    ||
481  | 
    { | 
    ||
482  | 
    #ifndef SMALL  | 
    ||
483  | 
    128  | 
    u_char buf[Z_BUFSIZE];  | 
    |
484  | 
    char *name;  | 
    ||
485  | 
    int error, ifd, ofd, oreg;  | 
    ||
486  | 
    void *cookie;  | 
    ||
487  | 
    ssize_t nr;  | 
    ||
488  | 
    u_int32_t mtime;  | 
    ||
489  | 
    64  | 
    struct z_info info;  | 
    |
490  | 
    64  | 
    struct stat osb;  | 
    |
491  | 
    |||
492  | 
    mtime = 0;  | 
    ||
493  | 
    oreg = 0;  | 
    ||
494  | 
    error = SUCCESS;  | 
    ||
495  | 
    name = NULL;  | 
    ||
496  | 
    cookie = NULL;  | 
    ||
497  | 
    |||
498  | 
    ✓✓ | 64  | 
    if (pipin)  | 
    
499  | 
    44  | 
    ifd = dup(STDIN_FILENO);  | 
    |
500  | 
    else  | 
    ||
501  | 
    20  | 
    ifd = open(in, O_RDONLY);  | 
    |
502  | 
    ✗✓ | 64  | 
    	if (ifd < 0) { | 
    
503  | 
    if (verbose >= 0)  | 
    ||
504  | 
    			warn("%s", in); | 
    ||
505  | 
    return (FAILURE);  | 
    ||
506  | 
    }  | 
    ||
507  | 
    |||
508  | 
    ✓✓ | 64  | 
    if (cat)  | 
    
509  | 
    54  | 
    ofd = dup(STDOUT_FILENO);  | 
    |
510  | 
    	else { | 
    ||
511  | 
    ✗✓ | 10  | 
    		if (stat(out, &osb) == 0) { | 
    
512  | 
    oreg = S_ISREG(osb.st_mode);  | 
    ||
513  | 
    			if (!force && oreg && !permission(out)) { | 
    ||
514  | 
    (void) close(ifd);  | 
    ||
515  | 
    return (WARNING);  | 
    ||
516  | 
    }  | 
    ||
517  | 
    }  | 
    ||
518  | 
    10  | 
    ofd = open(out, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR);  | 
    |
519  | 
    }  | 
    ||
520  | 
    ✗✓ | 64  | 
    	if (ofd < 0) { | 
    
521  | 
    if (verbose >= 0)  | 
    ||
522  | 
    			warn("%s", out); | 
    ||
523  | 
    (void) close(ifd);  | 
    ||
524  | 
    return (FAILURE);  | 
    ||
525  | 
    }  | 
    ||
526  | 
    |||
527  | 
    ✓✗✗✓ | 
    128  | 
    	if (method != M_COMPRESS && !force && isatty(ofd)) { | 
    
528  | 
    if (verbose >= 0)  | 
    ||
529  | 
    			warnx("%s: won't write compressed data to terminal", | 
    ||
530  | 
    out);  | 
    ||
531  | 
    (void) close(ofd);  | 
    ||
532  | 
    (void) close(ifd);  | 
    ||
533  | 
    return (FAILURE);  | 
    ||
534  | 
    }  | 
    ||
535  | 
    |||
536  | 
    ✓✓ | 64  | 
    	if (!pipin && storename) { | 
    
537  | 
    20  | 
    name = basename(in);  | 
    |
538  | 
    20  | 
    mtime = (u_int32_t)sb->st_mtime;  | 
    |
539  | 
    20  | 
    }  | 
    |
540  | 
    ✗✓ | 64  | 
    	if ((cookie = method->wopen(ofd, name, bits, mtime)) == NULL) { | 
    
541  | 
    if (verbose >= 0)  | 
    ||
542  | 
    			warn("%s", out); | 
    ||
543  | 
    if (oreg)  | 
    ||
544  | 
    (void) unlink(out);  | 
    ||
545  | 
    (void) close(ofd);  | 
    ||
546  | 
    (void) close(ifd);  | 
    ||
547  | 
    return (FAILURE);  | 
    ||
548  | 
    }  | 
    ||
549  | 
    |||
550  | 
    ✓✓ | 264  | 
    while ((nr = read(ifd, buf, sizeof(buf))) > 0)  | 
    
551  | 
    ✗✓ | 68  | 
    		if (method->write(cookie, buf, nr) != nr) { | 
    
552  | 
    if (verbose >= 0)  | 
    ||
553  | 
    				warn("%s", out); | 
    ||
554  | 
    error = FAILURE;  | 
    ||
555  | 
    break;  | 
    ||
556  | 
    }  | 
    ||
557  | 
    |||
558  | 
    ✗✓ | 64  | 
    	if (!error && nr < 0) { | 
    
559  | 
    if (verbose >= 0)  | 
    ||
560  | 
    			warn("%s", in); | 
    ||
561  | 
    error = FAILURE;  | 
    ||
562  | 
    }  | 
    ||
563  | 
    |||
564  | 
    ✗✓ | 64  | 
    	if (method->close(cookie, &info, out, sb)) { | 
    
565  | 
    if (!error && verbose >= 0)  | 
    ||
566  | 
    			warn("%s", out); | 
    ||
567  | 
    error = FAILURE;  | 
    ||
568  | 
    }  | 
    ||
569  | 
    |||
570  | 
    ✗✓ | 64  | 
    	if (close(ifd)) { | 
    
571  | 
    if (!error && verbose >= 0)  | 
    ||
572  | 
    			warn("%s", in); | 
    ||
573  | 
    error = FAILURE;  | 
    ||
574  | 
    }  | 
    ||
575  | 
    |||
576  | 
    ✓✓✗✓ | 
    74  | 
    	if (!force && !cat && info.total_out >= info.total_in) { | 
    
577  | 
    if (verbose > 0)  | 
    ||
578  | 
    fprintf(stderr, "file would grow; left unmodified\n");  | 
    ||
579  | 
    (void) unlink(out);  | 
    ||
580  | 
    error = WARNING;  | 
    ||
581  | 
    }  | 
    ||
582  | 
    |||
583  | 
    ✗✓ | 64  | 
    	if (error) { | 
    
584  | 
    if (oreg)  | 
    ||
585  | 
    (void) unlink(out);  | 
    ||
586  | 
    ✓✓ | 64  | 
    } else if (verbose > 0)  | 
    
587  | 
    10  | 
    verbose_info(out, info.total_out, info.total_in, info.hlen);  | 
    |
588  | 
    |||
589  | 
    64  | 
    return (error);  | 
    |
590  | 
    #else  | 
    ||
591  | 
    	warnx("compression not supported"); | 
    ||
592  | 
    return (FAILURE);  | 
    ||
593  | 
    #endif  | 
    ||
594  | 
    64  | 
    }  | 
    |
595  | 
    |||
596  | 
    const struct compressor *  | 
    ||
597  | 
    check_method(int fd)  | 
    ||
598  | 
    { | 
    ||
599  | 
    const struct compressor *method;  | 
    ||
600  | 
    1142  | 
    u_char magic[2];  | 
    |
601  | 
    |||
602  | 
    ✗✓ | 571  | 
    if (read(fd, magic, sizeof(magic)) != 2)  | 
    
603  | 
    return (NULL);  | 
    ||
604  | 
    ✓✗ | 1142  | 
    	for (method = &c_table[0]; method->name != NULL; method++) { | 
    
605  | 
    ✓✗✓✗ | 
    1142  | 
    if (magic[0] == method->magic[0] &&  | 
    
606  | 
    571  | 
    magic[1] == method->magic[1])  | 
    |
607  | 
    571  | 
    return (method);  | 
    |
608  | 
    }  | 
    ||
609  | 
    #ifndef SMALL  | 
    ||
610  | 
    	if (force && cat) { | 
    ||
611  | 
    null_magic[0] = magic[0];  | 
    ||
612  | 
    null_magic[1] = magic[1];  | 
    ||
613  | 
    return (&null_method);  | 
    ||
614  | 
    }  | 
    ||
615  | 
    #endif /* SMALL */  | 
    ||
616  | 
    return (NULL);  | 
    ||
617  | 
    571  | 
    }  | 
    |
618  | 
    |||
619  | 
    int  | 
    ||
620  | 
    dodecompress(const char *in, char *out, struct stat *sb)  | 
    ||
621  | 
    { | 
    ||
622  | 
    const struct compressor *method;  | 
    ||
623  | 
    1142  | 
    u_char buf[Z_BUFSIZE];  | 
    |
624  | 
    571  | 
    char oldname[PATH_MAX];  | 
    |
625  | 
    int error, oreg, ifd, ofd;  | 
    ||
626  | 
    void *cookie;  | 
    ||
627  | 
    ssize_t nr;  | 
    ||
628  | 
    571  | 
    struct z_info info;  | 
    |
629  | 
    571  | 
    struct stat osb;  | 
    |
630  | 
    |||
631  | 
    oreg = 0;  | 
    ||
632  | 
    error = SUCCESS;  | 
    ||
633  | 
    cookie = NULL;  | 
    ||
634  | 
    |||
635  | 
    ✓✓ | 571  | 
    if (pipin)  | 
    
636  | 
    22  | 
    ifd = dup(STDIN_FILENO);  | 
    |
637  | 
    else  | 
    ||
638  | 
    549  | 
    ifd = open(in, O_RDONLY);  | 
    |
639  | 
    ✗✓ | 571  | 
    	if (ifd < 0) { | 
    
640  | 
    if (verbose >= 0)  | 
    ||
641  | 
    			warn("%s", in); | 
    ||
642  | 
    return -1;  | 
    ||
643  | 
    }  | 
    ||
644  | 
    |||
645  | 
    ✓✓✗✓ | 
    1132  | 
    	if (!force && isatty(ifd)) { | 
    
646  | 
    if (verbose >= 0)  | 
    ||
647  | 
    			warnx("%s: won't read compressed data from terminal", | 
    ||
648  | 
    in);  | 
    ||
649  | 
    close (ifd);  | 
    ||
650  | 
    return -1;  | 
    ||
651  | 
    }  | 
    ||
652  | 
    |||
653  | 
    ✗✓ | 571  | 
    	if ((method = check_method(ifd)) == NULL) { | 
    
654  | 
    if (verbose >= 0)  | 
    ||
655  | 
    			warnx("%s: unrecognized file format", in); | 
    ||
656  | 
    close (ifd);  | 
    ||
657  | 
    return -1;  | 
    ||
658  | 
    }  | 
    ||
659  | 
    |||
660  | 
    /* XXX - open constrains outfile to MAXPATHLEN so this is safe */  | 
    ||
661  | 
    571  | 
    oldname[0] = '\0';  | 
    |
662  | 
    ✗✓ | 571  | 
    	if ((cookie = method->ropen(ifd, oldname, 1)) == NULL) { | 
    
663  | 
    if (verbose >= 0)  | 
    ||
664  | 
    			warn("%s", in); | 
    ||
665  | 
    close (ifd);  | 
    ||
666  | 
    return (FAILURE);  | 
    ||
667  | 
    }  | 
    ||
668  | 
    ✗✓✗✗ | 
    571  | 
    	if (storename && oldname[0] != '\0') { | 
    
669  | 
    char *cp = strrchr(out, '/');  | 
    ||
670  | 
    		if (cp != NULL) { | 
    ||
671  | 
    *(cp + 1) = '\0';  | 
    ||
672  | 
    strlcat(out, oldname, PATH_MAX);  | 
    ||
673  | 
    } else  | 
    ||
674  | 
    strlcpy(out, oldname, PATH_MAX);  | 
    ||
675  | 
    cat = 0; /* XXX should -c override? */  | 
    ||
676  | 
    }  | 
    ||
677  | 
    |||
678  | 
    ✓✓ | 571  | 
    if (testmode)  | 
    
679  | 
    533  | 
    ofd = -1;  | 
    |
680  | 
    	else { | 
    ||
681  | 
    ✓✓ | 38  | 
    if (cat)  | 
    
682  | 
    18  | 
    ofd = dup(STDOUT_FILENO);  | 
    |
683  | 
    		else { | 
    ||
684  | 
    ✓✓ | 20  | 
    			if (stat(out, &osb) == 0) { | 
    
685  | 
    6  | 
    oreg = S_ISREG(osb.st_mode);  | 
    |
686  | 
    ✗✓✗✗ | 
    6  | 
    				if (!force && oreg && !permission(out)) { | 
    
687  | 
    (void) close(ifd);  | 
    ||
688  | 
    return (WARNING);  | 
    ||
689  | 
    }  | 
    ||
690  | 
    }  | 
    ||
691  | 
    20  | 
    ofd = open(out, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR);  | 
    |
692  | 
    }  | 
    ||
693  | 
    ✗✓ | 38  | 
    		if (ofd < 0) { | 
    
694  | 
    if (verbose >= 0)  | 
    ||
695  | 
    				warn("%s", in); | 
    ||
696  | 
    method->close(cookie, NULL, NULL, NULL);  | 
    ||
697  | 
    return (FAILURE);  | 
    ||
698  | 
    }  | 
    ||
699  | 
    }  | 
    ||
700  | 
    |||
701  | 
    ✓✓ | 1282  | 
    	while ((nr = method->read(cookie, buf, sizeof(buf))) > 0) { | 
    
702  | 
    ✓✓✗✓ | 
    114  | 
    		if (ofd != -1 && write(ofd, buf, nr) != nr) { | 
    
703  | 
    if (verbose >= 0)  | 
    ||
704  | 
    				warn("%s", out); | 
    ||
705  | 
    error = FAILURE;  | 
    ||
706  | 
    break;  | 
    ||
707  | 
    }  | 
    ||
708  | 
    }  | 
    ||
709  | 
    |||
710  | 
    ✓✓ | 571  | 
    	if (!error && nr < 0) { | 
    
711  | 
    ✓✗ | 515  | 
    if (verbose >= 0)  | 
    
712  | 
    515  | 
    			warnx("%s: %s", in, | 
    |
713  | 
    ✓✓ | 1040  | 
    errno == EINVAL ? "crc error" : strerror(errno));  | 
    
714  | 
    515  | 
    error = errno == EINVAL ? WARNING : FAILURE;  | 
    |
715  | 
    515  | 
    }  | 
    |
716  | 
    |||
717  | 
    ✗✓ | 571  | 
    	if (method->close(cookie, &info, NULL, NULL)) { | 
    
718  | 
    if (!error && verbose >= 0)  | 
    ||
719  | 
    			warnx("%s", in); | 
    ||
720  | 
    error = FAILURE;  | 
    ||
721  | 
    }  | 
    ||
722  | 
    ✗✓ | 571  | 
    	if (storename && !cat) { | 
    
723  | 
    		if (info.mtime != 0) { | 
    ||
724  | 
    sb->st_mtimespec.tv_sec =  | 
    ||
725  | 
    sb->st_atimespec.tv_sec = info.mtime;  | 
    ||
726  | 
    sb->st_mtimespec.tv_nsec =  | 
    ||
727  | 
    sb->st_atimespec.tv_nsec = 0;  | 
    ||
728  | 
    } else  | 
    ||
729  | 
    storename = 0; /* no timestamp to restore */  | 
    ||
730  | 
    }  | 
    ||
731  | 
    ✓✓ | 571  | 
    if (error == SUCCESS)  | 
    
732  | 
    56  | 
    setfile(out, ofd, sb);  | 
    |
733  | 
    |||
734  | 
    ✓✓✗✓ | 
    609  | 
    	if (ofd != -1 && close(ofd)) { | 
    
735  | 
    if (!error && verbose >= 0)  | 
    ||
736  | 
    			warn("%s", out); | 
    ||
737  | 
    error = FAILURE;  | 
    ||
738  | 
    }  | 
    ||
739  | 
    |||
740  | 
    ✓✓ | 571  | 
    	if (!error) { | 
    
741  | 
    ✗✓ | 56  | 
    		if (list) { | 
    
742  | 
    if (info.mtime == 0)  | 
    ||
743  | 
    info.mtime = (u_int32_t)sb->st_mtime;  | 
    ||
744  | 
    list_stats(out, method, &info);  | 
    ||
745  | 
    ✓✓ | 56  | 
    		} else if (verbose > 0) { | 
    
746  | 
    20  | 
    verbose_info(out, info.total_in, info.total_out,  | 
    |
747  | 
    10  | 
    info.hlen);  | 
    |
748  | 
    10  | 
    }  | 
    |
749  | 
    }  | 
    ||
750  | 
    |||
751  | 
    /* On error, clean up the file we created but preserve errno. */  | 
    ||
752  | 
    ✗✓ | 571  | 
    if (error && oreg)  | 
    
753  | 
    unlink(out);  | 
    ||
754  | 
    |||
755  | 
    571  | 
    return (error);  | 
    |
756  | 
    571  | 
    }  | 
    |
757  | 
    |||
758  | 
    void  | 
    ||
759  | 
    setfile(const char *name, int fd, struct stat *fs)  | 
    ||
760  | 
    { | 
    ||
761  | 
    1382  | 
    struct timespec ts[2];  | 
    |
762  | 
    |||
763  | 
    ✓✓ | 691  | 
    if (name == NULL || cat || testmode)  | 
    
764  | 
    661  | 
    return;  | 
    |
765  | 
    |||
766  | 
    /*  | 
    ||
767  | 
    * If input was a pipe we don't have any info to restore but we  | 
    ||
768  | 
    * must set the mode since the current mode on the file is 0200.  | 
    ||
769  | 
    */  | 
    ||
770  | 
    ✗✓ | 30  | 
    	if (pipin) { | 
    
771  | 
    mode_t mask = umask(022);  | 
    ||
772  | 
    fchmod(fd, DEFFILEMODE & ~mask);  | 
    ||
773  | 
    umask(mask);  | 
    ||
774  | 
    return;  | 
    ||
775  | 
    }  | 
    ||
776  | 
    |||
777  | 
    /*  | 
    ||
778  | 
    * Changing the ownership probably won't succeed, unless we're root  | 
    ||
779  | 
    * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid bits are not  | 
    ||
780  | 
    * allowed.  | 
    ||
781  | 
    */  | 
    ||
782  | 
    30  | 
    fs->st_mode &= ACCESSPERMS;  | 
    |
783  | 
    ✗✓ | 30  | 
    	if (fchown(fd, fs->st_uid, fs->st_gid)) { | 
    
784  | 
    if (errno != EPERM)  | 
    ||
785  | 
    			warn("fchown: %s", name); | 
    ||
786  | 
    fs->st_mode &= ~(S_ISUID|S_ISGID);  | 
    ||
787  | 
    }  | 
    ||
788  | 
    ✗✓ | 30  | 
    if (fchmod(fd, fs->st_mode))  | 
    
789  | 
    		warn("fchmod: %s", name); | 
    ||
790  | 
    |||
791  | 
    ✗✓✗✗ | 
    30  | 
    if (fs->st_flags && fchflags(fd, fs->st_flags))  | 
    
792  | 
    		warn("fchflags: %s", name); | 
    ||
793  | 
    |||
794  | 
    30  | 
    ts[0] = fs->st_atim;  | 
    |
795  | 
    30  | 
    ts[1] = fs->st_mtim;  | 
    |
796  | 
    ✗✓ | 30  | 
    if (futimens(fd, ts))  | 
    
797  | 
    		warn("futimens: %s", name); | 
    ||
798  | 
    721  | 
    }  | 
    |
799  | 
    |||
800  | 
    int  | 
    ||
801  | 
    permission(const char *fname)  | 
    ||
802  | 
    { | 
    ||
803  | 
    int ch, first;  | 
    ||
804  | 
    |||
805  | 
    if (!isatty(fileno(stderr)))  | 
    ||
806  | 
    return (0);  | 
    ||
807  | 
    (void)fprintf(stderr, "overwrite %s? ", fname);  | 
    ||
808  | 
    first = ch = getchar();  | 
    ||
809  | 
    while (ch != '\n' && ch != EOF)  | 
    ||
810  | 
    ch = getchar();  | 
    ||
811  | 
    return (first == 'y');  | 
    ||
812  | 
    }  | 
    ||
813  | 
    |||
814  | 
    /*  | 
    ||
815  | 
    * Check infile for a known suffix and return the suffix portion or NULL.  | 
    ||
816  | 
    */  | 
    ||
817  | 
    const char *  | 
    ||
818  | 
    check_suffix(const char *infile)  | 
    ||
819  | 
    { | 
    ||
820  | 
    int i;  | 
    ||
821  | 
    char *suf, *sep, *separators = ".-_";  | 
    ||
822  | 
    	static char *suffixes[] = { "Z", "gz", "z", "tgz", "taz", NULL }; | 
    ||
823  | 
    |||
824  | 
    ✓✓ | 1827  | 
    	for (sep = separators; *sep != '\0'; sep++) { | 
    
825  | 
    ✓✓ | 609  | 
    if ((suf = strrchr(infile, *sep)) == NULL)  | 
    
826  | 
    continue;  | 
    ||
827  | 
    549  | 
    suf++;  | 
    |
828  | 
    |||
829  | 
    ✓✗ | 2212  | 
    		for (i = 0; suffixes[i] != NULL; i++) { | 
    
830  | 
    ✓✓ | 1106  | 
    if (strcmp(suf, suffixes[i]) == 0)  | 
    
831  | 
    549  | 
    return (suf - 1);  | 
    |
832  | 
    }  | 
    ||
833  | 
    }  | 
    ||
834  | 
    20  | 
    return (NULL);  | 
    |
835  | 
    569  | 
    }  | 
    |
836  | 
    |||
837  | 
    /*  | 
    ||
838  | 
    * Set outfile based on the suffix. In most cases we just strip  | 
    ||
839  | 
    * off the suffix but things like .tgz and .taz are special.  | 
    ||
840  | 
    */  | 
    ||
841  | 
    char *  | 
    ||
842  | 
    set_outfile(const char *infile, char *outfile, size_t osize)  | 
    ||
843  | 
    { | 
    ||
844  | 
    const char *s;  | 
    ||
845  | 
    char *cp;  | 
    ||
846  | 
    |||
847  | 
    ✗✓ | 1098  | 
    if ((s = check_suffix(infile)) == NULL)  | 
    
848  | 
    return (NULL);  | 
    ||
849  | 
    |||
850  | 
    549  | 
    (void)strlcpy(outfile, infile, osize);  | 
    |
851  | 
    549  | 
    cp = outfile + (s - infile) + 1;  | 
    |
852  | 
    /*  | 
    ||
853  | 
    * Convert tgz and taz -> tar, else drop the suffix.  | 
    ||
854  | 
    */  | 
    ||
855  | 
    ✓✓ | 549  | 
    	if (strcmp(cp, "tgz") == 0) { | 
    
856  | 
    4  | 
    cp[1] = 'a';  | 
    |
857  | 
    4  | 
    cp[2] = 'r';  | 
    |
858  | 
    549  | 
    } else if (strcmp(cp, "taz") == 0)  | 
    |
859  | 
    cp[2] = 'r';  | 
    ||
860  | 
    else  | 
    ||
861  | 
    cp[-1] = '\0';  | 
    ||
862  | 
    549  | 
    return (outfile);  | 
    |
863  | 
    549  | 
    }  | 
    |
864  | 
    |||
865  | 
    /*  | 
    ||
866  | 
    * Print output for the -l option.  | 
    ||
867  | 
    */  | 
    ||
868  | 
    void  | 
    ||
869  | 
    list_stats(const char *name, const struct compressor *method,  | 
    ||
870  | 
    struct z_info *info)  | 
    ||
871  | 
    { | 
    ||
872  | 
    static off_t compressed_total, uncompressed_total, header_total;  | 
    ||
873  | 
    static u_int nruns;  | 
    ||
874  | 
    char *timestr;  | 
    ||
875  | 
    |||
876  | 
    	if (nruns == 0) { | 
    ||
877  | 
    		if (verbose >= 0) { | 
    ||
878  | 
    if (verbose > 0)  | 
    ||
879  | 
    				fputs("method  crc      date   time  ", stdout); | 
    ||
880  | 
    			puts("compressed  uncompressed  ratio  uncompressed_name"); | 
    ||
881  | 
    }  | 
    ||
882  | 
    }  | 
    ||
883  | 
    nruns++;  | 
    ||
884  | 
    |||
885  | 
    	if (name != NULL) { | 
    ||
886  | 
    		if (verbose > 0) { | 
    ||
887  | 
    time_t t = info->mtime; /* XXX 32 bit mtime */  | 
    ||
888  | 
    |||
889  | 
    timestr = ctime(&t) + 4;  | 
    ||
890  | 
    timestr[12] = '\0';  | 
    ||
891  | 
    if (timestr[4] == ' ')  | 
    ||
892  | 
    timestr[4] = '0';  | 
    ||
893  | 
    			printf("%-7.7s %08x %s ", method->name, info->crc, | 
    ||
894  | 
    timestr);  | 
    ||
895  | 
    }  | 
    ||
896  | 
    		printf("%10lld    %10lld  %4.1f%%  %s\n", | 
    ||
897  | 
    (long long)(info->total_in + info->hlen),  | 
    ||
898  | 
    (long long)info->total_out,  | 
    ||
899  | 
    ((long long)info->total_out - (long long)info->total_in) *  | 
    ||
900  | 
    100.0 / info->total_out, name);  | 
    ||
901  | 
    compressed_total += info->total_in;  | 
    ||
902  | 
    uncompressed_total += info->total_out;  | 
    ||
903  | 
    header_total += info->hlen;  | 
    ||
904  | 
    	} else if (verbose >= 0) { | 
    ||
905  | 
    if (nruns < 3) /* only do totals for > 1 files */  | 
    ||
906  | 
    return;  | 
    ||
907  | 
    if (verbose > 0)  | 
    ||
908  | 
    			fputs("                              ", stdout); | 
    ||
909  | 
    		printf("%10lld    %10lld  %4.1f%%  (totals)\n", | 
    ||
910  | 
    (long long)(compressed_total + header_total),  | 
    ||
911  | 
    (long long)uncompressed_total,  | 
    ||
912  | 
    (uncompressed_total - compressed_total) *  | 
    ||
913  | 
    100.0 / uncompressed_total);  | 
    ||
914  | 
    }  | 
    ||
915  | 
    }  | 
    ||
916  | 
    |||
917  | 
    void  | 
    ||
918  | 
    verbose_info(const char *file, off_t compressed, off_t uncompressed,  | 
    ||
919  | 
    u_int32_t hlen)  | 
    ||
920  | 
    { | 
    ||
921  | 
    ✓✓ | 40  | 
    	if (testmode) { | 
    
922  | 
    10  | 
    		fputs("OK\n", stderr); | 
    |
923  | 
    10  | 
    return;  | 
    |
924  | 
    }  | 
    ||
925  | 
    ✗✓ | 10  | 
    	if (!pipin) { | 
    
926  | 
    fprintf(stderr, "\t%4.1f%% -- replaced with %s\n",  | 
    ||
927  | 
    (uncompressed - compressed) * 100.0 / uncompressed, file);  | 
    ||
928  | 
    }  | 
    ||
929  | 
    10  | 
    compressed += hlen;  | 
    |
930  | 
    10  | 
    fprintf(stderr, "%lld bytes in, %lld bytes out\n",  | 
    |
931  | 
    10  | 
    (long long)(decomp ? compressed : uncompressed),  | 
    |
932  | 
    10  | 
    (long long)(decomp ? uncompressed : compressed));  | 
    |
933  | 
    30  | 
    }  | 
    |
934  | 
    |||
935  | 
    __dead void  | 
    ||
936  | 
    usage(int status)  | 
    ||
937  | 
    { | 
    ||
938  | 
    const bool gzip = (__progname[0] == 'g');  | 
    ||
939  | 
    |||
940  | 
    	switch (pmode) { | 
    ||
941  | 
    case MODE_COMP:  | 
    ||
942  | 
    fprintf(stderr, "usage: %s [-123456789cdf%sh%slNnOqrt%sv] "  | 
    ||
943  | 
    "[-b bits] [-o filename] [-S suffix]\n"  | 
    ||
944  | 
    " %*s [file ...]\n", __progname,  | 
    ||
945  | 
    !gzip ? "g" : "", gzip ? "L" : "", gzip ? "V" : "",  | 
    ||
946  | 
    (int)strlen(__progname), "");  | 
    ||
947  | 
    break;  | 
    ||
948  | 
    case MODE_DECOMP:  | 
    ||
949  | 
    fprintf(stderr, "usage: %s [-cfh%slNnqrt%sv] [-o filename] "  | 
    ||
950  | 
    "[file ...]\n", __progname,  | 
    ||
951  | 
    gzip ? "L" : "", gzip ? "V" : "");  | 
    ||
952  | 
    break;  | 
    ||
953  | 
    case MODE_CAT:  | 
    ||
954  | 
    fprintf(stderr, "usage: %s [-f%shqr] [file ...]\n",  | 
    ||
955  | 
    __progname, gzip ? "" : "g");  | 
    ||
956  | 
    break;  | 
    ||
957  | 
    }  | 
    ||
958  | 
    exit(status);  | 
    ||
959  | 
    }  | 
    
| Generated by: GCOVR (Version 3.3) |