Sat Jun 10 04:45:25 2023 UTC ()
Pull git commit way-etc-20140221.tar.bz2 by Xin Li from FreeBSD:

    Remove unneeded checks for prelen.

    In order to determine the type of a compressed file, we have to read
    in the first four bytes which may also be important for decompression
    purposes, to do that we would pass the buffer that we have already
    read in, along with the size of it.

    Rename header1 to fourbytes to make that explicit, and remove all
    checks for prelen.


(simonb)
diff -r1.118 -r1.119 src/usr.bin/gzip/gzip.c
diff -r1.7 -r1.8 src/usr.bin/gzip/unlz.c
diff -r1.3 -r1.4 src/usr.bin/gzip/unpack.c

cvs diff -r1.118 -r1.119 src/usr.bin/gzip/gzip.c (switch to unified diff)

--- src/usr.bin/gzip/gzip.c 2022/01/22 14:00:45 1.118
+++ src/usr.bin/gzip/gzip.c 2023/06/10 04:45:25 1.119
@@ -1,2323 +1,2323 @@ @@ -1,2323 +1,2323 @@
1/* $NetBSD: gzip.c,v 1.118 2022/01/22 14:00:45 christos Exp $ */ 1/* $NetBSD: gzip.c,v 1.119 2023/06/10 04:45:25 simonb Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1997, 1998, 2003, 2004, 2006, 2008, 2009, 2010, 2011, 2015, 2017 4 * Copyright (c) 1997, 1998, 2003, 2004, 2006, 2008, 2009, 2010, 2011, 2015, 2017
5 * Matthew R. Green 5 * Matthew R. Green
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution. 15 * documentation and/or other materials provided with the distribution.
16 * 16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE. 27 * SUCH DAMAGE.
28 */ 28 */
29 29
30#include <sys/cdefs.h> 30#include <sys/cdefs.h>
31#ifndef lint 31#ifndef lint
32__COPYRIGHT("@(#) Copyright (c) 1997, 1998, 2003, 2004, 2006, 2008,\ 32__COPYRIGHT("@(#) Copyright (c) 1997, 1998, 2003, 2004, 2006, 2008,\
33 2009, 2010, 2011, 2015, 2017 Matthew R. Green. All rights reserved."); 33 2009, 2010, 2011, 2015, 2017 Matthew R. Green. All rights reserved.");
34__RCSID("$NetBSD: gzip.c,v 1.118 2022/01/22 14:00:45 christos Exp $"); 34__RCSID("$NetBSD: gzip.c,v 1.119 2023/06/10 04:45:25 simonb Exp $");
35#endif /* not lint */ 35#endif /* not lint */
36 36
37/* 37/*
38 * gzip.c -- GPL free gzip using zlib. 38 * gzip.c -- GPL free gzip using zlib.
39 * 39 *
40 * RFC 1950 covers the zlib format 40 * RFC 1950 covers the zlib format
41 * RFC 1951 covers the deflate format 41 * RFC 1951 covers the deflate format
42 * RFC 1952 covers the gzip format 42 * RFC 1952 covers the gzip format
43 * 43 *
44 * TODO: 44 * TODO:
45 * - use mmap where possible 45 * - use mmap where possible
46 * - handle some signals better (remove outfile?) 46 * - handle some signals better (remove outfile?)
47 * - make bzip2/compress -v/-t/-l support work as well as possible 47 * - make bzip2/compress -v/-t/-l support work as well as possible
48 */ 48 */
49 49
50#include <sys/param.h> 50#include <sys/param.h>
51#include <sys/stat.h> 51#include <sys/stat.h>
52#include <sys/time.h> 52#include <sys/time.h>
53 53
54#include <inttypes.h> 54#include <inttypes.h>
55#include <unistd.h> 55#include <unistd.h>
56#include <stdio.h> 56#include <stdio.h>
57#include <string.h> 57#include <string.h>
58#include <stdlib.h> 58#include <stdlib.h>
59#include <err.h> 59#include <err.h>
60#include <errno.h> 60#include <errno.h>
61#include <fcntl.h> 61#include <fcntl.h>
62#include <zlib.h> 62#include <zlib.h>
63#include <fts.h> 63#include <fts.h>
64#include <libgen.h> 64#include <libgen.h>
65#include <stdarg.h> 65#include <stdarg.h>
66#include <getopt.h> 66#include <getopt.h>
67#include <time.h> 67#include <time.h>
68#include <paths.h> 68#include <paths.h>
69 69
70#ifndef PRIdOFF 70#ifndef PRIdOFF
71#define PRIdOFF PRId64 71#define PRIdOFF PRId64
72#endif 72#endif
73 73
74/* what type of file are we dealing with */ 74/* what type of file are we dealing with */
75enum filetype { 75enum filetype {
76 FT_GZIP, 76 FT_GZIP,
77#ifndef NO_BZIP2_SUPPORT 77#ifndef NO_BZIP2_SUPPORT
78 FT_BZIP2, 78 FT_BZIP2,
79#endif 79#endif
80#ifndef NO_COMPRESS_SUPPORT 80#ifndef NO_COMPRESS_SUPPORT
81 FT_Z, 81 FT_Z,
82#endif 82#endif
83#ifndef NO_PACK_SUPPORT 83#ifndef NO_PACK_SUPPORT
84 FT_PACK, 84 FT_PACK,
85#endif 85#endif
86#ifndef NO_XZ_SUPPORT 86#ifndef NO_XZ_SUPPORT
87 FT_XZ, 87 FT_XZ,
88#endif 88#endif
89#ifndef NO_LZ_SUPPORT 89#ifndef NO_LZ_SUPPORT
90 FT_LZ, 90 FT_LZ,
91#endif 91#endif
92 FT_LAST, 92 FT_LAST,
93 FT_UNKNOWN 93 FT_UNKNOWN
94}; 94};
95 95
96#ifndef NO_BZIP2_SUPPORT 96#ifndef NO_BZIP2_SUPPORT
97#include <bzlib.h> 97#include <bzlib.h>
98 98
99#define BZ2_SUFFIX ".bz2" 99#define BZ2_SUFFIX ".bz2"
100#define BZIP2_MAGIC "\102\132\150" 100#define BZIP2_MAGIC "\102\132\150"
101#endif 101#endif
102 102
103#ifndef NO_COMPRESS_SUPPORT 103#ifndef NO_COMPRESS_SUPPORT
104#define Z_SUFFIX ".Z" 104#define Z_SUFFIX ".Z"
105#define Z_MAGIC "\037\235" 105#define Z_MAGIC "\037\235"
106#endif 106#endif
107 107
108#ifndef NO_PACK_SUPPORT 108#ifndef NO_PACK_SUPPORT
109#define PACK_MAGIC "\037\036" 109#define PACK_MAGIC "\037\036"
110#endif 110#endif
111 111
112#ifndef NO_XZ_SUPPORT 112#ifndef NO_XZ_SUPPORT
113#include <lzma.h> 113#include <lzma.h>
114#define XZ_SUFFIX ".xz" 114#define XZ_SUFFIX ".xz"
115#define XZ_MAGIC "\3757zXZ" 115#define XZ_MAGIC "\3757zXZ"
116#endif 116#endif
117 117
118#ifndef NO_LZ_SUPPORT 118#ifndef NO_LZ_SUPPORT
119#define LZ_SUFFIX ".lz" 119#define LZ_SUFFIX ".lz"
120#define LZ_MAGIC "LZIP" 120#define LZ_MAGIC "LZIP"
121#endif 121#endif
122 122
123#define GZ_SUFFIX ".gz" 123#define GZ_SUFFIX ".gz"
124 124
125#define BUFLEN (64 * 1024) 125#define BUFLEN (64 * 1024)
126 126
127#define GZIP_MAGIC0 0x1F 127#define GZIP_MAGIC0 0x1F
128#define GZIP_MAGIC1 0x8B 128#define GZIP_MAGIC1 0x8B
129#define GZIP_OMAGIC1 0x9E 129#define GZIP_OMAGIC1 0x9E
130 130
131#define GZIP_TIMESTAMP (off_t)4 131#define GZIP_TIMESTAMP (off_t)4
132#define GZIP_ORIGNAME (off_t)10 132#define GZIP_ORIGNAME (off_t)10
133 133
134#define HEAD_CRC 0x02 134#define HEAD_CRC 0x02
135#define EXTRA_FIELD 0x04 135#define EXTRA_FIELD 0x04
136#define ORIG_NAME 0x08 136#define ORIG_NAME 0x08
137#define COMMENT 0x10 137#define COMMENT 0x10
138 138
139#define OS_CODE 3 /* Unix */ 139#define OS_CODE 3 /* Unix */
140 140
141typedef struct { 141typedef struct {
142 const char *zipped; 142 const char *zipped;
143 int ziplen; 143 int ziplen;
144 const char *normal; /* for unzip - must not be longer than zipped */ 144 const char *normal; /* for unzip - must not be longer than zipped */
145} suffixes_t; 145} suffixes_t;
146static suffixes_t suffixes[] = { 146static suffixes_t suffixes[] = {
147#define SUFFIX(Z, N) {Z, sizeof Z - 1, N} 147#define SUFFIX(Z, N) {Z, sizeof Z - 1, N}
148 SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S .xxx */ 148 SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S .xxx */
149#ifndef SMALL 149#ifndef SMALL
150 SUFFIX(GZ_SUFFIX, ""), 150 SUFFIX(GZ_SUFFIX, ""),
151 SUFFIX(".z", ""), 151 SUFFIX(".z", ""),
152 SUFFIX("-gz", ""), 152 SUFFIX("-gz", ""),
153 SUFFIX("-z", ""), 153 SUFFIX("-z", ""),
154 SUFFIX("_z", ""), 154 SUFFIX("_z", ""),
155 SUFFIX(".taz", ".tar"), 155 SUFFIX(".taz", ".tar"),
156 SUFFIX(".tgz", ".tar"), 156 SUFFIX(".tgz", ".tar"),
157#ifndef NO_BZIP2_SUPPORT 157#ifndef NO_BZIP2_SUPPORT
158 SUFFIX(BZ2_SUFFIX, ""), 158 SUFFIX(BZ2_SUFFIX, ""),
159#endif 159#endif
160#ifndef NO_COMPRESS_SUPPORT 160#ifndef NO_COMPRESS_SUPPORT
161 SUFFIX(Z_SUFFIX, ""), 161 SUFFIX(Z_SUFFIX, ""),
162#endif 162#endif
163#ifndef NO_XZ_SUPPORT 163#ifndef NO_XZ_SUPPORT
164 SUFFIX(XZ_SUFFIX, ""), 164 SUFFIX(XZ_SUFFIX, ""),
165#endif 165#endif
166#ifndef NO_LZ_SUPPORT 166#ifndef NO_LZ_SUPPORT
167 SUFFIX(LZ_SUFFIX, ""), 167 SUFFIX(LZ_SUFFIX, ""),
168#endif 168#endif
169 SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S "" */ 169 SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S "" */
170#endif /* SMALL */ 170#endif /* SMALL */
171#undef SUFFIX 171#undef SUFFIX
172}; 172};
173#define NUM_SUFFIXES (sizeof suffixes / sizeof suffixes[0]) 173#define NUM_SUFFIXES (sizeof suffixes / sizeof suffixes[0])
174#define SUFFIX_MAXLEN 30 174#define SUFFIX_MAXLEN 30
175 175
176static const char gzip_version[] = "NetBSD gzip 20170803"; 176static const char gzip_version[] = "NetBSD gzip 20170803";
177 177
178static int cflag; /* stdout mode */ 178static int cflag; /* stdout mode */
179static int dflag; /* decompress mode */ 179static int dflag; /* decompress mode */
180static int lflag; /* list mode */ 180static int lflag; /* list mode */
181static int numflag = 6; /* gzip -1..-9 value */ 181static int numflag = 6; /* gzip -1..-9 value */
182 182
183#ifndef SMALL 183#ifndef SMALL
184static int fflag; /* force mode */ 184static int fflag; /* force mode */
185static int kflag; /* don't delete input files */ 185static int kflag; /* don't delete input files */
186static int nflag; /* don't save name/timestamp */ 186static int nflag; /* don't save name/timestamp */
187static int Nflag; /* don't restore name/timestamp */ 187static int Nflag; /* don't restore name/timestamp */
188static int qflag; /* quiet mode */ 188static int qflag; /* quiet mode */
189static int rflag; /* recursive mode */ 189static int rflag; /* recursive mode */
190static int tflag; /* test */ 190static int tflag; /* test */
191static int vflag; /* verbose mode */ 191static int vflag; /* verbose mode */
192static sig_atomic_t print_info = 0; 192static sig_atomic_t print_info = 0;
193#else 193#else
194#define qflag 0 194#define qflag 0
195#define tflag 0 195#define tflag 0
196#endif 196#endif
197 197
198static int exit_value = 0; /* exit value */ 198static int exit_value = 0; /* exit value */
199 199
200static const char *infile; /* name of file coming in */ 200static const char *infile; /* name of file coming in */
201 201
202static void maybe_err(const char *fmt, ...) __printflike(1, 2) __dead; 202static void maybe_err(const char *fmt, ...) __printflike(1, 2) __dead;
203#if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \ 203#if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \
204 !defined(NO_XZ_SUPPORT) 204 !defined(NO_XZ_SUPPORT)
205static void maybe_errx(const char *fmt, ...) __printflike(1, 2) __dead; 205static void maybe_errx(const char *fmt, ...) __printflike(1, 2) __dead;
206#endif 206#endif
207static void maybe_warn(const char *fmt, ...) __printflike(1, 2); 207static void maybe_warn(const char *fmt, ...) __printflike(1, 2);
208static void maybe_warnx(const char *fmt, ...) __printflike(1, 2); 208static void maybe_warnx(const char *fmt, ...) __printflike(1, 2);
209static enum filetype file_gettype(u_char *); 209static enum filetype file_gettype(u_char *);
210#ifdef SMALL 210#ifdef SMALL
211#define gz_compress(if, of, sz, fn, tm) gz_compress(if, of, sz) 211#define gz_compress(if, of, sz, fn, tm) gz_compress(if, of, sz)
212#endif 212#endif
213static off_t gz_compress(int, int, off_t *, const char *, uint32_t); 213static off_t gz_compress(int, int, off_t *, const char *, uint32_t);
214static off_t gz_uncompress(int, int, char *, size_t, off_t *, const char *); 214static off_t gz_uncompress(int, int, char *, size_t, off_t *, const char *);
215static off_t file_compress(char *, char *, size_t); 215static off_t file_compress(char *, char *, size_t);
216static off_t file_uncompress(char *, char *, size_t); 216static off_t file_uncompress(char *, char *, size_t);
217static void handle_pathname(char *); 217static void handle_pathname(char *);
218static void handle_file(char *, struct stat *); 218static void handle_file(char *, struct stat *);
219static void handle_stdin(void); 219static void handle_stdin(void);
220static void handle_stdout(void); 220static void handle_stdout(void);
221static void print_ratio(off_t, off_t, FILE *); 221static void print_ratio(off_t, off_t, FILE *);
222static void print_list(int fd, off_t, const char *, time_t); 222static void print_list(int fd, off_t, const char *, time_t);
223__dead static void usage(void); 223__dead static void usage(void);
224__dead static void display_version(void); 224__dead static void display_version(void);
225static const suffixes_t *check_suffix(char *, int); 225static const suffixes_t *check_suffix(char *, int);
226static ssize_t read_retry(int, void *, size_t); 226static ssize_t read_retry(int, void *, size_t);
227static ssize_t write_retry(int, const void *, size_t); 227static ssize_t write_retry(int, const void *, size_t);
228static void print_list_out(off_t, off_t, const char*); 228static void print_list_out(off_t, off_t, const char*);
229 229
230#ifdef SMALL 230#ifdef SMALL
231#define infile_set(f,t) infile_set(f) 231#define infile_set(f,t) infile_set(f)
232#endif 232#endif
233static void infile_set(const char *newinfile, off_t total); 233static void infile_set(const char *newinfile, off_t total);
234 234
235#ifdef SMALL 235#ifdef SMALL
236#define unlink_input(f, sb) unlink(f) 236#define unlink_input(f, sb) unlink(f)
237#define check_siginfo() /* nothing */ 237#define check_siginfo() /* nothing */
238#define setup_signals() /* nothing */ 238#define setup_signals() /* nothing */
239#define infile_newdata(t) /* nothing */ 239#define infile_newdata(t) /* nothing */
240#else 240#else
241static off_t infile_total; /* total expected to read/write */ 241static off_t infile_total; /* total expected to read/write */
242static off_t infile_current; /* current read/write */ 242static off_t infile_current; /* current read/write */
243 243
244static void check_siginfo(void); 244static void check_siginfo(void);
245static off_t cat_fd(unsigned char *, size_t, off_t *, int fd); 245static off_t cat_fd(unsigned char *, size_t, off_t *, int fd);
246static void prepend_gzip(char *, int *, char ***); 246static void prepend_gzip(char *, int *, char ***);
247static void handle_dir(char *); 247static void handle_dir(char *);
248static void print_verbage(const char *, const char *, off_t, off_t); 248static void print_verbage(const char *, const char *, off_t, off_t);
249static void print_test(const char *, int); 249static void print_test(const char *, int);
250static void copymodes(int fd, const struct stat *, const char *file); 250static void copymodes(int fd, const struct stat *, const char *file);
251static int check_outfile(const char *outfile); 251static int check_outfile(const char *outfile);
252static void setup_signals(void); 252static void setup_signals(void);
253static void infile_newdata(size_t newdata); 253static void infile_newdata(size_t newdata);
254static void infile_clear(void); 254static void infile_clear(void);
255#endif 255#endif
256 256
257#ifndef NO_BZIP2_SUPPORT 257#ifndef NO_BZIP2_SUPPORT
258static off_t unbzip2(int, int, char *, size_t, off_t *); 258static off_t unbzip2(int, int, char *, size_t, off_t *);
259#endif 259#endif
260 260
261#ifndef NO_COMPRESS_SUPPORT 261#ifndef NO_COMPRESS_SUPPORT
262static FILE *zdopen(int); 262static FILE *zdopen(int);
263static off_t zuncompress(FILE *, FILE *, char *, size_t, off_t *); 263static off_t zuncompress(FILE *, FILE *, char *, size_t, off_t *);
264#endif 264#endif
265 265
266#ifndef NO_PACK_SUPPORT 266#ifndef NO_PACK_SUPPORT
267static off_t unpack(int, int, char *, size_t, off_t *); 267static off_t unpack(int, int, char *, size_t, off_t *);
268#endif 268#endif
269 269
270#ifndef NO_XZ_SUPPORT 270#ifndef NO_XZ_SUPPORT
271static off_t unxz(int, int, char *, size_t, off_t *); 271static off_t unxz(int, int, char *, size_t, off_t *);
272static off_t unxz_len(int); 272static off_t unxz_len(int);
273#endif 273#endif
274 274
275#ifndef NO_LZ_SUPPORT 275#ifndef NO_LZ_SUPPORT
276static off_t unlz(int, int, char *, size_t, off_t *); 276static off_t unlz(int, int, char *, size_t, off_t *);
277#endif 277#endif
278 278
279#ifdef SMALL 279#ifdef SMALL
280#define getopt_long(a,b,c,d,e) getopt(a,b,c) 280#define getopt_long(a,b,c,d,e) getopt(a,b,c)
281#else 281#else
282static const struct option longopts[] = { 282static const struct option longopts[] = {
283 { "stdout", no_argument, 0, 'c' }, 283 { "stdout", no_argument, 0, 'c' },
284 { "to-stdout", no_argument, 0, 'c' }, 284 { "to-stdout", no_argument, 0, 'c' },
285 { "decompress", no_argument, 0, 'd' }, 285 { "decompress", no_argument, 0, 'd' },
286 { "uncompress", no_argument, 0, 'd' }, 286 { "uncompress", no_argument, 0, 'd' },
287 { "force", no_argument, 0, 'f' }, 287 { "force", no_argument, 0, 'f' },
288 { "help", no_argument, 0, 'h' }, 288 { "help", no_argument, 0, 'h' },
289 { "keep", no_argument, 0, 'k' }, 289 { "keep", no_argument, 0, 'k' },
290 { "list", no_argument, 0, 'l' }, 290 { "list", no_argument, 0, 'l' },
291 { "no-name", no_argument, 0, 'n' }, 291 { "no-name", no_argument, 0, 'n' },
292 { "name", no_argument, 0, 'N' }, 292 { "name", no_argument, 0, 'N' },
293 { "quiet", no_argument, 0, 'q' }, 293 { "quiet", no_argument, 0, 'q' },
294 { "recursive", no_argument, 0, 'r' }, 294 { "recursive", no_argument, 0, 'r' },
295 { "suffix", required_argument, 0, 'S' }, 295 { "suffix", required_argument, 0, 'S' },
296 { "test", no_argument, 0, 't' }, 296 { "test", no_argument, 0, 't' },
297 { "verbose", no_argument, 0, 'v' }, 297 { "verbose", no_argument, 0, 'v' },
298 { "version", no_argument, 0, 'V' }, 298 { "version", no_argument, 0, 'V' },
299 { "fast", no_argument, 0, '1' }, 299 { "fast", no_argument, 0, '1' },
300 { "best", no_argument, 0, '9' }, 300 { "best", no_argument, 0, '9' },
301#if 0 301#if 0
302 /* 302 /*
303 * This is what else GNU gzip implements. --ascii isn't useful 303 * This is what else GNU gzip implements. --ascii isn't useful
304 * on NetBSD, and I don't care to have a --license. 304 * on NetBSD, and I don't care to have a --license.
305 */ 305 */
306 { "ascii", no_argument, 0, 'a' }, 306 { "ascii", no_argument, 0, 'a' },
307 { "license", no_argument, 0, 'L' }, 307 { "license", no_argument, 0, 'L' },
308#endif 308#endif
309 { NULL, no_argument, 0, 0 }, 309 { NULL, no_argument, 0, 0 },
310}; 310};
311#endif 311#endif
312 312
313int 313int
314main(int argc, char **argv) 314main(int argc, char **argv)
315{ 315{
316 const char *progname = getprogname(); 316 const char *progname = getprogname();
317#ifndef SMALL 317#ifndef SMALL
318 char *gzip; 318 char *gzip;
319 int len; 319 int len;
320#endif 320#endif
321 int ch; 321 int ch;
322 322
323 setup_signals(); 323 setup_signals();
324 324
325#ifndef SMALL 325#ifndef SMALL
326 if ((gzip = getenv("GZIP")) != NULL) 326 if ((gzip = getenv("GZIP")) != NULL)
327 prepend_gzip(gzip, &argc, &argv); 327 prepend_gzip(gzip, &argc, &argv);
328#endif 328#endif
329 329
330 /* 330 /*
331 * XXX 331 * XXX
332 * handle being called `gunzip', `zcat' and `gzcat' 332 * handle being called `gunzip', `zcat' and `gzcat'
333 */ 333 */
334 if (strcmp(progname, "gunzip") == 0) 334 if (strcmp(progname, "gunzip") == 0)
335 dflag = 1; 335 dflag = 1;
336 else if (strcmp(progname, "zcat") == 0 || 336 else if (strcmp(progname, "zcat") == 0 ||
337 strcmp(progname, "gzcat") == 0) 337 strcmp(progname, "gzcat") == 0)
338 dflag = cflag = 1; 338 dflag = cflag = 1;
339 339
340#ifdef SMALL 340#ifdef SMALL
341#define OPT_LIST "123456789cdhlV" 341#define OPT_LIST "123456789cdhlV"
342#else 342#else
343#define OPT_LIST "123456789cdfhklNnqrS:tVv" 343#define OPT_LIST "123456789cdfhklNnqrS:tVv"
344#endif 344#endif
345 345
346 while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1) { 346 while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1) {
347 switch (ch) { 347 switch (ch) {
348 case '1': case '2': case '3': 348 case '1': case '2': case '3':
349 case '4': case '5': case '6': 349 case '4': case '5': case '6':
350 case '7': case '8': case '9': 350 case '7': case '8': case '9':
351 numflag = ch - '0'; 351 numflag = ch - '0';
352 break; 352 break;
353 case 'c': 353 case 'c':
354 cflag = 1; 354 cflag = 1;
355 break; 355 break;
356 case 'd': 356 case 'd':
357 dflag = 1; 357 dflag = 1;
358 break; 358 break;
359 case 'l': 359 case 'l':
360 lflag = 1; 360 lflag = 1;
361 dflag = 1; 361 dflag = 1;
362 break; 362 break;
363 case 'V': 363 case 'V':
364 display_version(); 364 display_version();
365 /* NOTREACHED */ 365 /* NOTREACHED */
366#ifndef SMALL 366#ifndef SMALL
367 case 'f': 367 case 'f':
368 fflag = 1; 368 fflag = 1;
369 break; 369 break;
370 case 'k': 370 case 'k':
371 kflag = 1; 371 kflag = 1;
372 break; 372 break;
373 case 'N': 373 case 'N':
374 nflag = 0; 374 nflag = 0;
375 Nflag = 1; 375 Nflag = 1;
376 break; 376 break;
377 case 'n': 377 case 'n':
378 nflag = 1; 378 nflag = 1;
379 Nflag = 0; 379 Nflag = 0;
380 break; 380 break;
381 case 'q': 381 case 'q':
382 qflag = 1; 382 qflag = 1;
383 break; 383 break;
384 case 'r': 384 case 'r':
385 rflag = 1; 385 rflag = 1;
386 break; 386 break;
387 case 'S': 387 case 'S':
388 len = strlen(optarg); 388 len = strlen(optarg);
389 if (len != 0) { 389 if (len != 0) {
390 if (len > SUFFIX_MAXLEN) 390 if (len > SUFFIX_MAXLEN)
391 errx(1, "incorrect suffix: '%s'", optarg); 391 errx(1, "incorrect suffix: '%s'", optarg);
392 suffixes[0].zipped = optarg; 392 suffixes[0].zipped = optarg;
393 suffixes[0].ziplen = len; 393 suffixes[0].ziplen = len;
394 } else { 394 } else {
395 suffixes[NUM_SUFFIXES - 1].zipped = ""; 395 suffixes[NUM_SUFFIXES - 1].zipped = "";
396 suffixes[NUM_SUFFIXES - 1].ziplen = 0; 396 suffixes[NUM_SUFFIXES - 1].ziplen = 0;
397 } 397 }
398 break; 398 break;
399 case 't': 399 case 't':
400 cflag = 1; 400 cflag = 1;
401 tflag = 1; 401 tflag = 1;
402 dflag = 1; 402 dflag = 1;
403 break; 403 break;
404 case 'v': 404 case 'v':
405 vflag = 1; 405 vflag = 1;
406 break; 406 break;
407#endif 407#endif
408 default: 408 default:
409 usage(); 409 usage();
410 /* NOTREACHED */ 410 /* NOTREACHED */
411 } 411 }
412 } 412 }
413 argv += optind; 413 argv += optind;
414 argc -= optind; 414 argc -= optind;
415 415
416 if (argc == 0) { 416 if (argc == 0) {
417 if (dflag) /* stdin mode */ 417 if (dflag) /* stdin mode */
418 handle_stdin(); 418 handle_stdin();
419 else /* stdout mode */ 419 else /* stdout mode */
420 handle_stdout(); 420 handle_stdout();
421 } else { 421 } else {
422 do { 422 do {
423 handle_pathname(argv[0]); 423 handle_pathname(argv[0]);
424 } while (*++argv); 424 } while (*++argv);
425 } 425 }
426#ifndef SMALL 426#ifndef SMALL
427 if (qflag == 0 && lflag && argc > 1) 427 if (qflag == 0 && lflag && argc > 1)
428 print_list(-1, 0, "(totals)", 0); 428 print_list(-1, 0, "(totals)", 0);
429#endif 429#endif
430 exit(exit_value); 430 exit(exit_value);
431} 431}
432 432
433/* maybe print a warning */ 433/* maybe print a warning */
434void 434void
435maybe_warn(const char *fmt, ...) 435maybe_warn(const char *fmt, ...)
436{ 436{
437 va_list ap; 437 va_list ap;
438 438
439 if (qflag == 0) { 439 if (qflag == 0) {
440 va_start(ap, fmt); 440 va_start(ap, fmt);
441 vwarn(fmt, ap); 441 vwarn(fmt, ap);
442 va_end(ap); 442 va_end(ap);
443 } 443 }
444 if (exit_value == 0) 444 if (exit_value == 0)
445 exit_value = 1; 445 exit_value = 1;
446} 446}
447 447
448/* ... without an errno. */ 448/* ... without an errno. */
449void 449void
450maybe_warnx(const char *fmt, ...) 450maybe_warnx(const char *fmt, ...)
451{ 451{
452 va_list ap; 452 va_list ap;
453 453
454 if (qflag == 0) { 454 if (qflag == 0) {
455 va_start(ap, fmt); 455 va_start(ap, fmt);
456 vwarnx(fmt, ap); 456 vwarnx(fmt, ap);
457 va_end(ap); 457 va_end(ap);
458 } 458 }
459 if (exit_value == 0) 459 if (exit_value == 0)
460 exit_value = 1; 460 exit_value = 1;
461} 461}
462 462
463/* maybe print an error */ 463/* maybe print an error */
464void 464void
465maybe_err(const char *fmt, ...) 465maybe_err(const char *fmt, ...)
466{ 466{
467 va_list ap; 467 va_list ap;
468 468
469 if (qflag == 0) { 469 if (qflag == 0) {
470 va_start(ap, fmt); 470 va_start(ap, fmt);
471 vwarn(fmt, ap); 471 vwarn(fmt, ap);
472 va_end(ap); 472 va_end(ap);
473 } 473 }
474 exit(2); 474 exit(2);
475} 475}
476 476
477#if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \ 477#if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \
478 !defined(NO_XZ_SUPPORT) 478 !defined(NO_XZ_SUPPORT)
479/* ... without an errno. */ 479/* ... without an errno. */
480void 480void
481maybe_errx(const char *fmt, ...) 481maybe_errx(const char *fmt, ...)
482{ 482{
483 va_list ap; 483 va_list ap;
484 484
485 if (qflag == 0) { 485 if (qflag == 0) {
486 va_start(ap, fmt); 486 va_start(ap, fmt);
487 vwarnx(fmt, ap); 487 vwarnx(fmt, ap);
488 va_end(ap); 488 va_end(ap);
489 } 489 }
490 exit(2); 490 exit(2);
491} 491}
492#endif 492#endif
493 493
494#ifndef SMALL 494#ifndef SMALL
495/* split up $GZIP and prepend it to the argument list */ 495/* split up $GZIP and prepend it to the argument list */
496static void 496static void
497prepend_gzip(char *gzip, int *argc, char ***argv) 497prepend_gzip(char *gzip, int *argc, char ***argv)
498{ 498{
499 char *s, **nargv, **ac; 499 char *s, **nargv, **ac;
500 int nenvarg = 0, i; 500 int nenvarg = 0, i;
501 501
502 /* scan how many arguments there are */ 502 /* scan how many arguments there are */
503 for (s = gzip;;) { 503 for (s = gzip;;) {
504 while (*s == ' ' || *s == '\t') 504 while (*s == ' ' || *s == '\t')
505 s++; 505 s++;
506 if (*s == 0) 506 if (*s == 0)
507 goto count_done; 507 goto count_done;
508 nenvarg++; 508 nenvarg++;
509 while (*s != ' ' && *s != '\t') 509 while (*s != ' ' && *s != '\t')
510 if (*s++ == 0) 510 if (*s++ == 0)
511 goto count_done; 511 goto count_done;
512 } 512 }
513count_done: 513count_done:
514 /* punt early */ 514 /* punt early */
515 if (nenvarg == 0) 515 if (nenvarg == 0)
516 return; 516 return;
517 517
518 *argc += nenvarg; 518 *argc += nenvarg;
519 ac = *argv; 519 ac = *argv;
520 520
521 nargv = (char **)malloc((*argc + 1) * sizeof(char *)); 521 nargv = (char **)malloc((*argc + 1) * sizeof(char *));
522 if (nargv == NULL) 522 if (nargv == NULL)
523 maybe_err("malloc"); 523 maybe_err("malloc");
524 524
525 /* stash this away */ 525 /* stash this away */
526 *argv = nargv; 526 *argv = nargv;
527 527
528 /* copy the program name first */ 528 /* copy the program name first */
529 i = 0; 529 i = 0;
530 nargv[i++] = *(ac++); 530 nargv[i++] = *(ac++);
531 531
532 /* take a copy of $GZIP and add it to the array */ 532 /* take a copy of $GZIP and add it to the array */
533 s = strdup(gzip); 533 s = strdup(gzip);
534 if (s == NULL) 534 if (s == NULL)
535 maybe_err("strdup"); 535 maybe_err("strdup");
536 for (;;) { 536 for (;;) {
537 /* Skip whitespaces. */ 537 /* Skip whitespaces. */
538 while (*s == ' ' || *s == '\t') 538 while (*s == ' ' || *s == '\t')
539 s++; 539 s++;
540 if (*s == 0) 540 if (*s == 0)
541 goto copy_done; 541 goto copy_done;
542 nargv[i++] = s; 542 nargv[i++] = s;
543 /* Find the end of this argument. */ 543 /* Find the end of this argument. */
544 while (*s != ' ' && *s != '\t') 544 while (*s != ' ' && *s != '\t')
545 if (*s++ == 0) 545 if (*s++ == 0)
546 /* Argument followed by NUL. */ 546 /* Argument followed by NUL. */
547 goto copy_done; 547 goto copy_done;
548 /* Terminate by overwriting ' ' or '\t' with NUL. */ 548 /* Terminate by overwriting ' ' or '\t' with NUL. */
549 *s++ = 0; 549 *s++ = 0;
550 } 550 }
551copy_done: 551copy_done:
552 552
553 /* copy the original arguments and a NULL */ 553 /* copy the original arguments and a NULL */
554 while (*ac) 554 while (*ac)
555 nargv[i++] = *(ac++); 555 nargv[i++] = *(ac++);
556 nargv[i] = NULL; 556 nargv[i] = NULL;
557} 557}
558#endif 558#endif
559 559
560/* compress input to output. Return bytes read, -1 on error */ 560/* compress input to output. Return bytes read, -1 on error */
561static off_t 561static off_t
562gz_compress(int in, int out, off_t *gsizep, const char *origname, uint32_t mtime) 562gz_compress(int in, int out, off_t *gsizep, const char *origname, uint32_t mtime)
563{ 563{
564 z_stream z; 564 z_stream z;
565 char *outbufp, *inbufp; 565 char *outbufp, *inbufp;
566 off_t in_tot = 0, out_tot = 0; 566 off_t in_tot = 0, out_tot = 0;
567 ssize_t in_size; 567 ssize_t in_size;
568 int i, error; 568 int i, error;
569 uLong crc; 569 uLong crc;
570#ifdef SMALL 570#ifdef SMALL
571 static char header[] = { GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 0, 571 static char header[] = { GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 0,
572 0, 0, 0, 0, 572 0, 0, 0, 0,
573 0, OS_CODE }; 573 0, OS_CODE };
574#endif 574#endif
575 575
576 outbufp = malloc(BUFLEN); 576 outbufp = malloc(BUFLEN);
577 inbufp = malloc(BUFLEN); 577 inbufp = malloc(BUFLEN);
578 if (outbufp == NULL || inbufp == NULL) { 578 if (outbufp == NULL || inbufp == NULL) {
579 maybe_err("malloc failed"); 579 maybe_err("malloc failed");
580 goto out; 580 goto out;
581 } 581 }
582 582
583 memset(&z, 0, sizeof z); 583 memset(&z, 0, sizeof z);
584 z.zalloc = Z_NULL; 584 z.zalloc = Z_NULL;
585 z.zfree = Z_NULL; 585 z.zfree = Z_NULL;
586 z.opaque = 0; 586 z.opaque = 0;
587 587
588#ifdef SMALL 588#ifdef SMALL
589 memcpy(outbufp, header, sizeof header); 589 memcpy(outbufp, header, sizeof header);
590 i = sizeof header; 590 i = sizeof header;
591#else 591#else
592 if (nflag != 0) { 592 if (nflag != 0) {
593 mtime = 0; 593 mtime = 0;
594 origname = ""; 594 origname = "";
595 } 595 }
596 596
597 i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c%c%c%s", 597 i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c%c%c%s",
598 GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 598 GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED,
599 *origname ? ORIG_NAME : 0, 599 *origname ? ORIG_NAME : 0,
600 mtime & 0xff, 600 mtime & 0xff,
601 (mtime >> 8) & 0xff, 601 (mtime >> 8) & 0xff,
602 (mtime >> 16) & 0xff, 602 (mtime >> 16) & 0xff,
603 (mtime >> 24) & 0xff, 603 (mtime >> 24) & 0xff,
604 numflag == 1 ? 4 : numflag == 9 ? 2 : 0, 604 numflag == 1 ? 4 : numflag == 9 ? 2 : 0,
605 OS_CODE, origname); 605 OS_CODE, origname);
606 if (i >= BUFLEN) 606 if (i >= BUFLEN)
607 /* this need PATH_MAX > BUFLEN ... */ 607 /* this need PATH_MAX > BUFLEN ... */
608 maybe_err("snprintf"); 608 maybe_err("snprintf");
609 if (*origname) 609 if (*origname)
610 i++; 610 i++;
611#endif 611#endif
612 612
613 z.next_out = (unsigned char *)outbufp + i; 613 z.next_out = (unsigned char *)outbufp + i;
614 z.avail_out = BUFLEN - i; 614 z.avail_out = BUFLEN - i;
615 615
616 error = deflateInit2(&z, numflag, Z_DEFLATED, 616 error = deflateInit2(&z, numflag, Z_DEFLATED,
617 (-MAX_WBITS), 8, Z_DEFAULT_STRATEGY); 617 (-MAX_WBITS), 8, Z_DEFAULT_STRATEGY);
618 if (error != Z_OK) { 618 if (error != Z_OK) {
619 maybe_warnx("deflateInit2 failed"); 619 maybe_warnx("deflateInit2 failed");
620 in_tot = -1; 620 in_tot = -1;
621 goto out; 621 goto out;
622 } 622 }
623 623
624 crc = crc32(0L, Z_NULL, 0); 624 crc = crc32(0L, Z_NULL, 0);
625 for (;;) { 625 for (;;) {
626 check_siginfo(); 626 check_siginfo();
627 if (z.avail_out == 0) { 627 if (z.avail_out == 0) {
628 if (write_retry(out, outbufp, BUFLEN) != BUFLEN) { 628 if (write_retry(out, outbufp, BUFLEN) != BUFLEN) {
629 maybe_warn("write"); 629 maybe_warn("write");
630 out_tot = -1; 630 out_tot = -1;
631 goto out; 631 goto out;
632 } 632 }
633 633
634 out_tot += BUFLEN; 634 out_tot += BUFLEN;
635 z.next_out = (unsigned char *)outbufp; 635 z.next_out = (unsigned char *)outbufp;
636 z.avail_out = BUFLEN; 636 z.avail_out = BUFLEN;
637 } 637 }
638 638
639 if (z.avail_in == 0) { 639 if (z.avail_in == 0) {
640 in_size = read(in, inbufp, BUFLEN); 640 in_size = read(in, inbufp, BUFLEN);
641 if (in_size < 0) { 641 if (in_size < 0) {
642 maybe_warn("read"); 642 maybe_warn("read");
643 in_tot = -1; 643 in_tot = -1;
644 goto out; 644 goto out;
645 } 645 }
646 if (in_size == 0) 646 if (in_size == 0)
647 break; 647 break;
648 infile_newdata(in_size); 648 infile_newdata(in_size);
649 649
650 crc = crc32(crc, (const Bytef *)inbufp, (unsigned)in_size); 650 crc = crc32(crc, (const Bytef *)inbufp, (unsigned)in_size);
651 in_tot += in_size; 651 in_tot += in_size;
652 z.next_in = (unsigned char *)inbufp; 652 z.next_in = (unsigned char *)inbufp;
653 z.avail_in = in_size; 653 z.avail_in = in_size;
654 } 654 }
655 655
656 error = deflate(&z, Z_NO_FLUSH); 656 error = deflate(&z, Z_NO_FLUSH);
657 if (error != Z_OK && error != Z_STREAM_END) { 657 if (error != Z_OK && error != Z_STREAM_END) {
658 maybe_warnx("deflate failed"); 658 maybe_warnx("deflate failed");
659 in_tot = -1; 659 in_tot = -1;
660 goto out; 660 goto out;
661 } 661 }
662 } 662 }
663 663
664 /* clean up */ 664 /* clean up */
665 for (;;) { 665 for (;;) {
666 size_t len; 666 size_t len;
667 ssize_t w; 667 ssize_t w;
668 668
669 error = deflate(&z, Z_FINISH); 669 error = deflate(&z, Z_FINISH);
670 if (error != Z_OK && error != Z_STREAM_END) { 670 if (error != Z_OK && error != Z_STREAM_END) {
671 maybe_warnx("deflate failed"); 671 maybe_warnx("deflate failed");
672 in_tot = -1; 672 in_tot = -1;
673 goto out; 673 goto out;
674 } 674 }
675 675
676 len = (char *)z.next_out - outbufp; 676 len = (char *)z.next_out - outbufp;
677 677
678 w = write_retry(out, outbufp, len); 678 w = write_retry(out, outbufp, len);
679 if (w == -1 || (size_t)w != len) { 679 if (w == -1 || (size_t)w != len) {
680 maybe_warn("write"); 680 maybe_warn("write");
681 out_tot = -1; 681 out_tot = -1;
682 goto out; 682 goto out;
683 } 683 }
684 out_tot += len; 684 out_tot += len;
685 z.next_out = (unsigned char *)outbufp; 685 z.next_out = (unsigned char *)outbufp;
686 z.avail_out = BUFLEN; 686 z.avail_out = BUFLEN;
687 687
688 if (error == Z_STREAM_END) 688 if (error == Z_STREAM_END)
689 break; 689 break;
690 } 690 }
691 691
692 if (deflateEnd(&z) != Z_OK) { 692 if (deflateEnd(&z) != Z_OK) {
693 maybe_warnx("deflateEnd failed"); 693 maybe_warnx("deflateEnd failed");
694 in_tot = -1; 694 in_tot = -1;
695 goto out; 695 goto out;
696 } 696 }
697 697
698 i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c", 698 i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c",
699 (int)crc & 0xff, 699 (int)crc & 0xff,
700 (int)(crc >> 8) & 0xff, 700 (int)(crc >> 8) & 0xff,
701 (int)(crc >> 16) & 0xff, 701 (int)(crc >> 16) & 0xff,
702 (int)(crc >> 24) & 0xff, 702 (int)(crc >> 24) & 0xff,
703 (int)in_tot & 0xff, 703 (int)in_tot & 0xff,
704 (int)(in_tot >> 8) & 0xff, 704 (int)(in_tot >> 8) & 0xff,
705 (int)(in_tot >> 16) & 0xff, 705 (int)(in_tot >> 16) & 0xff,
706 (int)(in_tot >> 24) & 0xff); 706 (int)(in_tot >> 24) & 0xff);
707 if (i != 8) 707 if (i != 8)
708 maybe_err("snprintf"); 708 maybe_err("snprintf");
709#if 0 709#if 0
710 if (in_tot > 0xffffffff) 710 if (in_tot > 0xffffffff)
711 maybe_warn("input file size >= 4GB cannot be saved"); 711 maybe_warn("input file size >= 4GB cannot be saved");
712#endif 712#endif
713 if (write_retry(out, outbufp, i) != i) { 713 if (write_retry(out, outbufp, i) != i) {
714 maybe_warn("write"); 714 maybe_warn("write");
715 in_tot = -1; 715 in_tot = -1;
716 } else 716 } else
717 out_tot += i; 717 out_tot += i;
718 718
719out: 719out:
720 if (inbufp != NULL) 720 if (inbufp != NULL)
721 free(inbufp); 721 free(inbufp);
722 if (outbufp != NULL) 722 if (outbufp != NULL)
723 free(outbufp); 723 free(outbufp);
724 if (gsizep) 724 if (gsizep)
725 *gsizep = out_tot; 725 *gsizep = out_tot;
726 return in_tot; 726 return in_tot;
727} 727}
728 728
729/* 729/*
730 * uncompress input to output then close the input. return the 730 * uncompress input to output then close the input. return the
731 * uncompressed size written, and put the compressed sized read 731 * uncompressed size written, and put the compressed sized read
732 * into `*gsizep'. 732 * into `*gsizep'.
733 */ 733 */
734static off_t 734static off_t
735gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep, 735gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
736 const char *filename) 736 const char *filename)
737{ 737{
738 z_stream z; 738 z_stream z;
739 char *outbufp, *inbufp; 739 char *outbufp, *inbufp;
740 off_t out_tot = -1, in_tot = 0; 740 off_t out_tot = -1, in_tot = 0;
741 uint32_t out_sub_tot = 0; 741 uint32_t out_sub_tot = 0;
742 enum { 742 enum {
743 GZSTATE_MAGIC0, 743 GZSTATE_MAGIC0,
744 GZSTATE_MAGIC1, 744 GZSTATE_MAGIC1,
745 GZSTATE_METHOD, 745 GZSTATE_METHOD,
746 GZSTATE_FLAGS, 746 GZSTATE_FLAGS,
747 GZSTATE_SKIPPING, 747 GZSTATE_SKIPPING,
748 GZSTATE_EXTRA, 748 GZSTATE_EXTRA,
749 GZSTATE_EXTRA2, 749 GZSTATE_EXTRA2,
750 GZSTATE_EXTRA3, 750 GZSTATE_EXTRA3,
751 GZSTATE_ORIGNAME, 751 GZSTATE_ORIGNAME,
752 GZSTATE_COMMENT, 752 GZSTATE_COMMENT,
753 GZSTATE_HEAD_CRC1, 753 GZSTATE_HEAD_CRC1,
754 GZSTATE_HEAD_CRC2, 754 GZSTATE_HEAD_CRC2,
755 GZSTATE_INIT, 755 GZSTATE_INIT,
756 GZSTATE_READ, 756 GZSTATE_READ,
757 GZSTATE_CRC, 757 GZSTATE_CRC,
758 GZSTATE_LEN, 758 GZSTATE_LEN,
759 } state = GZSTATE_MAGIC0; 759 } state = GZSTATE_MAGIC0;
760 int flags = 0, skip_count = 0; 760 int flags = 0, skip_count = 0;
761 int error = Z_STREAM_ERROR, done_reading = 0; 761 int error = Z_STREAM_ERROR, done_reading = 0;
762 uLong crc = 0; 762 uLong crc = 0;
763 ssize_t wr; 763 ssize_t wr;
764 int needmore = 0; 764 int needmore = 0;
765 765
766#define ADVANCE() { z.next_in++; z.avail_in--; } 766#define ADVANCE() { z.next_in++; z.avail_in--; }
767 767
768 if ((outbufp = malloc(BUFLEN)) == NULL) { 768 if ((outbufp = malloc(BUFLEN)) == NULL) {
769 maybe_err("malloc failed"); 769 maybe_err("malloc failed");
770 goto out2; 770 goto out2;
771 } 771 }
772 if ((inbufp = malloc(BUFLEN)) == NULL) { 772 if ((inbufp = malloc(BUFLEN)) == NULL) {
773 maybe_err("malloc failed"); 773 maybe_err("malloc failed");
774 goto out1; 774 goto out1;
775 } 775 }
776 776
777 memset(&z, 0, sizeof z); 777 memset(&z, 0, sizeof z);
778 z.avail_in = prelen; 778 z.avail_in = prelen;
779 z.next_in = (unsigned char *)pre; 779 z.next_in = (unsigned char *)pre;
780 z.avail_out = BUFLEN; 780 z.avail_out = BUFLEN;
781 z.next_out = (unsigned char *)outbufp; 781 z.next_out = (unsigned char *)outbufp;
782 z.zalloc = NULL; 782 z.zalloc = NULL;
783 z.zfree = NULL; 783 z.zfree = NULL;
784 z.opaque = 0; 784 z.opaque = 0;
785 785
786 in_tot = prelen; 786 in_tot = prelen;
787 out_tot = 0; 787 out_tot = 0;
788 788
789 for (;;) { 789 for (;;) {
790 check_siginfo(); 790 check_siginfo();
791 if ((z.avail_in == 0 || needmore) && done_reading == 0) { 791 if ((z.avail_in == 0 || needmore) && done_reading == 0) {
792 ssize_t in_size; 792 ssize_t in_size;
793 793
794 if (z.avail_in > 0) { 794 if (z.avail_in > 0) {
795 memmove(inbufp, z.next_in, z.avail_in); 795 memmove(inbufp, z.next_in, z.avail_in);
796 } 796 }
797 z.next_in = (unsigned char *)inbufp; 797 z.next_in = (unsigned char *)inbufp;
798 in_size = read(in, z.next_in + z.avail_in, 798 in_size = read(in, z.next_in + z.avail_in,
799 BUFLEN - z.avail_in); 799 BUFLEN - z.avail_in);
800 800
801 if (in_size == -1) { 801 if (in_size == -1) {
802 maybe_warn("failed to read stdin"); 802 maybe_warn("failed to read stdin");
803 goto stop_and_fail; 803 goto stop_and_fail;
804 } else if (in_size == 0) { 804 } else if (in_size == 0) {
805 done_reading = 1; 805 done_reading = 1;
806 } 806 }
807 infile_newdata(in_size); 807 infile_newdata(in_size);
808 808
809 z.avail_in += in_size; 809 z.avail_in += in_size;
810 needmore = 0; 810 needmore = 0;
811 811
812 in_tot += in_size; 812 in_tot += in_size;
813 } 813 }
814 if (z.avail_in == 0) { 814 if (z.avail_in == 0) {
815 if (done_reading && state != GZSTATE_MAGIC0) { 815 if (done_reading && state != GZSTATE_MAGIC0) {
816 maybe_warnx("%s: unexpected end of file", 816 maybe_warnx("%s: unexpected end of file",
817 filename); 817 filename);
818 goto stop_and_fail; 818 goto stop_and_fail;
819 } 819 }
820 goto stop; 820 goto stop;
821 } 821 }
822 switch (state) { 822 switch (state) {
823 case GZSTATE_MAGIC0: 823 case GZSTATE_MAGIC0:
824 if (*z.next_in != GZIP_MAGIC0) { 824 if (*z.next_in != GZIP_MAGIC0) {
825 if (in_tot > 0) { 825 if (in_tot > 0) {
826 maybe_warnx("%s: trailing garbage " 826 maybe_warnx("%s: trailing garbage "
827 "ignored", filename); 827 "ignored", filename);
828 goto stop; 828 goto stop;
829 } 829 }
830 maybe_warnx("input not gziped (MAGIC0)"); 830 maybe_warnx("input not gziped (MAGIC0)");
831 exit_value = 2; 831 exit_value = 2;
832 goto stop_and_fail; 832 goto stop_and_fail;
833 } 833 }
834 ADVANCE(); 834 ADVANCE();
835 state++; 835 state++;
836 out_sub_tot = 0; 836 out_sub_tot = 0;
837 crc = crc32(0L, Z_NULL, 0); 837 crc = crc32(0L, Z_NULL, 0);
838 break; 838 break;
839 839
840 case GZSTATE_MAGIC1: 840 case GZSTATE_MAGIC1:
841 if (*z.next_in != GZIP_MAGIC1 && 841 if (*z.next_in != GZIP_MAGIC1 &&
842 *z.next_in != GZIP_OMAGIC1) { 842 *z.next_in != GZIP_OMAGIC1) {
843 maybe_warnx("input not gziped (MAGIC1)"); 843 maybe_warnx("input not gziped (MAGIC1)");
844 goto stop_and_fail; 844 goto stop_and_fail;
845 } 845 }
846 ADVANCE(); 846 ADVANCE();
847 state++; 847 state++;
848 break; 848 break;
849 849
850 case GZSTATE_METHOD: 850 case GZSTATE_METHOD:
851 if (*z.next_in != Z_DEFLATED) { 851 if (*z.next_in != Z_DEFLATED) {
852 maybe_warnx("unknown compression method"); 852 maybe_warnx("unknown compression method");
853 goto stop_and_fail; 853 goto stop_and_fail;
854 } 854 }
855 ADVANCE(); 855 ADVANCE();
856 state++; 856 state++;
857 break; 857 break;
858 858
859 case GZSTATE_FLAGS: 859 case GZSTATE_FLAGS:
860 flags = *z.next_in; 860 flags = *z.next_in;
861 ADVANCE(); 861 ADVANCE();
862 skip_count = 6; 862 skip_count = 6;
863 state++; 863 state++;
864 break; 864 break;
865 865
866 case GZSTATE_SKIPPING: 866 case GZSTATE_SKIPPING:
867 if (skip_count > 0) { 867 if (skip_count > 0) {
868 skip_count--; 868 skip_count--;
869 ADVANCE(); 869 ADVANCE();
870 } else 870 } else
871 state++; 871 state++;
872 break; 872 break;
873 873
874 case GZSTATE_EXTRA: 874 case GZSTATE_EXTRA:
875 if ((flags & EXTRA_FIELD) == 0) { 875 if ((flags & EXTRA_FIELD) == 0) {
876 state = GZSTATE_ORIGNAME; 876 state = GZSTATE_ORIGNAME;
877 break; 877 break;
878 } 878 }
879 skip_count = *z.next_in; 879 skip_count = *z.next_in;
880 ADVANCE(); 880 ADVANCE();
881 state++; 881 state++;
882 break; 882 break;
883 883
884 case GZSTATE_EXTRA2: 884 case GZSTATE_EXTRA2:
885 skip_count |= ((*z.next_in) << 8); 885 skip_count |= ((*z.next_in) << 8);
886 ADVANCE(); 886 ADVANCE();
887 state++; 887 state++;
888 break; 888 break;
889 889
890 case GZSTATE_EXTRA3: 890 case GZSTATE_EXTRA3:
891 if (skip_count > 0) { 891 if (skip_count > 0) {
892 skip_count--; 892 skip_count--;
893 ADVANCE(); 893 ADVANCE();
894 } else 894 } else
895 state++; 895 state++;
896 break; 896 break;
897 897
898 case GZSTATE_ORIGNAME: 898 case GZSTATE_ORIGNAME:
899 if ((flags & ORIG_NAME) == 0) { 899 if ((flags & ORIG_NAME) == 0) {
900 state++; 900 state++;
901 break; 901 break;
902 } 902 }
903 if (*z.next_in == 0) 903 if (*z.next_in == 0)
904 state++; 904 state++;
905 ADVANCE(); 905 ADVANCE();
906 break; 906 break;
907 907
908 case GZSTATE_COMMENT: 908 case GZSTATE_COMMENT:
909 if ((flags & COMMENT) == 0) { 909 if ((flags & COMMENT) == 0) {
910 state++; 910 state++;
911 break; 911 break;
912 } 912 }
913 if (*z.next_in == 0) 913 if (*z.next_in == 0)
914 state++; 914 state++;
915 ADVANCE(); 915 ADVANCE();
916 break; 916 break;
917 917
918 case GZSTATE_HEAD_CRC1: 918 case GZSTATE_HEAD_CRC1:
919 if (flags & HEAD_CRC) 919 if (flags & HEAD_CRC)
920 skip_count = 2; 920 skip_count = 2;
921 else 921 else
922 skip_count = 0; 922 skip_count = 0;
923 state++; 923 state++;
924 break; 924 break;
925 925
926 case GZSTATE_HEAD_CRC2: 926 case GZSTATE_HEAD_CRC2:
927 if (skip_count > 0) { 927 if (skip_count > 0) {
928 skip_count--; 928 skip_count--;
929 ADVANCE(); 929 ADVANCE();
930 } else 930 } else
931 state++; 931 state++;
932 break; 932 break;
933 933
934 case GZSTATE_INIT: 934 case GZSTATE_INIT:
935 if (inflateInit2(&z, -MAX_WBITS) != Z_OK) { 935 if (inflateInit2(&z, -MAX_WBITS) != Z_OK) {
936 maybe_warnx("failed to inflateInit"); 936 maybe_warnx("failed to inflateInit");
937 goto stop_and_fail; 937 goto stop_and_fail;
938 } 938 }
939 state++; 939 state++;
940 break; 940 break;
941 941
942 case GZSTATE_READ: 942 case GZSTATE_READ:
943 error = inflate(&z, Z_FINISH); 943 error = inflate(&z, Z_FINISH);
944 switch (error) { 944 switch (error) {
945 /* Z_BUF_ERROR goes with Z_FINISH... */ 945 /* Z_BUF_ERROR goes with Z_FINISH... */
946 case Z_BUF_ERROR: 946 case Z_BUF_ERROR:
947 if (z.avail_out > 0 && !done_reading) 947 if (z.avail_out > 0 && !done_reading)
948 continue; 948 continue;
949 949
950 case Z_STREAM_END: 950 case Z_STREAM_END:
951 case Z_OK: 951 case Z_OK:
952 break; 952 break;
953 953
954 case Z_NEED_DICT: 954 case Z_NEED_DICT:
955 maybe_warnx("Z_NEED_DICT error"); 955 maybe_warnx("Z_NEED_DICT error");
956 goto stop_and_fail; 956 goto stop_and_fail;
957 case Z_DATA_ERROR: 957 case Z_DATA_ERROR:
958 maybe_warnx("data stream error"); 958 maybe_warnx("data stream error");
959 goto stop_and_fail; 959 goto stop_and_fail;
960 case Z_STREAM_ERROR: 960 case Z_STREAM_ERROR:
961 maybe_warnx("internal stream error"); 961 maybe_warnx("internal stream error");
962 goto stop_and_fail; 962 goto stop_and_fail;
963 case Z_MEM_ERROR: 963 case Z_MEM_ERROR:
964 maybe_warnx("memory allocation error"); 964 maybe_warnx("memory allocation error");
965 goto stop_and_fail; 965 goto stop_and_fail;
966 966
967 default: 967 default:
968 maybe_warn("unknown error from inflate(): %d", 968 maybe_warn("unknown error from inflate(): %d",
969 error); 969 error);
970 } 970 }
971 wr = BUFLEN - z.avail_out; 971 wr = BUFLEN - z.avail_out;
972 972
973 if (wr != 0) { 973 if (wr != 0) {
974 crc = crc32(crc, (const Bytef *)outbufp, (unsigned)wr); 974 crc = crc32(crc, (const Bytef *)outbufp, (unsigned)wr);
975 if ( 975 if (
976#ifndef SMALL 976#ifndef SMALL
977 /* don't write anything with -t */ 977 /* don't write anything with -t */
978 tflag == 0 && 978 tflag == 0 &&
979#endif 979#endif
980 write_retry(out, outbufp, wr) != wr) { 980 write_retry(out, outbufp, wr) != wr) {
981 maybe_warn("error writing to output"); 981 maybe_warn("error writing to output");
982 goto stop_and_fail; 982 goto stop_and_fail;
983 } 983 }
984 984
985 out_tot += wr; 985 out_tot += wr;
986 out_sub_tot += wr; 986 out_sub_tot += wr;
987 } 987 }
988 988
989 if (error == Z_STREAM_END) { 989 if (error == Z_STREAM_END) {
990 inflateEnd(&z); 990 inflateEnd(&z);
991 state++; 991 state++;
992 } 992 }
993 993
994 z.next_out = (unsigned char *)outbufp; 994 z.next_out = (unsigned char *)outbufp;
995 z.avail_out = BUFLEN; 995 z.avail_out = BUFLEN;
996 996
997 break; 997 break;
998 case GZSTATE_CRC: 998 case GZSTATE_CRC:
999 { 999 {
1000 uLong origcrc; 1000 uLong origcrc;
1001 1001
1002 if (z.avail_in < 4) { 1002 if (z.avail_in < 4) {
1003 if (!done_reading) { 1003 if (!done_reading) {
1004 needmore = 1; 1004 needmore = 1;
1005 continue; 1005 continue;
1006 } 1006 }
1007 maybe_warnx("truncated input"); 1007 maybe_warnx("truncated input");
1008 goto stop_and_fail; 1008 goto stop_and_fail;
1009 } 1009 }
1010 origcrc = ((unsigned)z.next_in[0] & 0xff) | 1010 origcrc = ((unsigned)z.next_in[0] & 0xff) |
1011 ((unsigned)z.next_in[1] & 0xff) << 8 | 1011 ((unsigned)z.next_in[1] & 0xff) << 8 |
1012 ((unsigned)z.next_in[2] & 0xff) << 16 | 1012 ((unsigned)z.next_in[2] & 0xff) << 16 |
1013 ((unsigned)z.next_in[3] & 0xff) << 24; 1013 ((unsigned)z.next_in[3] & 0xff) << 24;
1014 if (origcrc != crc) { 1014 if (origcrc != crc) {
1015 maybe_warnx("invalid compressed" 1015 maybe_warnx("invalid compressed"
1016 " data--crc error"); 1016 " data--crc error");
1017 goto stop_and_fail; 1017 goto stop_and_fail;
1018 } 1018 }
1019 } 1019 }
1020 1020
1021 z.avail_in -= 4; 1021 z.avail_in -= 4;
1022 z.next_in += 4; 1022 z.next_in += 4;
1023 1023
1024 if (!z.avail_in && done_reading) { 1024 if (!z.avail_in && done_reading) {
1025 goto stop; 1025 goto stop;
1026 } 1026 }
1027 state++; 1027 state++;
1028 break; 1028 break;
1029 case GZSTATE_LEN: 1029 case GZSTATE_LEN:
1030 { 1030 {
1031 uLong origlen; 1031 uLong origlen;
1032 1032
1033 if (z.avail_in < 4) { 1033 if (z.avail_in < 4) {
1034 if (!done_reading) { 1034 if (!done_reading) {
1035 needmore = 1; 1035 needmore = 1;
1036 continue; 1036 continue;
1037 } 1037 }
1038 maybe_warnx("truncated input"); 1038 maybe_warnx("truncated input");
1039 goto stop_and_fail; 1039 goto stop_and_fail;
1040 } 1040 }
1041 origlen = ((unsigned)z.next_in[0] & 0xff) | 1041 origlen = ((unsigned)z.next_in[0] & 0xff) |
1042 ((unsigned)z.next_in[1] & 0xff) << 8 | 1042 ((unsigned)z.next_in[1] & 0xff) << 8 |
1043 ((unsigned)z.next_in[2] & 0xff) << 16 | 1043 ((unsigned)z.next_in[2] & 0xff) << 16 |
1044 ((unsigned)z.next_in[3] & 0xff) << 24; 1044 ((unsigned)z.next_in[3] & 0xff) << 24;
1045 1045
1046 if (origlen != out_sub_tot) { 1046 if (origlen != out_sub_tot) {
1047 maybe_warnx("invalid compressed" 1047 maybe_warnx("invalid compressed"
1048 " data--length error"); 1048 " data--length error");
1049 goto stop_and_fail; 1049 goto stop_and_fail;
1050 } 1050 }
1051 } 1051 }
1052  1052
1053 z.avail_in -= 4; 1053 z.avail_in -= 4;
1054 z.next_in += 4; 1054 z.next_in += 4;
1055 1055
1056 if (error < 0) { 1056 if (error < 0) {
1057 maybe_warnx("decompression error"); 1057 maybe_warnx("decompression error");
1058 goto stop_and_fail; 1058 goto stop_and_fail;
1059 } 1059 }
1060 state = GZSTATE_MAGIC0; 1060 state = GZSTATE_MAGIC0;
1061 break; 1061 break;
1062 } 1062 }
1063 continue; 1063 continue;
1064stop_and_fail: 1064stop_and_fail:
1065 out_tot = -1; 1065 out_tot = -1;
1066stop: 1066stop:
1067 break; 1067 break;
1068 } 1068 }
1069 if (state > GZSTATE_INIT) 1069 if (state > GZSTATE_INIT)
1070 inflateEnd(&z); 1070 inflateEnd(&z);
1071 1071
1072 free(inbufp); 1072 free(inbufp);
1073out1: 1073out1:
1074 free(outbufp); 1074 free(outbufp);
1075out2: 1075out2:
1076 if (gsizep) 1076 if (gsizep)
1077 *gsizep = in_tot; 1077 *gsizep = in_tot;
1078 return (out_tot); 1078 return (out_tot);
1079} 1079}
1080 1080
1081#ifndef SMALL 1081#ifndef SMALL
1082/* 1082/*
1083 * set the owner, mode, flags & utimes using the given file descriptor. 1083 * set the owner, mode, flags & utimes using the given file descriptor.
1084 * file is only used in possible warning messages. 1084 * file is only used in possible warning messages.
1085 */ 1085 */
1086static void 1086static void
1087copymodes(int fd, const struct stat *sbp, const char *file) 1087copymodes(int fd, const struct stat *sbp, const char *file)
1088{ 1088{
1089 struct timeval times[2]; 1089 struct timeval times[2];
1090 struct stat sb; 1090 struct stat sb;
1091 1091
1092 /* 1092 /*
1093 * If we have no info on the input, give this file some 1093 * If we have no info on the input, give this file some
1094 * default values and return.. 1094 * default values and return..
1095 */ 1095 */
1096 if (sbp == NULL) { 1096 if (sbp == NULL) {
1097 mode_t mask = umask(022); 1097 mode_t mask = umask(022);
1098 1098
1099 (void)fchmod(fd, DEFFILEMODE & ~mask); 1099 (void)fchmod(fd, DEFFILEMODE & ~mask);
1100 (void)umask(mask); 1100 (void)umask(mask);
1101 return; 1101 return;
1102 } 1102 }
1103 sb = *sbp; 1103 sb = *sbp;
1104 1104
1105 /* if the chown fails, remove set-id bits as-per compress(1) */ 1105 /* if the chown fails, remove set-id bits as-per compress(1) */
1106 if (fchown(fd, sb.st_uid, sb.st_gid) < 0) { 1106 if (fchown(fd, sb.st_uid, sb.st_gid) < 0) {
1107 if (errno != EPERM) 1107 if (errno != EPERM)
1108 maybe_warn("couldn't fchown: %s", file); 1108 maybe_warn("couldn't fchown: %s", file);
1109 sb.st_mode &= ~(S_ISUID|S_ISGID); 1109 sb.st_mode &= ~(S_ISUID|S_ISGID);
1110 } 1110 }
1111 1111
1112 /* we only allow set-id and the 9 normal permission bits */ 1112 /* we only allow set-id and the 9 normal permission bits */
1113 sb.st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; 1113 sb.st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
1114 if (fchmod(fd, sb.st_mode) < 0) 1114 if (fchmod(fd, sb.st_mode) < 0)
1115 maybe_warn("couldn't fchmod: %s", file); 1115 maybe_warn("couldn't fchmod: %s", file);
1116 1116
1117 /* only try flags if they exist already */ 1117 /* only try flags if they exist already */
1118 if (sb.st_flags != 0 && fchflags(fd, sb.st_flags) < 0) 1118 if (sb.st_flags != 0 && fchflags(fd, sb.st_flags) < 0)
1119 maybe_warn("couldn't fchflags: %s", file); 1119 maybe_warn("couldn't fchflags: %s", file);
1120 1120
1121 TIMESPEC_TO_TIMEVAL(&times[0], &sb.st_atimespec); 1121 TIMESPEC_TO_TIMEVAL(&times[0], &sb.st_atimespec);
1122 TIMESPEC_TO_TIMEVAL(&times[1], &sb.st_mtimespec); 1122 TIMESPEC_TO_TIMEVAL(&times[1], &sb.st_mtimespec);
1123 if (futimes(fd, times) < 0) 1123 if (futimes(fd, times) < 0)
1124 maybe_warn("couldn't utimes: %s", file); 1124 maybe_warn("couldn't utimes: %s", file);
1125} 1125}
1126#endif 1126#endif
1127 1127
1128/* what sort of file is this? */ 1128/* what sort of file is this? */
1129static enum filetype 1129static enum filetype
1130file_gettype(u_char *buf) 1130file_gettype(u_char *buf)
1131{ 1131{
1132 1132
1133 if (buf[0] == GZIP_MAGIC0 && 1133 if (buf[0] == GZIP_MAGIC0 &&
1134 (buf[1] == GZIP_MAGIC1 || buf[1] == GZIP_OMAGIC1)) 1134 (buf[1] == GZIP_MAGIC1 || buf[1] == GZIP_OMAGIC1))
1135 return FT_GZIP; 1135 return FT_GZIP;
1136 else 1136 else
1137#ifndef NO_BZIP2_SUPPORT 1137#ifndef NO_BZIP2_SUPPORT
1138 if (memcmp(buf, BZIP2_MAGIC, 3) == 0 && 1138 if (memcmp(buf, BZIP2_MAGIC, 3) == 0 &&
1139 buf[3] >= '0' && buf[3] <= '9') 1139 buf[3] >= '0' && buf[3] <= '9')
1140 return FT_BZIP2; 1140 return FT_BZIP2;
1141 else 1141 else
1142#endif 1142#endif
1143#ifndef NO_COMPRESS_SUPPORT 1143#ifndef NO_COMPRESS_SUPPORT
1144 if (memcmp(buf, Z_MAGIC, 2) == 0) 1144 if (memcmp(buf, Z_MAGIC, 2) == 0)
1145 return FT_Z; 1145 return FT_Z;
1146 else 1146 else
1147#endif 1147#endif
1148#ifndef NO_PACK_SUPPORT 1148#ifndef NO_PACK_SUPPORT
1149 if (memcmp(buf, PACK_MAGIC, 2) == 0) 1149 if (memcmp(buf, PACK_MAGIC, 2) == 0)
1150 return FT_PACK; 1150 return FT_PACK;
1151 else 1151 else
1152#endif 1152#endif
1153#ifndef NO_XZ_SUPPORT 1153#ifndef NO_XZ_SUPPORT
1154 if (memcmp(buf, XZ_MAGIC, 4) == 0) /* XXX: We only have 4 bytes */ 1154 if (memcmp(buf, XZ_MAGIC, 4) == 0) /* XXX: We only have 4 bytes */
1155 return FT_XZ; 1155 return FT_XZ;
1156 else 1156 else
1157#endif 1157#endif
1158#ifndef NO_LZ_SUPPORT 1158#ifndef NO_LZ_SUPPORT
1159 if (memcmp(buf, LZ_MAGIC, 4) == 0) 1159 if (memcmp(buf, LZ_MAGIC, 4) == 0)
1160 return FT_LZ; 1160 return FT_LZ;
1161 else 1161 else
1162#endif 1162#endif
1163 return FT_UNKNOWN; 1163 return FT_UNKNOWN;
1164} 1164}
1165 1165
1166#ifndef SMALL 1166#ifndef SMALL
1167/* check the outfile is OK. */ 1167/* check the outfile is OK. */
1168static int 1168static int
1169check_outfile(const char *outfile) 1169check_outfile(const char *outfile)
1170{ 1170{
1171 struct stat sb; 1171 struct stat sb;
1172 int ok = 1; 1172 int ok = 1;
1173 1173
1174 if (lflag == 0 && stat(outfile, &sb) == 0) { 1174 if (lflag == 0 && stat(outfile, &sb) == 0) {
1175 if (fflag) 1175 if (fflag)
1176 unlink(outfile); 1176 unlink(outfile);
1177 else if (isatty(STDIN_FILENO)) { 1177 else if (isatty(STDIN_FILENO)) {
1178 char ans[10] = { 'n', '\0' }; /* default */ 1178 char ans[10] = { 'n', '\0' }; /* default */
1179 1179
1180 fprintf(stderr, "%s already exists -- do you wish to " 1180 fprintf(stderr, "%s already exists -- do you wish to "
1181 "overwrite (y or n)? " , outfile); 1181 "overwrite (y or n)? " , outfile);
1182 (void)fgets(ans, sizeof(ans) - 1, stdin); 1182 (void)fgets(ans, sizeof(ans) - 1, stdin);
1183 if (ans[0] != 'y' && ans[0] != 'Y') { 1183 if (ans[0] != 'y' && ans[0] != 'Y') {
1184 fprintf(stderr, "\tnot overwriting\n"); 1184 fprintf(stderr, "\tnot overwriting\n");
1185 ok = 0; 1185 ok = 0;
1186 } else 1186 } else
1187 unlink(outfile); 1187 unlink(outfile);
1188 } else { 1188 } else {
1189 maybe_warnx("%s already exists -- skipping", outfile); 1189 maybe_warnx("%s already exists -- skipping", outfile);
1190 ok = 0; 1190 ok = 0;
1191 } 1191 }
1192 } 1192 }
1193 return ok; 1193 return ok;
1194} 1194}
1195 1195
1196static void 1196static void
1197unlink_input(const char *file, const struct stat *sb) 1197unlink_input(const char *file, const struct stat *sb)
1198{ 1198{
1199 struct stat nsb; 1199 struct stat nsb;
1200 1200
1201 if (kflag) 1201 if (kflag)
1202 return; 1202 return;
1203 if (stat(file, &nsb) != 0) 1203 if (stat(file, &nsb) != 0)
1204 /* Must be gone already */ 1204 /* Must be gone already */
1205 return; 1205 return;
1206 if (nsb.st_dev != sb->st_dev || nsb.st_ino != sb->st_ino) 1206 if (nsb.st_dev != sb->st_dev || nsb.st_ino != sb->st_ino)
1207 /* Definitely a different file */ 1207 /* Definitely a different file */
1208 return; 1208 return;
1209 unlink(file); 1209 unlink(file);
1210} 1210}
1211 1211
1212static void 1212static void
1213got_siginfo(int signo) 1213got_siginfo(int signo)
1214{ 1214{
1215 1215
1216 print_info = 1; 1216 print_info = 1;
1217} 1217}
1218 1218
1219static void 1219static void
1220setup_signals(void) 1220setup_signals(void)
1221{ 1221{
1222 1222
1223 signal(SIGINFO, got_siginfo); 1223 signal(SIGINFO, got_siginfo);
1224} 1224}
1225 1225
1226static void 1226static void
1227infile_newdata(size_t newdata) 1227infile_newdata(size_t newdata)
1228{ 1228{
1229 1229
1230 infile_current += newdata; 1230 infile_current += newdata;
1231} 1231}
1232#endif 1232#endif
1233 1233
1234static void 1234static void
1235infile_set(const char *newinfile, off_t total) 1235infile_set(const char *newinfile, off_t total)
1236{ 1236{
1237 1237
1238 if (newinfile) 1238 if (newinfile)
1239 infile = newinfile; 1239 infile = newinfile;
1240#ifndef SMALL 1240#ifndef SMALL
1241 infile_total = total; 1241 infile_total = total;
1242#endif 1242#endif
1243} 1243}
1244 1244
1245static void 1245static void
1246infile_clear(void) 1246infile_clear(void)
1247{ 1247{
1248 1248
1249 infile = NULL; 1249 infile = NULL;
1250#ifndef SMALL 1250#ifndef SMALL
1251 infile_total = infile_current = 0; 1251 infile_total = infile_current = 0;
1252#endif 1252#endif
1253} 1253}
1254 1254
1255static const suffixes_t * 1255static const suffixes_t *
1256check_suffix(char *file, int xlate) 1256check_suffix(char *file, int xlate)
1257{ 1257{
1258 const suffixes_t *s; 1258 const suffixes_t *s;
1259 int len = strlen(file); 1259 int len = strlen(file);
1260 char *sp; 1260 char *sp;
1261 1261
1262 for (s = suffixes; s != suffixes + NUM_SUFFIXES; s++) { 1262 for (s = suffixes; s != suffixes + NUM_SUFFIXES; s++) {
1263 /* if it doesn't fit in "a.suf", don't bother */ 1263 /* if it doesn't fit in "a.suf", don't bother */
1264 if (s->ziplen >= len) 1264 if (s->ziplen >= len)
1265 continue; 1265 continue;
1266 sp = file + len - s->ziplen; 1266 sp = file + len - s->ziplen;
1267 if (strcmp(s->zipped, sp) != 0) 1267 if (strcmp(s->zipped, sp) != 0)
1268 continue; 1268 continue;
1269 if (xlate) 1269 if (xlate)
1270 strcpy(sp, s->normal); 1270 strcpy(sp, s->normal);
1271 return s; 1271 return s;
1272 } 1272 }
1273 return NULL; 1273 return NULL;
1274} 1274}
1275 1275
1276/* 1276/*
1277 * compress the given file: create a corresponding .gz file and remove the 1277 * compress the given file: create a corresponding .gz file and remove the
1278 * original. 1278 * original.
1279 */ 1279 */
1280static off_t 1280static off_t
1281file_compress(char *file, char *outfile, size_t outsize) 1281file_compress(char *file, char *outfile, size_t outsize)
1282{ 1282{
1283 int in; 1283 int in;
1284 int out; 1284 int out;
1285 off_t size, in_size; 1285 off_t size, in_size;
1286#ifndef SMALL 1286#ifndef SMALL
1287 struct stat isb, osb; 1287 struct stat isb, osb;
1288 const suffixes_t *suff; 1288 const suffixes_t *suff;
1289#endif 1289#endif
1290 1290
1291 in = open(file, O_RDONLY); 1291 in = open(file, O_RDONLY);
1292 if (in == -1) { 1292 if (in == -1) {
1293 maybe_warn("can't open %s", file); 1293 maybe_warn("can't open %s", file);
1294 return -1; 1294 return -1;
1295 } 1295 }
1296 1296
1297#ifndef SMALL 1297#ifndef SMALL
1298 if (fstat(in, &isb) != 0) { 1298 if (fstat(in, &isb) != 0) {
1299 close(in); 1299 close(in);
1300 maybe_warn("can't stat %s", file); 1300 maybe_warn("can't stat %s", file);
1301 return -1; 1301 return -1;
1302 } 1302 }
1303 infile_set(file, isb.st_size); 1303 infile_set(file, isb.st_size);
1304#endif 1304#endif
1305 1305
1306 if (cflag == 0) { 1306 if (cflag == 0) {
1307#ifndef SMALL 1307#ifndef SMALL
1308 if (isb.st_nlink > 1 && fflag == 0) { 1308 if (isb.st_nlink > 1 && fflag == 0) {
1309 maybe_warnx("%s has %d other link%s -- " 1309 maybe_warnx("%s has %d other link%s -- "
1310 "skipping", file, isb.st_nlink - 1, 1310 "skipping", file, isb.st_nlink - 1,
1311 isb.st_nlink == 1 ? "" : "s"); 1311 isb.st_nlink == 1 ? "" : "s");
1312 close(in); 1312 close(in);
1313 return -1; 1313 return -1;
1314 } 1314 }
1315 1315
1316 if (fflag == 0 && (suff = check_suffix(file, 0)) 1316 if (fflag == 0 && (suff = check_suffix(file, 0))
1317 && suff->zipped[0] != 0) { 1317 && suff->zipped[0] != 0) {
1318 maybe_warnx("%s already has %s suffix -- unchanged", 1318 maybe_warnx("%s already has %s suffix -- unchanged",
1319 file, suff->zipped); 1319 file, suff->zipped);
1320 close(in); 1320 close(in);
1321 return -1; 1321 return -1;
1322 } 1322 }
1323#endif 1323#endif
1324 1324
1325 /* Add (usually) .gz to filename */ 1325 /* Add (usually) .gz to filename */
1326 if ((size_t)snprintf(outfile, outsize, "%s%s", 1326 if ((size_t)snprintf(outfile, outsize, "%s%s",
1327 file, suffixes[0].zipped) >= outsize) 1327 file, suffixes[0].zipped) >= outsize)
1328 memcpy(outfile + outsize - suffixes[0].ziplen - 1, 1328 memcpy(outfile + outsize - suffixes[0].ziplen - 1,
1329 suffixes[0].zipped, suffixes[0].ziplen + 1); 1329 suffixes[0].zipped, suffixes[0].ziplen + 1);
1330 1330
1331#ifndef SMALL 1331#ifndef SMALL
1332 if (check_outfile(outfile) == 0) { 1332 if (check_outfile(outfile) == 0) {
1333 close(in); 1333 close(in);
1334 return -1; 1334 return -1;
1335 } 1335 }
1336#endif 1336#endif
1337 } 1337 }
1338 1338
1339 if (cflag == 0) { 1339 if (cflag == 0) {
1340 out = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600); 1340 out = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600);
1341 if (out == -1) { 1341 if (out == -1) {
1342 maybe_warn("could not create output: %s", outfile); 1342 maybe_warn("could not create output: %s", outfile);
1343 fclose(stdin); 1343 fclose(stdin);
1344 return -1; 1344 return -1;
1345 } 1345 }
1346 } else 1346 } else
1347 out = STDOUT_FILENO; 1347 out = STDOUT_FILENO;
1348 1348
1349 in_size = gz_compress(in, out, &size, basename(file), (uint32_t)isb.st_mtime); 1349 in_size = gz_compress(in, out, &size, basename(file), (uint32_t)isb.st_mtime);
1350 1350
1351 (void)close(in); 1351 (void)close(in);
1352 1352
1353 /* 1353 /*
1354 * If there was an error, in_size will be -1. 1354 * If there was an error, in_size will be -1.
1355 * If we compressed to stdout, just return the size. 1355 * If we compressed to stdout, just return the size.
1356 * Otherwise stat the file and check it is the correct size. 1356 * Otherwise stat the file and check it is the correct size.
1357 * We only blow away the file if we can stat the output and it 1357 * We only blow away the file if we can stat the output and it
1358 * has the expected size. 1358 * has the expected size.
1359 */ 1359 */
1360 if (cflag != 0) 1360 if (cflag != 0)
1361 return in_size == -1 ? -1 : size; 1361 return in_size == -1 ? -1 : size;
1362 1362
1363#ifndef SMALL 1363#ifndef SMALL
1364 if (fstat(out, &osb) != 0) { 1364 if (fstat(out, &osb) != 0) {
1365 maybe_warn("couldn't stat: %s", outfile); 1365 maybe_warn("couldn't stat: %s", outfile);
1366 goto bad_outfile; 1366 goto bad_outfile;
1367 } 1367 }
1368 1368
1369 if (osb.st_size != size) { 1369 if (osb.st_size != size) {
1370 maybe_warnx("output file: %s wrong size (%" PRIdOFF 1370 maybe_warnx("output file: %s wrong size (%" PRIdOFF
1371 " != %" PRIdOFF "), deleting", 1371 " != %" PRIdOFF "), deleting",
1372 outfile, osb.st_size, size); 1372 outfile, osb.st_size, size);
1373 goto bad_outfile; 1373 goto bad_outfile;
1374 } 1374 }
1375 1375
1376 copymodes(out, &isb, outfile); 1376 copymodes(out, &isb, outfile);
1377#endif 1377#endif
1378 if (close(out) == -1) 1378 if (close(out) == -1)
1379 maybe_warn("couldn't close output"); 1379 maybe_warn("couldn't close output");
1380 1380
1381 /* output is good, ok to delete input */ 1381 /* output is good, ok to delete input */
1382 unlink_input(file, &isb); 1382 unlink_input(file, &isb);
1383 return size; 1383 return size;
1384 1384
1385#ifndef SMALL 1385#ifndef SMALL
1386 bad_outfile: 1386 bad_outfile:
1387 if (close(out) == -1) 1387 if (close(out) == -1)
1388 maybe_warn("couldn't close output"); 1388 maybe_warn("couldn't close output");
1389 1389
1390 maybe_warnx("leaving original %s", file); 1390 maybe_warnx("leaving original %s", file);
1391 unlink(outfile); 1391 unlink(outfile);
1392 return size; 1392 return size;
1393#endif 1393#endif
1394} 1394}
1395 1395
1396/* uncompress the given file and remove the original */ 1396/* uncompress the given file and remove the original */
1397static off_t 1397static off_t
1398file_uncompress(char *file, char *outfile, size_t outsize) 1398file_uncompress(char *file, char *outfile, size_t outsize)
1399{ 1399{
1400 struct stat isb, osb; 1400 struct stat isb, osb;
1401 off_t size; 1401 off_t size;
1402 ssize_t rbytes; 1402 ssize_t rbytes;
1403 unsigned char header1[4]; 1403 unsigned char fourbytes[4];
1404 enum filetype method; 1404 enum filetype method;
1405 int fd, ofd, zfd = -1; 1405 int fd, ofd, zfd = -1;
1406 size_t in_size; 1406 size_t in_size;
1407#ifndef SMALL 1407#ifndef SMALL
1408 ssize_t rv; 1408 ssize_t rv;
1409 time_t timestamp = 0; 1409 time_t timestamp = 0;
1410 char name[PATH_MAX + 1]; 1410 char name[PATH_MAX + 1];
1411#endif 1411#endif
1412 1412
1413 /* gather the old name info */ 1413 /* gather the old name info */
1414 1414
1415 fd = open(file, O_RDONLY); 1415 fd = open(file, O_RDONLY);
1416 if (fd < 0) { 1416 if (fd < 0) {
1417 maybe_warn("can't open %s", file); 1417 maybe_warn("can't open %s", file);
1418 goto lose; 1418 goto lose;
1419 } 1419 }
1420 if (fstat(fd, &isb) != 0) { 1420 if (fstat(fd, &isb) != 0) {
1421 close(fd); 1421 close(fd);
1422 maybe_warn("can't stat %s", file); 1422 maybe_warn("can't stat %s", file);
1423 goto lose; 1423 goto lose;
1424 } 1424 }
1425 if (S_ISREG(isb.st_mode)) 1425 if (S_ISREG(isb.st_mode))
1426 in_size = isb.st_size; 1426 in_size = isb.st_size;
1427 else 1427 else
1428 in_size = 0; 1428 in_size = 0;
1429 infile_set(file, in_size); 1429 infile_set(file, in_size);
1430 1430
1431 strlcpy(outfile, file, outsize); 1431 strlcpy(outfile, file, outsize);
1432 if (check_suffix(outfile, 1) == NULL && !(cflag || lflag)) { 1432 if (check_suffix(outfile, 1) == NULL && !(cflag || lflag)) {
1433 maybe_warnx("%s: unknown suffix -- ignored", file); 1433 maybe_warnx("%s: unknown suffix -- ignored", file);
1434 goto lose; 1434 goto lose;
1435 } 1435 }
1436 1436
1437 rbytes = read(fd, header1, sizeof header1); 1437 rbytes = read(fd, fourbytes, sizeof fourbytes);
1438 if (rbytes != sizeof header1) { 1438 if (rbytes != sizeof fourbytes) {
1439 /* we don't want to fail here. */ 1439 /* we don't want to fail here. */
1440#ifndef SMALL 1440#ifndef SMALL
1441 if (fflag) 1441 if (fflag)
1442 goto lose; 1442 goto lose;
1443#endif 1443#endif
1444 if (rbytes == -1) 1444 if (rbytes == -1)
1445 maybe_warn("can't read %s", file); 1445 maybe_warn("can't read %s", file);
1446 else 1446 else
1447 goto unexpected_EOF; 1447 goto unexpected_EOF;
1448 goto lose; 1448 goto lose;
1449 } 1449 }
1450 infile_newdata(rbytes); 1450 infile_newdata(rbytes);
1451 1451
1452 method = file_gettype(header1); 1452 method = file_gettype(fourbytes);
1453#ifndef SMALL 1453#ifndef SMALL
1454 if (fflag == 0 && method == FT_UNKNOWN) { 1454 if (fflag == 0 && method == FT_UNKNOWN) {
1455 maybe_warnx("%s: not in gzip format", file); 1455 maybe_warnx("%s: not in gzip format", file);
1456 goto lose; 1456 goto lose;
1457 } 1457 }
1458 1458
1459#endif 1459#endif
1460 1460
1461#ifndef SMALL 1461#ifndef SMALL
1462 if (method == FT_GZIP && Nflag) { 1462 if (method == FT_GZIP && Nflag) {
1463 unsigned char ts[4]; /* timestamp */ 1463 unsigned char ts[4]; /* timestamp */
1464 1464
1465 rv = pread(fd, ts, sizeof ts, GZIP_TIMESTAMP); 1465 rv = pread(fd, ts, sizeof ts, GZIP_TIMESTAMP);
1466 if (rv >= 0 && rv < (ssize_t)(sizeof ts)) 1466 if (rv >= 0 && rv < (ssize_t)(sizeof ts))
1467 goto unexpected_EOF; 1467 goto unexpected_EOF;
1468 if (rv == -1) { 1468 if (rv == -1) {
1469 if (!fflag) 1469 if (!fflag)
1470 maybe_warn("can't read %s", file); 1470 maybe_warn("can't read %s", file);
1471 goto lose; 1471 goto lose;
1472 } 1472 }
1473 infile_newdata(rv); 1473 infile_newdata(rv);
1474 timestamp = ts[3] << 24 | ts[2] << 16 | ts[1] << 8 | ts[0]; 1474 timestamp = ts[3] << 24 | ts[2] << 16 | ts[1] << 8 | ts[0];
1475 1475
1476 if (header1[3] & ORIG_NAME) { 1476 if (fourbytes[3] & ORIG_NAME) {
1477 rbytes = pread(fd, name, sizeof(name) - 1, GZIP_ORIGNAME); 1477 rbytes = pread(fd, name, sizeof(name) - 1, GZIP_ORIGNAME);
1478 if (rbytes < 0) { 1478 if (rbytes < 0) {
1479 maybe_warn("can't read %s", file); 1479 maybe_warn("can't read %s", file);
1480 goto lose; 1480 goto lose;
1481 } 1481 }
1482 if (name[0] != '\0') { 1482 if (name[0] != '\0') {
1483 char *dp, *nf; 1483 char *dp, *nf;
1484 1484
1485 /* Make sure that name is NUL-terminated */ 1485 /* Make sure that name is NUL-terminated */
1486 name[rbytes] = '\0'; 1486 name[rbytes] = '\0';
1487 1487
1488 /* strip saved directory name */ 1488 /* strip saved directory name */
1489 nf = strrchr(name, '/'); 1489 nf = strrchr(name, '/');
1490 if (nf == NULL) 1490 if (nf == NULL)
1491 nf = name; 1491 nf = name;
1492 else 1492 else
1493 nf++; 1493 nf++;
1494 1494
1495 /* preserve original directory name */ 1495 /* preserve original directory name */
1496 dp = strrchr(file, '/'); 1496 dp = strrchr(file, '/');
1497 if (dp == NULL) 1497 if (dp == NULL)
1498 dp = file; 1498 dp = file;
1499 else 1499 else
1500 dp++; 1500 dp++;
1501 snprintf(outfile, outsize, "%.*s%.*s", 1501 snprintf(outfile, outsize, "%.*s%.*s",
1502 (int) (dp - file), 1502 (int) (dp - file),
1503 file, (int) rbytes, nf); 1503 file, (int) rbytes, nf);
1504 } 1504 }
1505 } 1505 }
1506 } 1506 }
1507#endif 1507#endif
1508 lseek(fd, 0, SEEK_SET); 1508 lseek(fd, 0, SEEK_SET);
1509 1509
1510 if (cflag == 0 || lflag) { 1510 if (cflag == 0 || lflag) {
1511#ifndef SMALL 1511#ifndef SMALL
1512 if (isb.st_nlink > 1 && lflag == 0 && fflag == 0) { 1512 if (isb.st_nlink > 1 && lflag == 0 && fflag == 0) {
1513 maybe_warnx("%s has %d other links -- skipping", 1513 maybe_warnx("%s has %d other links -- skipping",
1514 file, isb.st_nlink - 1); 1514 file, isb.st_nlink - 1);
1515 goto lose; 1515 goto lose;
1516 } 1516 }
1517 if (nflag == 0 && timestamp) 1517 if (nflag == 0 && timestamp)
1518 isb.st_mtime = timestamp; 1518 isb.st_mtime = timestamp;
1519 if (check_outfile(outfile) == 0) 1519 if (check_outfile(outfile) == 0)
1520 goto lose; 1520 goto lose;
1521#endif 1521#endif
1522 } 1522 }
1523 1523
1524 if (cflag) 1524 if (cflag)
1525 zfd = STDOUT_FILENO; 1525 zfd = STDOUT_FILENO;
1526 else if (lflag) 1526 else if (lflag)
1527 zfd = -1; 1527 zfd = -1;
1528 else { 1528 else {
1529 zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600); 1529 zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600);
1530 if (zfd == STDOUT_FILENO) { 1530 if (zfd == STDOUT_FILENO) {
1531 /* We won't close STDOUT_FILENO later... */ 1531 /* We won't close STDOUT_FILENO later... */
1532 zfd = dup(zfd); 1532 zfd = dup(zfd);
1533 close(STDOUT_FILENO); 1533 close(STDOUT_FILENO);
1534 } 1534 }
1535 if (zfd == -1) { 1535 if (zfd == -1) {
1536 maybe_warn("can't open %s", outfile); 1536 maybe_warn("can't open %s", outfile);
1537 goto lose; 1537 goto lose;
1538 } 1538 }
1539 } 1539 }
1540 1540
1541 switch (method) { 1541 switch (method) {
1542#ifndef NO_BZIP2_SUPPORT 1542#ifndef NO_BZIP2_SUPPORT
1543 case FT_BZIP2: 1543 case FT_BZIP2:
1544 /* XXX */ 1544 /* XXX */
1545 if (lflag) { 1545 if (lflag) {
1546 maybe_warnx("no -l with bzip2 files"); 1546 maybe_warnx("no -l with bzip2 files");
1547 goto lose; 1547 goto lose;
1548 } 1548 }
1549 1549
1550 size = unbzip2(fd, zfd, NULL, 0, NULL); 1550 size = unbzip2(fd, zfd, NULL, 0, NULL);
1551 break; 1551 break;
1552#endif 1552#endif
1553 1553
1554#ifndef NO_COMPRESS_SUPPORT 1554#ifndef NO_COMPRESS_SUPPORT
1555 case FT_Z: { 1555 case FT_Z: {
1556 FILE *in, *out; 1556 FILE *in, *out;
1557 1557
1558 /* XXX */ 1558 /* XXX */
1559 if (lflag) { 1559 if (lflag) {
1560 maybe_warnx("no -l with Lempel-Ziv files"); 1560 maybe_warnx("no -l with Lempel-Ziv files");
1561 goto lose; 1561 goto lose;
1562 } 1562 }
1563 1563
1564 if ((in = zdopen(fd)) == NULL) { 1564 if ((in = zdopen(fd)) == NULL) {
1565 maybe_warn("zdopen for read: %s", file); 1565 maybe_warn("zdopen for read: %s", file);
1566 goto lose; 1566 goto lose;
1567 } 1567 }
1568 1568
1569 out = fdopen(dup(zfd), "w"); 1569 out = fdopen(dup(zfd), "w");
1570 if (out == NULL) { 1570 if (out == NULL) {
1571 maybe_warn("fdopen for write: %s", outfile); 1571 maybe_warn("fdopen for write: %s", outfile);
1572 fclose(in); 1572 fclose(in);
1573 goto lose; 1573 goto lose;
1574 } 1574 }
1575 1575
1576 size = zuncompress(in, out, NULL, 0, NULL); 1576 size = zuncompress(in, out, NULL, 0, NULL);
1577 /* need to fclose() if ferror() is true... */ 1577 /* need to fclose() if ferror() is true... */
1578 if (ferror(in) | fclose(in)) { 1578 if (ferror(in) | fclose(in)) {
1579 maybe_warn("failed infile fclose"); 1579 maybe_warn("failed infile fclose");
1580 unlink(outfile); 1580 unlink(outfile);
1581 (void)fclose(out); 1581 (void)fclose(out);
1582 } 1582 }
1583 if (fclose(out) != 0) { 1583 if (fclose(out) != 0) {
1584 maybe_warn("failed outfile fclose"); 1584 maybe_warn("failed outfile fclose");
1585 unlink(outfile); 1585 unlink(outfile);
1586 goto lose; 1586 goto lose;
1587 } 1587 }
1588 break; 1588 break;
1589 } 1589 }
1590#endif 1590#endif
1591 1591
1592#ifndef NO_PACK_SUPPORT 1592#ifndef NO_PACK_SUPPORT
1593 case FT_PACK: 1593 case FT_PACK:
1594 if (lflag) { 1594 if (lflag) {
1595 maybe_warnx("no -l with packed files"); 1595 maybe_warnx("no -l with packed files");
1596 goto lose; 1596 goto lose;
1597 } 1597 }
1598 1598
1599 size = unpack(fd, zfd, NULL, 0, NULL); 1599 size = unpack(fd, zfd, NULL, 0, NULL);
1600 break; 1600 break;
1601#endif 1601#endif
1602 1602
1603#ifndef NO_XZ_SUPPORT 1603#ifndef NO_XZ_SUPPORT
1604 case FT_XZ: 1604 case FT_XZ:
1605 if (lflag) { 1605 if (lflag) {
1606 size = unxz_len(fd); 1606 size = unxz_len(fd);
1607 print_list_out(in_size, size, file); 1607 print_list_out(in_size, size, file);
1608 return -1; 1608 return -1;
1609 } 1609 }
1610 size = unxz(fd, zfd, NULL, 0, NULL); 1610 size = unxz(fd, zfd, NULL, 0, NULL);
1611 break; 1611 break;
1612#endif 1612#endif
1613 1613
1614#ifndef NO_LZ_SUPPORT 1614#ifndef NO_LZ_SUPPORT
1615 case FT_LZ: 1615 case FT_LZ:
1616 if (lflag) { 1616 if (lflag) {
1617 maybe_warnx("no -l with lzip files"); 1617 maybe_warnx("no -l with lzip files");
1618 goto lose; 1618 goto lose;
1619 } 1619 }
1620 size = unlz(fd, zfd, NULL, 0, NULL); 1620 size = unlz(fd, zfd, NULL, 0, NULL);
1621 break; 1621 break;
1622#endif 1622#endif
1623#ifndef SMALL 1623#ifndef SMALL
1624 case FT_UNKNOWN: 1624 case FT_UNKNOWN:
1625 if (lflag) { 1625 if (lflag) {
1626 maybe_warnx("no -l for unknown filetypes"); 1626 maybe_warnx("no -l for unknown filetypes");
1627 goto lose; 1627 goto lose;
1628 } 1628 }
1629 size = cat_fd(NULL, 0, NULL, fd); 1629 size = cat_fd(NULL, 0, NULL, fd);
1630 break; 1630 break;
1631#endif 1631#endif
1632 default: 1632 default:
1633 if (lflag) { 1633 if (lflag) {
1634 print_list(fd, in_size, outfile, isb.st_mtime); 1634 print_list(fd, in_size, outfile, isb.st_mtime);
1635 close(fd); 1635 close(fd);
1636 return -1; /* XXX */ 1636 return -1; /* XXX */
1637 } 1637 }
1638 1638
1639 size = gz_uncompress(fd, zfd, NULL, 0, NULL, file); 1639 size = gz_uncompress(fd, zfd, NULL, 0, NULL, file);
1640 break; 1640 break;
1641 } 1641 }
1642 1642
1643 if (close(fd) != 0) 1643 if (close(fd) != 0)
1644 maybe_warn("couldn't close input"); 1644 maybe_warn("couldn't close input");
1645 if (zfd != STDOUT_FILENO && close(zfd) != 0) 1645 if (zfd != STDOUT_FILENO && close(zfd) != 0)
1646 maybe_warn("couldn't close output"); 1646 maybe_warn("couldn't close output");
1647 1647
1648 if (size == -1) { 1648 if (size == -1) {
1649 if (cflag == 0) 1649 if (cflag == 0)
1650 unlink(outfile); 1650 unlink(outfile);
1651 maybe_warnx("%s: uncompress failed", file); 1651 maybe_warnx("%s: uncompress failed", file);
1652 return -1; 1652 return -1;
1653 } 1653 }
1654 1654
1655 /* if testing, or we uncompressed to stdout, this is all we need */ 1655 /* if testing, or we uncompressed to stdout, this is all we need */
1656#ifndef SMALL 1656#ifndef SMALL
1657 if (tflag) 1657 if (tflag)
1658 return size; 1658 return size;
1659#endif 1659#endif
1660 /* if we are uncompressing to stdin, don't remove the file. */ 1660 /* if we are uncompressing to stdin, don't remove the file. */
1661 if (cflag) 1661 if (cflag)
1662 return size; 1662 return size;
1663 1663
1664 /* 1664 /*
1665 * if we create a file... 1665 * if we create a file...
1666 */ 1666 */
1667 /* 1667 /*
1668 * if we can't stat the file don't remove the file. 1668 * if we can't stat the file don't remove the file.
1669 */ 1669 */
1670 1670
1671 ofd = open(outfile, O_RDWR, 0); 1671 ofd = open(outfile, O_RDWR, 0);
1672 if (ofd == -1) { 1672 if (ofd == -1) {
1673 maybe_warn("couldn't open (leaving original): %s", 1673 maybe_warn("couldn't open (leaving original): %s",
1674 outfile); 1674 outfile);
1675 return -1; 1675 return -1;
1676 } 1676 }
1677 if (fstat(ofd, &osb) != 0) { 1677 if (fstat(ofd, &osb) != 0) {
1678 maybe_warn("couldn't stat (leaving original): %s", 1678 maybe_warn("couldn't stat (leaving original): %s",
1679 outfile); 1679 outfile);
1680 close(ofd); 1680 close(ofd);
1681 return -1; 1681 return -1;
1682 } 1682 }
1683 if (osb.st_size != size) { 1683 if (osb.st_size != size) {
1684 maybe_warnx("stat gave different size: %" PRIdOFF 1684 maybe_warnx("stat gave different size: %" PRIdOFF
1685 " != %" PRIdOFF " (leaving original)", 1685 " != %" PRIdOFF " (leaving original)",
1686 size, osb.st_size); 1686 size, osb.st_size);
1687 close(ofd); 1687 close(ofd);
1688 unlink(outfile); 1688 unlink(outfile);
1689 return -1; 1689 return -1;
1690 } 1690 }
1691 unlink_input(file, &isb); 1691 unlink_input(file, &isb);
1692#ifndef SMALL 1692#ifndef SMALL
1693 copymodes(ofd, &isb, outfile); 1693 copymodes(ofd, &isb, outfile);
1694#endif 1694#endif
1695 close(ofd); 1695 close(ofd);
1696 return size; 1696 return size;
1697 1697
1698 unexpected_EOF: 1698 unexpected_EOF:
1699 maybe_warnx("%s: unexpected end of file", file); 1699 maybe_warnx("%s: unexpected end of file", file);
1700 lose: 1700 lose:
1701 if (fd != -1) 1701 if (fd != -1)
1702 close(fd); 1702 close(fd);
1703 if (zfd != -1 && zfd != STDOUT_FILENO) 1703 if (zfd != -1 && zfd != STDOUT_FILENO)
1704 close(fd); 1704 close(fd);
1705 return -1; 1705 return -1;
1706} 1706}
1707 1707
1708#ifndef SMALL 1708#ifndef SMALL
1709static void 1709static void
1710check_siginfo(void) 1710check_siginfo(void)
1711{ 1711{
1712 static int ttyfd = -2; 1712 static int ttyfd = -2;
1713 char buf[2048]; 1713 char buf[2048];
1714 int n; 1714 int n;
1715 1715
1716 if (print_info == 0) 1716 if (print_info == 0)
1717 return; 1717 return;
1718 1718
1719 if (!infile) 1719 if (!infile)
1720 goto out; 1720 goto out;
1721 1721
1722 if (ttyfd == -2) 1722 if (ttyfd == -2)
1723 ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC); 1723 ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC);
1724 1724
1725 if (ttyfd == -1) 1725 if (ttyfd == -1)
1726 goto out; 1726 goto out;
1727 1727
1728 if (infile_total) { 1728 if (infile_total) {
1729 const double pcent = (100.0 * infile_current) / infile_total; 1729 const double pcent = (100.0 * infile_current) / infile_total;
1730 1730
1731 n = snprintf(buf, sizeof(buf), 1731 n = snprintf(buf, sizeof(buf),
1732 "%s: %s: done %ju/%ju bytes (%3.2f%%)\n", 1732 "%s: %s: done %ju/%ju bytes (%3.2f%%)\n",
1733 getprogname(), infile, (uintmax_t)infile_current, 1733 getprogname(), infile, (uintmax_t)infile_current,
1734 (uintmax_t)infile_total, pcent); 1734 (uintmax_t)infile_total, pcent);
1735 } else { 1735 } else {
1736 n = snprintf(buf, sizeof(buf), "%s: %s: done %ju bytes\n", 1736 n = snprintf(buf, sizeof(buf), "%s: %s: done %ju bytes\n",
1737 getprogname(), infile, (uintmax_t)infile_current); 1737 getprogname(), infile, (uintmax_t)infile_current);
1738 } 1738 }
1739 1739
1740 if (n <= 0) 1740 if (n <= 0)
1741 goto out; 1741 goto out;
1742 1742
1743 write(ttyfd, buf, (size_t)n); 1743 write(ttyfd, buf, (size_t)n);
1744out: 1744out:
1745 print_info = 0; 1745 print_info = 0;
1746} 1746}
1747 1747
1748static off_t 1748static off_t
1749cat_fd(unsigned char * prepend, size_t count, off_t *gsizep, int fd) 1749cat_fd(unsigned char * prepend, size_t count, off_t *gsizep, int fd)
1750{ 1750{
1751 char buf[BUFLEN]; 1751 char buf[BUFLEN];
1752 off_t in_tot; 1752 off_t in_tot;
1753 ssize_t w; 1753 ssize_t w;
1754 1754
1755 in_tot = count; 1755 in_tot = count;
1756 w = write_retry(STDOUT_FILENO, prepend, count); 1756 w = write_retry(STDOUT_FILENO, prepend, count);
1757 if (w == -1 || (size_t)w != count) { 1757 if (w == -1 || (size_t)w != count) {
1758 maybe_warn("write to stdout"); 1758 maybe_warn("write to stdout");
1759 return -1; 1759 return -1;
1760 } 1760 }
1761 for (;;) { 1761 for (;;) {
1762 ssize_t rv; 1762 ssize_t rv;
1763 1763
1764 rv = read(fd, buf, sizeof buf); 1764 rv = read(fd, buf, sizeof buf);
1765 if (rv == 0) 1765 if (rv == 0)
1766 break; 1766 break;
1767 if (rv < 0) { 1767 if (rv < 0) {
1768 maybe_warn("read from fd %d", fd); 1768 maybe_warn("read from fd %d", fd);
1769 break; 1769 break;
1770 } 1770 }
1771 infile_newdata(rv); 1771 infile_newdata(rv);
1772 1772
1773 if (write_retry(STDOUT_FILENO, buf, rv) != rv) { 1773 if (write_retry(STDOUT_FILENO, buf, rv) != rv) {
1774 maybe_warn("write to stdout"); 1774 maybe_warn("write to stdout");
1775 break; 1775 break;
1776 } 1776 }
1777 in_tot += rv; 1777 in_tot += rv;
1778 } 1778 }
1779 1779
1780 if (gsizep) 1780 if (gsizep)
1781 *gsizep = in_tot; 1781 *gsizep = in_tot;
1782 return (in_tot); 1782 return (in_tot);
1783} 1783}
1784#endif 1784#endif
1785 1785
1786static void 1786static void
1787handle_stdin(void) 1787handle_stdin(void)
1788{ 1788{
1789 struct stat isb; 1789 struct stat isb;
1790 unsigned char header1[4]; 1790 unsigned char fourbytes[4];
1791 size_t in_size; 1791 size_t in_size;
1792 off_t usize, gsize; 1792 off_t usize, gsize;
1793 enum filetype method; 1793 enum filetype method;
1794 ssize_t bytes_read; 1794 ssize_t bytes_read;
1795#ifndef NO_COMPRESS_SUPPORT 1795#ifndef NO_COMPRESS_SUPPORT
1796 FILE *in; 1796 FILE *in;
1797#endif 1797#endif
1798 1798
1799#ifndef SMALL 1799#ifndef SMALL
1800 if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) { 1800 if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) {
1801 maybe_warnx("standard input is a terminal -- ignoring"); 1801 maybe_warnx("standard input is a terminal -- ignoring");
1802 goto out; 1802 goto out;
1803 } 1803 }
1804#endif 1804#endif
1805 1805
1806 if (fstat(STDIN_FILENO, &isb) < 0) { 1806 if (fstat(STDIN_FILENO, &isb) < 0) {
1807 maybe_warn("fstat"); 1807 maybe_warn("fstat");
1808 goto out; 1808 goto out;
1809 } 1809 }
1810 if (S_ISREG(isb.st_mode)) 1810 if (S_ISREG(isb.st_mode))
1811 in_size = isb.st_size; 1811 in_size = isb.st_size;
1812 else 1812 else
1813 in_size = 0; 1813 in_size = 0;
1814 infile_set("(stdin)", in_size); 1814 infile_set("(stdin)", in_size);
1815 1815
1816 if (lflag) { 1816 if (lflag) {
1817 print_list(STDIN_FILENO, in_size, infile, isb.st_mtime); 1817 print_list(STDIN_FILENO, in_size, infile, isb.st_mtime);
1818 goto out; 1818 goto out;
1819 } 1819 }
1820 1820
1821 bytes_read = read_retry(STDIN_FILENO, header1, sizeof header1); 1821 bytes_read = read_retry(STDIN_FILENO, fourbytes, sizeof fourbytes);
1822 if (bytes_read == -1) { 1822 if (bytes_read == -1) {
1823 maybe_warn("can't read stdin"); 1823 maybe_warn("can't read stdin");
1824 goto out; 1824 goto out;
1825 } else if (bytes_read != sizeof(header1)) { 1825 } else if (bytes_read != sizeof(fourbytes)) {
1826 maybe_warnx("(stdin): unexpected end of file"); 1826 maybe_warnx("(stdin): unexpected end of file");
1827 goto out; 1827 goto out;
1828 } 1828 }
1829 1829
1830 method = file_gettype(header1); 1830 method = file_gettype(fourbytes);
1831 switch (method) { 1831 switch (method) {
1832 default: 1832 default:
1833#ifndef SMALL 1833#ifndef SMALL
1834 if (fflag == 0) { 1834 if (fflag == 0) {
1835 maybe_warnx("unknown compression format"); 1835 maybe_warnx("unknown compression format");
1836 goto out; 1836 goto out;
1837 } 1837 }
1838 usize = cat_fd(header1, sizeof header1, &gsize, STDIN_FILENO); 1838 usize = cat_fd(fourbytes, sizeof fourbytes, &gsize, STDIN_FILENO);
1839 break; 1839 break;
1840#endif 1840#endif
1841 case FT_GZIP: 1841 case FT_GZIP:
1842 usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO, 1842 usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO,
1843 (char *)header1, sizeof header1, &gsize, "(stdin)"); 1843 (char *)fourbytes, sizeof fourbytes, &gsize, "(stdin)");
1844 break; 1844 break;
1845#ifndef NO_BZIP2_SUPPORT 1845#ifndef NO_BZIP2_SUPPORT
1846 case FT_BZIP2: 1846 case FT_BZIP2:
1847 usize = unbzip2(STDIN_FILENO, STDOUT_FILENO, 1847 usize = unbzip2(STDIN_FILENO, STDOUT_FILENO,
1848 (char *)header1, sizeof header1, &gsize); 1848 (char *)fourbytes, sizeof fourbytes, &gsize);
1849 break; 1849 break;
1850#endif 1850#endif
1851#ifndef NO_COMPRESS_SUPPORT 1851#ifndef NO_COMPRESS_SUPPORT
1852 case FT_Z: 1852 case FT_Z:
1853 if ((in = zdopen(STDIN_FILENO)) == NULL) { 1853 if ((in = zdopen(STDIN_FILENO)) == NULL) {
1854 maybe_warnx("zopen of stdin"); 1854 maybe_warnx("zopen of stdin");
1855 goto out; 1855 goto out;
1856 } 1856 }
1857 1857
1858 usize = zuncompress(in, stdout, (char *)header1, 1858 usize = zuncompress(in, stdout, (char *)fourbytes,
1859 sizeof header1, &gsize); 1859 sizeof fourbytes, &gsize);
1860 fclose(in); 1860 fclose(in);
1861 break; 1861 break;
1862#endif 1862#endif
1863#ifndef NO_PACK_SUPPORT 1863#ifndef NO_PACK_SUPPORT
1864 case FT_PACK: 1864 case FT_PACK:
1865 usize = unpack(STDIN_FILENO, STDOUT_FILENO, 1865 usize = unpack(STDIN_FILENO, STDOUT_FILENO,
1866 (char *)header1, sizeof header1, &gsize); 1866 (char *)fourbytes, sizeof fourbytes, &gsize);
1867 break; 1867 break;
1868#endif 1868#endif
1869#ifndef NO_XZ_SUPPORT 1869#ifndef NO_XZ_SUPPORT
1870 case FT_XZ: 1870 case FT_XZ:
1871 usize = unxz(STDIN_FILENO, STDOUT_FILENO, 1871 usize = unxz(STDIN_FILENO, STDOUT_FILENO,
1872 (char *)header1, sizeof header1, &gsize); 1872 (char *)fourbytes, sizeof fourbytes, &gsize);
1873 break; 1873 break;
1874#endif 1874#endif
1875#ifndef NO_LZ_SUPPORT 1875#ifndef NO_LZ_SUPPORT
1876 case FT_LZ: 1876 case FT_LZ:
1877 usize = unlz(STDIN_FILENO, STDOUT_FILENO, 1877 usize = unlz(STDIN_FILENO, STDOUT_FILENO,
1878 (char *)header1, sizeof header1, &gsize); 1878 (char *)fourbytes, sizeof fourbytes, &gsize);
1879 break; 1879 break;
1880#endif 1880#endif
1881 } 1881 }
1882 1882
1883#ifndef SMALL 1883#ifndef SMALL
1884 if (vflag && !tflag && usize != -1 && gsize != -1) 1884 if (vflag && !tflag && usize != -1 && gsize != -1)
1885 print_verbage(NULL, NULL, usize, gsize); 1885 print_verbage(NULL, NULL, usize, gsize);
1886 if (vflag && tflag) 1886 if (vflag && tflag)
1887 print_test("(stdin)", usize != -1); 1887 print_test("(stdin)", usize != -1);
1888#else 1888#else
1889 (void)&usize; 1889 (void)&usize;
1890#endif 1890#endif
1891 1891
1892out: 1892out:
1893 infile_clear(); 1893 infile_clear();
1894} 1894}
1895 1895
1896static void 1896static void
1897handle_stdout(void) 1897handle_stdout(void)
1898{ 1898{
1899 off_t gsize; 1899 off_t gsize;
1900#ifndef SMALL 1900#ifndef SMALL
1901 off_t usize; 1901 off_t usize;
1902 struct stat sb; 1902 struct stat sb;
1903 time_t systime; 1903 time_t systime;
1904 uint32_t mtime; 1904 uint32_t mtime;
1905 int ret; 1905 int ret;
1906 1906
1907 infile_set("<stdout>", 0); 1907 infile_set("<stdout>", 0);
1908 1908
1909 if (fflag == 0 && isatty(STDOUT_FILENO)) { 1909 if (fflag == 0 && isatty(STDOUT_FILENO)) {
1910 maybe_warnx("standard output is a terminal -- ignoring"); 1910 maybe_warnx("standard output is a terminal -- ignoring");
1911 return; 1911 return;
1912 } 1912 }
1913 1913
1914 /* If stdin is a file use its mtime, otherwise use current time */ 1914 /* If stdin is a file use its mtime, otherwise use current time */
1915 ret = fstat(STDIN_FILENO, &sb); 1915 ret = fstat(STDIN_FILENO, &sb);
1916 if (ret < 0) { 1916 if (ret < 0) {
1917 maybe_warn("Can't stat stdin"); 1917 maybe_warn("Can't stat stdin");
1918 return; 1918 return;
1919 } 1919 }
1920 1920
1921 if (S_ISREG(sb.st_mode)) { 1921 if (S_ISREG(sb.st_mode)) {
1922 infile_set("<stdout>", sb.st_size); 1922 infile_set("<stdout>", sb.st_size);
1923 mtime = (uint32_t)sb.st_mtime; 1923 mtime = (uint32_t)sb.st_mtime;
1924 } else { 1924 } else {
1925 systime = time(NULL); 1925 systime = time(NULL);
1926 if (systime == -1) { 1926 if (systime == -1) {
1927 maybe_warn("time"); 1927 maybe_warn("time");
1928 return; 1928 return;
1929 } 1929 }
1930 mtime = (uint32_t)systime; 1930 mtime = (uint32_t)systime;
1931 } 1931 }
1932  1932
1933 usize = 1933 usize =
1934#endif 1934#endif
1935 gz_compress(STDIN_FILENO, STDOUT_FILENO, &gsize, "", mtime); 1935 gz_compress(STDIN_FILENO, STDOUT_FILENO, &gsize, "", mtime);
1936#ifndef SMALL 1936#ifndef SMALL
1937 if (vflag && !tflag && usize != -1 && gsize != -1) 1937 if (vflag && !tflag && usize != -1 && gsize != -1)
1938 print_verbage(NULL, NULL, usize, gsize); 1938 print_verbage(NULL, NULL, usize, gsize);
1939#endif 1939#endif
1940} 1940}
1941 1941
1942/* do what is asked for, for the path name */ 1942/* do what is asked for, for the path name */
1943static void 1943static void
1944handle_pathname(char *path) 1944handle_pathname(char *path)
1945{ 1945{
1946 char *opath = path, *s = NULL; 1946 char *opath = path, *s = NULL;
1947 ssize_t len; 1947 ssize_t len;
1948 int slen; 1948 int slen;
1949 struct stat sb; 1949 struct stat sb;
1950 1950
1951 /* check for stdout/stdin */ 1951 /* check for stdout/stdin */
1952 if (path[0] == '-' && path[1] == '\0') { 1952 if (path[0] == '-' && path[1] == '\0') {
1953 if (dflag) 1953 if (dflag)
1954 handle_stdin(); 1954 handle_stdin();
1955 else 1955 else
1956 handle_stdout(); 1956 handle_stdout();
1957 return; 1957 return;
1958 } 1958 }
1959 1959
1960retry: 1960retry:
1961 if (stat(path, &sb) != 0) { 1961 if (stat(path, &sb) != 0) {
1962 /* lets try <path>.gz if we're decompressing */ 1962 /* lets try <path>.gz if we're decompressing */
1963 if (dflag && s == NULL && errno == ENOENT) { 1963 if (dflag && s == NULL && errno == ENOENT) {
1964 len = strlen(path); 1964 len = strlen(path);
1965 slen = suffixes[0].ziplen; 1965 slen = suffixes[0].ziplen;
1966 s = malloc(len + slen + 1); 1966 s = malloc(len + slen + 1);
1967 if (s == NULL) 1967 if (s == NULL)
1968 maybe_err("malloc"); 1968 maybe_err("malloc");
1969 memcpy(s, path, len); 1969 memcpy(s, path, len);
1970 memcpy(s + len, suffixes[0].zipped, slen + 1); 1970 memcpy(s + len, suffixes[0].zipped, slen + 1);
1971 path = s; 1971 path = s;
1972 goto retry; 1972 goto retry;
1973 } 1973 }
1974 maybe_warn("can't stat: %s", opath); 1974 maybe_warn("can't stat: %s", opath);
1975 goto out; 1975 goto out;
1976 } 1976 }
1977 1977
1978 if (S_ISDIR(sb.st_mode)) { 1978 if (S_ISDIR(sb.st_mode)) {
1979#ifndef SMALL 1979#ifndef SMALL
1980 if (rflag) 1980 if (rflag)
1981 handle_dir(path); 1981 handle_dir(path);
1982 else 1982 else
1983#endif 1983#endif
1984 maybe_warnx("%s is a directory", path); 1984 maybe_warnx("%s is a directory", path);
1985 goto out; 1985 goto out;
1986 } 1986 }
1987 1987
1988 if (S_ISREG(sb.st_mode)) 1988 if (S_ISREG(sb.st_mode))
1989 handle_file(path, &sb); 1989 handle_file(path, &sb);
1990 else 1990 else
1991 maybe_warnx("%s is not a regular file", path); 1991 maybe_warnx("%s is not a regular file", path);
1992 1992
1993out: 1993out:
1994 if (s) 1994 if (s)
1995 free(s); 1995 free(s);
1996} 1996}
1997 1997
1998/* compress/decompress a file */ 1998/* compress/decompress a file */
1999static void 1999static void
2000handle_file(char *file, struct stat *sbp) 2000handle_file(char *file, struct stat *sbp)
2001{ 2001{
2002 off_t usize, gsize; 2002 off_t usize, gsize;
2003 char outfile[PATH_MAX]; 2003 char outfile[PATH_MAX];
2004 2004
2005 infile_set(file, sbp->st_size); 2005 infile_set(file, sbp->st_size);
2006 if (dflag) { 2006 if (dflag) {
2007 usize = file_uncompress(file, outfile, sizeof(outfile)); 2007 usize = file_uncompress(file, outfile, sizeof(outfile));
2008#ifndef SMALL 2008#ifndef SMALL
2009 if (vflag && tflag) 2009 if (vflag && tflag)
2010 print_test(file, usize != -1); 2010 print_test(file, usize != -1);
2011#endif 2011#endif
2012 if (usize == -1) 2012 if (usize == -1)
2013 return; 2013 return;
2014 gsize = sbp->st_size; 2014 gsize = sbp->st_size;
2015 } else { 2015 } else {
2016 gsize = file_compress(file, outfile, sizeof(outfile)); 2016 gsize = file_compress(file, outfile, sizeof(outfile));
2017 if (gsize == -1) 2017 if (gsize == -1)
2018 return; 2018 return;
2019 usize = sbp->st_size; 2019 usize = sbp->st_size;
2020 } 2020 }
2021 infile_clear(); 2021 infile_clear();
2022 2022
2023#ifndef SMALL 2023#ifndef SMALL
2024 if (vflag && !tflag) 2024 if (vflag && !tflag)
2025 print_verbage(file, (cflag) ? NULL : outfile, usize, gsize); 2025 print_verbage(file, (cflag) ? NULL : outfile, usize, gsize);
2026#endif 2026#endif
2027} 2027}
2028 2028
2029#ifndef SMALL 2029#ifndef SMALL
2030/* this is used with -r to recursively descend directories */ 2030/* this is used with -r to recursively descend directories */
2031static void 2031static void
2032handle_dir(char *dir) 2032handle_dir(char *dir)
2033{ 2033{
2034 char *path_argv[2]; 2034 char *path_argv[2];
2035 FTS *fts; 2035 FTS *fts;
2036 FTSENT *entry; 2036 FTSENT *entry;
2037 2037
2038 path_argv[0] = dir; 2038 path_argv[0] = dir;
2039 path_argv[1] = 0; 2039 path_argv[1] = 0;
2040 fts = fts_open(path_argv, FTS_PHYSICAL, NULL); 2040 fts = fts_open(path_argv, FTS_PHYSICAL, NULL);
2041 if (fts == NULL) { 2041 if (fts == NULL) {
2042 warn("couldn't fts_open %s", dir); 2042 warn("couldn't fts_open %s", dir);
2043 return; 2043 return;
2044 } 2044 }
2045 2045
2046 while ((entry = fts_read(fts))) { 2046 while ((entry = fts_read(fts))) {
2047 switch(entry->fts_info) { 2047 switch(entry->fts_info) {
2048 case FTS_D: 2048 case FTS_D:
2049 case FTS_DP: 2049 case FTS_DP:
2050 continue; 2050 continue;
2051 2051
2052 case FTS_DNR: 2052 case FTS_DNR:
2053 case FTS_ERR: 2053 case FTS_ERR:
2054 case FTS_NS: 2054 case FTS_NS:
2055 maybe_warn("%s", entry->fts_path); 2055 maybe_warn("%s", entry->fts_path);
2056 continue; 2056 continue;
2057 case FTS_F: 2057 case FTS_F:
2058 handle_file(entry->fts_name, entry->fts_statp); 2058 handle_file(entry->fts_name, entry->fts_statp);
2059 } 2059 }
2060 } 2060 }
2061 (void)fts_close(fts); 2061 (void)fts_close(fts);
2062} 2062}
2063#endif 2063#endif
2064 2064
2065/* print a ratio - size reduction as a fraction of uncompressed size */ 2065/* print a ratio - size reduction as a fraction of uncompressed size */
2066static void 2066static void
2067print_ratio(off_t in, off_t out, FILE *where) 2067print_ratio(off_t in, off_t out, FILE *where)
2068{ 2068{
2069 int percent10; /* 10 * percent */ 2069 int percent10; /* 10 * percent */
2070 off_t diff; 2070 off_t diff;
2071 char buff[8]; 2071 char buff[8];
2072 int len; 2072 int len;
2073 2073
2074 diff = in - out/2; 2074 diff = in - out/2;
2075 if (in == 0 && out == 0) 2075 if (in == 0 && out == 0)
2076 percent10 = 0; 2076 percent10 = 0;
2077 else if (diff < 0) 2077 else if (diff < 0)
2078 /* 2078 /*
2079 * Output is more than double size of input! print -99.9% 2079 * Output is more than double size of input! print -99.9%
2080 * Quite possibly we've failed to get the original size. 2080 * Quite possibly we've failed to get the original size.
2081 */ 2081 */
2082 percent10 = -999; 2082 percent10 = -999;
2083 else { 2083 else {
2084 /* 2084 /*
2085 * We only need 12 bits of result from the final division, 2085 * We only need 12 bits of result from the final division,
2086 * so reduce the values until a 32bit division will suffice. 2086 * so reduce the values until a 32bit division will suffice.
2087 */ 2087 */
2088 while (in > 0x100000) { 2088 while (in > 0x100000) {
2089 diff >>= 1; 2089 diff >>= 1;
2090 in >>= 1; 2090 in >>= 1;
2091 } 2091 }
2092 if (in != 0) 2092 if (in != 0)
2093 percent10 = ((u_int)diff * 2000) / (u_int)in - 1000; 2093 percent10 = ((u_int)diff * 2000) / (u_int)in - 1000;
2094 else 2094 else
2095 percent10 = 0; 2095 percent10 = 0;
2096 } 2096 }
2097 2097
2098 len = snprintf(buff, sizeof buff, "%2.2d.", percent10); 2098 len = snprintf(buff, sizeof buff, "%2.2d.", percent10);
2099 /* Move the '.' to before the last digit */ 2099 /* Move the '.' to before the last digit */
2100 buff[len - 1] = buff[len - 2]; 2100 buff[len - 1] = buff[len - 2];
2101 buff[len - 2] = '.'; 2101 buff[len - 2] = '.';
2102 fprintf(where, "%5s%%", buff); 2102 fprintf(where, "%5s%%", buff);
2103} 2103}
2104 2104
2105#ifndef SMALL 2105#ifndef SMALL
2106/* print compression statistics, and the new name (if there is one!) */ 2106/* print compression statistics, and the new name (if there is one!) */
2107static void 2107static void
2108print_verbage(const char *file, const char *nfile, off_t usize, off_t gsize) 2108print_verbage(const char *file, const char *nfile, off_t usize, off_t gsize)
2109{ 2109{
2110 if (file) 2110 if (file)
2111 fprintf(stderr, "%s:%s ", file, 2111 fprintf(stderr, "%s:%s ", file,
2112 strlen(file) < 7 ? "\t\t" : "\t"); 2112 strlen(file) < 7 ? "\t\t" : "\t");
2113 print_ratio(usize, gsize, stderr); 2113 print_ratio(usize, gsize, stderr);
2114 if (nfile) 2114 if (nfile)
2115 fprintf(stderr, " -- replaced with %s", nfile); 2115 fprintf(stderr, " -- replaced with %s", nfile);
2116 fprintf(stderr, "\n"); 2116 fprintf(stderr, "\n");
2117 fflush(stderr); 2117 fflush(stderr);
2118} 2118}
2119 2119
2120/* print test results */ 2120/* print test results */
2121static void 2121static void
2122print_test(const char *file, int ok) 2122print_test(const char *file, int ok)
2123{ 2123{
2124 2124
2125 if (exit_value == 0 && ok == 0) 2125 if (exit_value == 0 && ok == 0)
2126 exit_value = 1; 2126 exit_value = 1;
2127 fprintf(stderr, "%s:%s %s\n", file, 2127 fprintf(stderr, "%s:%s %s\n", file,
2128 strlen(file) < 7 ? "\t\t" : "\t", ok ? "OK" : "NOT OK"); 2128 strlen(file) < 7 ? "\t\t" : "\t", ok ? "OK" : "NOT OK");
2129 fflush(stderr); 2129 fflush(stderr);
2130} 2130}
2131#endif 2131#endif
2132 2132
2133/* print a file's info ala --list */ 2133/* print a file's info ala --list */
2134/* eg: 2134/* eg:
2135 compressed uncompressed ratio uncompressed_name 2135 compressed uncompressed ratio uncompressed_name
2136 354841 1679360 78.8% /usr/pkgsrc/distfiles/libglade-2.0.1.tar 2136 354841 1679360 78.8% /usr/pkgsrc/distfiles/libglade-2.0.1.tar
2137*/ 2137*/
2138static void 2138static void
2139print_list(int fd, off_t out, const char *outfile, time_t ts) 2139print_list(int fd, off_t out, const char *outfile, time_t ts)
2140{ 2140{
2141 static int first = 1; 2141 static int first = 1;
2142#ifndef SMALL 2142#ifndef SMALL
2143 static off_t in_tot, out_tot; 2143 static off_t in_tot, out_tot;
2144 uint32_t crc = 0; 2144 uint32_t crc = 0;
2145#endif 2145#endif
2146 off_t in = 0, rv; 2146 off_t in = 0, rv;
2147 2147
2148 if (first) { 2148 if (first) {
2149#ifndef SMALL 2149#ifndef SMALL
2150 if (vflag) 2150 if (vflag)
2151 printf("method crc date time "); 2151 printf("method crc date time ");
2152#endif 2152#endif
2153 if (qflag == 0) 2153 if (qflag == 0)
2154 printf(" compressed uncompressed " 2154 printf(" compressed uncompressed "
2155 "ratio uncompressed_name\n"); 2155 "ratio uncompressed_name\n");
2156 } 2156 }
2157 first = 0; 2157 first = 0;
2158 2158
2159 /* print totals? */ 2159 /* print totals? */
2160#ifndef SMALL 2160#ifndef SMALL
2161 if (fd == -1) { 2161 if (fd == -1) {
2162 in = in_tot; 2162 in = in_tot;
2163 out = out_tot; 2163 out = out_tot;
2164 } else 2164 } else
2165#endif 2165#endif
2166 { 2166 {
2167 /* read the last 4 bytes - this is the uncompressed size */ 2167 /* read the last 4 bytes - this is the uncompressed size */
2168 rv = lseek(fd, (off_t)(-8), SEEK_END); 2168 rv = lseek(fd, (off_t)(-8), SEEK_END);
2169 if (rv != -1) { 2169 if (rv != -1) {
2170 unsigned char buf[8]; 2170 unsigned char buf[8];
2171 uint32_t usize; 2171 uint32_t usize;
2172 2172
2173 rv = read(fd, (char *)buf, sizeof(buf)); 2173 rv = read(fd, (char *)buf, sizeof(buf));
2174 if (rv == -1) 2174 if (rv == -1)
2175 maybe_warn("read of uncompressed size"); 2175 maybe_warn("read of uncompressed size");
2176 else if (rv != sizeof(buf)) 2176 else if (rv != sizeof(buf))
2177 maybe_warnx("read of uncompressed size"); 2177 maybe_warnx("read of uncompressed size");
2178 2178
2179 else { 2179 else {
2180 usize = buf[4]; 2180 usize = buf[4];
2181 usize |= (unsigned int)buf[5] << 8; 2181 usize |= (unsigned int)buf[5] << 8;
2182 usize |= (unsigned int)buf[6] << 16; 2182 usize |= (unsigned int)buf[6] << 16;
2183 usize |= (unsigned int)buf[7] << 24; 2183 usize |= (unsigned int)buf[7] << 24;
2184 in = (off_t)usize; 2184 in = (off_t)usize;
2185#ifndef SMALL 2185#ifndef SMALL
2186 crc = buf[0]; 2186 crc = buf[0];
2187 crc |= (unsigned int)buf[1] << 8; 2187 crc |= (unsigned int)buf[1] << 8;
2188 crc |= (unsigned int)buf[2] << 16; 2188 crc |= (unsigned int)buf[2] << 16;
2189 crc |= (unsigned int)buf[3] << 24; 2189 crc |= (unsigned int)buf[3] << 24;
2190#endif 2190#endif
2191 } 2191 }
2192 } 2192 }
2193 } 2193 }
2194 2194
2195#ifndef SMALL 2195#ifndef SMALL
2196 if (vflag && fd == -1) 2196 if (vflag && fd == -1)
2197 printf(" "); 2197 printf(" ");
2198 else if (vflag) { 2198 else if (vflag) {
2199 char *date = ctime(&ts); 2199 char *date = ctime(&ts);
2200 2200
2201 /* skip the day, 1/100th second, and year */ 2201 /* skip the day, 1/100th second, and year */
2202 date += 4; 2202 date += 4;
2203 date[12] = 0; 2203 date[12] = 0;
2204 printf("%5s %08x %11s ", "defla"/*XXX*/, crc, date); 2204 printf("%5s %08x %11s ", "defla"/*XXX*/, crc, date);
2205 } 2205 }
2206 in_tot += in; 2206 in_tot += in;
2207 out_tot += out; 2207 out_tot += out;
2208#endif 2208#endif
2209 print_list_out(out, in, outfile); 2209 print_list_out(out, in, outfile);
2210} 2210}
2211 2211
2212static void 2212static void
2213print_list_out(off_t out, off_t in, const char *outfile) 2213print_list_out(off_t out, off_t in, const char *outfile)
2214{ 2214{
2215 printf("%12llu %12llu ", (unsigned long long)out, (unsigned long long)in); 2215 printf("%12llu %12llu ", (unsigned long long)out, (unsigned long long)in);
2216 print_ratio(in, out, stdout); 2216 print_ratio(in, out, stdout);
2217 printf(" %s\n", outfile); 2217 printf(" %s\n", outfile);
2218} 2218}
2219 2219
2220/* display the usage of NetBSD gzip */ 2220/* display the usage of NetBSD gzip */
2221static void 2221static void
2222usage(void) 2222usage(void)
2223{ 2223{
2224 2224
2225 fprintf(stderr, "%s\n", gzip_version); 2225 fprintf(stderr, "%s\n", gzip_version);
2226 fprintf(stderr, 2226 fprintf(stderr,
2227 "usage: %s [-" OPT_LIST "] [<file> [<file> ...]]\n" 2227 "usage: %s [-" OPT_LIST "] [<file> [<file> ...]]\n"
2228#ifndef SMALL 2228#ifndef SMALL
2229 " -1 --fast fastest (worst) compression\n" 2229 " -1 --fast fastest (worst) compression\n"
2230 " -2 .. -8 set compression level\n" 2230 " -2 .. -8 set compression level\n"
2231 " -9 --best best (slowest) compression\n" 2231 " -9 --best best (slowest) compression\n"
2232 " -c --stdout write to stdout, keep original files\n" 2232 " -c --stdout write to stdout, keep original files\n"
2233 " --to-stdout\n" 2233 " --to-stdout\n"
2234 " -d --decompress uncompress files\n" 2234 " -d --decompress uncompress files\n"
2235 " --uncompress\n" 2235 " --uncompress\n"
2236 " -f --force force overwriting & compress links\n" 2236 " -f --force force overwriting & compress links\n"
2237 " -h --help display this help\n" 2237 " -h --help display this help\n"
2238 " -k --keep don't delete input files during operation\n" 2238 " -k --keep don't delete input files during operation\n"
2239 " -l --list list compressed file contents\n" 2239 " -l --list list compressed file contents\n"
2240 " -N --name save or restore original file name and time stamp\n" 2240 " -N --name save or restore original file name and time stamp\n"
2241 " -n --no-name don't save original file name or time stamp\n" 2241 " -n --no-name don't save original file name or time stamp\n"
2242 " -q --quiet output no warnings\n" 2242 " -q --quiet output no warnings\n"
2243 " -r --recursive recursively compress files in directories\n" 2243 " -r --recursive recursively compress files in directories\n"
2244 " -S .suf use suffix .suf instead of .gz\n" 2244 " -S .suf use suffix .suf instead of .gz\n"
2245 " --suffix .suf\n" 2245 " --suffix .suf\n"
2246 " -t --test test compressed file\n" 2246 " -t --test test compressed file\n"
2247 " -V --version display program version\n" 2247 " -V --version display program version\n"
2248 " -v --verbose print extra statistics\n", 2248 " -v --verbose print extra statistics\n",
2249#else 2249#else
2250 , 2250 ,
2251#endif 2251#endif
2252 getprogname()); 2252 getprogname());
2253 exit(0); 2253 exit(0);
2254} 2254}
2255 2255
2256/* display the version of NetBSD gzip */ 2256/* display the version of NetBSD gzip */
2257static void 2257static void
2258display_version(void) 2258display_version(void)
2259{ 2259{
2260 2260
2261 fprintf(stderr, "%s\n", gzip_version); 2261 fprintf(stderr, "%s\n", gzip_version);
2262 exit(0); 2262 exit(0);
2263} 2263}
2264 2264
2265#ifndef NO_BZIP2_SUPPORT 2265#ifndef NO_BZIP2_SUPPORT
2266#include "unbzip2.c" 2266#include "unbzip2.c"
2267#endif 2267#endif
2268#ifndef NO_COMPRESS_SUPPORT 2268#ifndef NO_COMPRESS_SUPPORT
2269#include "zuncompress.c" 2269#include "zuncompress.c"
2270#endif 2270#endif
2271#ifndef NO_PACK_SUPPORT 2271#ifndef NO_PACK_SUPPORT
2272#include "unpack.c" 2272#include "unpack.c"
2273#endif 2273#endif
2274#ifndef NO_XZ_SUPPORT 2274#ifndef NO_XZ_SUPPORT
2275#include "unxz.c" 2275#include "unxz.c"
2276#endif 2276#endif
2277#ifndef NO_LZ_SUPPORT 2277#ifndef NO_LZ_SUPPORT
2278#include "unlz.c" 2278#include "unlz.c"
2279#endif 2279#endif
2280 2280
2281static ssize_t 2281static ssize_t
2282read_retry(int fd, void *buf, size_t sz) 2282read_retry(int fd, void *buf, size_t sz)
2283{ 2283{
2284 char *cp = buf; 2284 char *cp = buf;
2285 size_t left = MIN(sz, (size_t) SSIZE_MAX); 2285 size_t left = MIN(sz, (size_t) SSIZE_MAX);
2286 2286
2287 while (left > 0) { 2287 while (left > 0) {
2288 ssize_t ret; 2288 ssize_t ret;
2289 2289
2290 ret = read(fd, cp, left); 2290 ret = read(fd, cp, left);
2291 if (ret == -1) { 2291 if (ret == -1) {
2292 return ret; 2292 return ret;
2293 } else if (ret == 0) { 2293 } else if (ret == 0) {
2294 break; /* EOF */ 2294 break; /* EOF */
2295 } 2295 }
2296 cp += ret; 2296 cp += ret;
2297 left -= ret; 2297 left -= ret;
2298 } 2298 }
2299 2299
2300 return sz - left; 2300 return sz - left;
2301} 2301}
2302 2302
2303static ssize_t 2303static ssize_t
2304write_retry(int fd, const void *buf, size_t sz) 2304write_retry(int fd, const void *buf, size_t sz)
2305{ 2305{
2306 const char *cp = buf; 2306 const char *cp = buf;
2307 size_t left = MIN(sz, (size_t) SSIZE_MAX); 2307 size_t left = MIN(sz, (size_t) SSIZE_MAX);
2308 2308
2309 while (left > 0) { 2309 while (left > 0) {
2310 ssize_t ret; 2310 ssize_t ret;
2311 2311
2312 ret = write(fd, cp, left); 2312 ret = write(fd, cp, left);
2313 if (ret == -1) { 2313 if (ret == -1) {
2314 return ret; 2314 return ret;
2315 } else if (ret == 0) { 2315 } else if (ret == 0) {
2316 abort(); /* Can't happen */ 2316 abort(); /* Can't happen */
2317 } 2317 }
2318 cp += ret; 2318 cp += ret;
2319 left -= ret; 2319 left -= ret;
2320 } 2320 }
2321 2321
2322 return sz - left; 2322 return sz - left;
2323} 2323}

cvs diff -r1.7 -r1.8 src/usr.bin/gzip/unlz.c (switch to unified diff)

--- src/usr.bin/gzip/unlz.c 2021/09/10 21:52:17 1.7
+++ src/usr.bin/gzip/unlz.c 2023/06/10 04:45:25 1.8
@@ -1,644 +1,642 @@ @@ -1,644 +1,642 @@
1/* $NetBSD: unlz.c,v 1.7 2021/09/10 21:52:17 rillig Exp $ */ 1/* $NetBSD: unlz.c,v 1.8 2023/06/10 04:45:25 simonb Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2018 The NetBSD Foundation, Inc. 4 * Copyright (c) 2018 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas. 8 * by Christos Zoulas.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32/* Lzd - Educational decompressor for the lzip format 32/* Lzd - Educational decompressor for the lzip format
33 Copyright (C) 2013-2018 Antonio Diaz Diaz. 33 Copyright (C) 2013-2018 Antonio Diaz Diaz.
34 34
35 This program is free software. Redistribution and use in source and 35 This program is free software. Redistribution and use in source and
36 binary forms, with or without modification, are permitted provided 36 binary forms, with or without modification, are permitted provided
37 that the following conditions are met: 37 that the following conditions are met:
38 38
39 1. Redistributions of source code must retain the above copyright 39 1. Redistributions of source code must retain the above copyright
40 notice, this list of conditions and the following disclaimer. 40 notice, this list of conditions and the following disclaimer.
41 41
42 2. Redistributions in binary form must reproduce the above copyright 42 2. Redistributions in binary form must reproduce the above copyright
43 notice, this list of conditions and the following disclaimer in the 43 notice, this list of conditions and the following disclaimer in the
44 documentation and/or other materials provided with the distribution. 44 documentation and/or other materials provided with the distribution.
45 45
46 This program is distributed in the hope that it will be useful, 46 This program is distributed in the hope that it will be useful,
47 but WITHOUT ANY WARRANTY; without even the implied warranty of 47 but WITHOUT ANY WARRANTY; without even the implied warranty of
48 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 48 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
49*/ 49*/
50 50
51#include <sys/param.h> 51#include <sys/param.h>
52#include <stdio.h> 52#include <stdio.h>
53#include <string.h> 53#include <string.h>
54#include <stdlib.h> 54#include <stdlib.h>
55#include <stdint.h> 55#include <stdint.h>
56#include <stdbool.h> 56#include <stdbool.h>
57#include <errno.h> 57#include <errno.h>
58#include <unistd.h> 58#include <unistd.h>
59 59
60#define LZ_STATES 12 60#define LZ_STATES 12
61 61
62#define LITERAL_CONTEXT_BITS 3 62#define LITERAL_CONTEXT_BITS 3
63#define POS_STATE_BITS 2 63#define POS_STATE_BITS 2
64#define POS_STATES (1 << POS_STATE_BITS) 64#define POS_STATES (1 << POS_STATE_BITS)
65#define POS_STATE_MASK (POS_STATES - 1) 65#define POS_STATE_MASK (POS_STATES - 1)
66 66
67#define STATES 4 67#define STATES 4
68#define DIS_SLOT_BITS 6 68#define DIS_SLOT_BITS 6
69 69
70#define DIS_MODEL_START 4 70#define DIS_MODEL_START 4
71#define DIS_MODEL_END 14 71#define DIS_MODEL_END 14
72 72
73#define MODELED_DISTANCES (1 << (DIS_MODEL_END / 2)) 73#define MODELED_DISTANCES (1 << (DIS_MODEL_END / 2))
74#define DIS_ALIGN_BITS 4 74#define DIS_ALIGN_BITS 4
75#define DIS_ALIGN_SIZE (1 << DIS_ALIGN_BITS) 75#define DIS_ALIGN_SIZE (1 << DIS_ALIGN_BITS)
76 76
77#define LOW_BITS 3 77#define LOW_BITS 3
78#define MID_BITS 3 78#define MID_BITS 3
79#define HIGH_BITS 8 79#define HIGH_BITS 8
80 80
81#define LOW_SYMBOLS (1 << LOW_BITS) 81#define LOW_SYMBOLS (1 << LOW_BITS)
82#define MID_SYMBOLS (1 << MID_BITS) 82#define MID_SYMBOLS (1 << MID_BITS)
83#define HIGH_SYMBOLS (1 << HIGH_BITS) 83#define HIGH_SYMBOLS (1 << HIGH_BITS)
84 84
85#define MAX_SYMBOLS (LOW_SYMBOLS + MID_SYMBOLS + HIGH_SYMBOLS) 85#define MAX_SYMBOLS (LOW_SYMBOLS + MID_SYMBOLS + HIGH_SYMBOLS)
86 86
87#define MIN_MATCH_LEN 2 87#define MIN_MATCH_LEN 2
88 88
89#define BIT_MODEL_MOVE_BITS 5 89#define BIT_MODEL_MOVE_BITS 5
90#define BIT_MODEL_TOTAL_BITS 11 90#define BIT_MODEL_TOTAL_BITS 11
91#define BIT_MODEL_TOTAL (1 << BIT_MODEL_TOTAL_BITS) 91#define BIT_MODEL_TOTAL (1 << BIT_MODEL_TOTAL_BITS)
92#define BIT_MODEL_INIT (BIT_MODEL_TOTAL / 2) 92#define BIT_MODEL_INIT (BIT_MODEL_TOTAL / 2)
93 93
94static const int lz_st_next[] = { 94static const int lz_st_next[] = {
95 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5, 95 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5,
96}; 96};
97 97
98static bool 98static bool
99lz_st_is_char(int st) { 99lz_st_is_char(int st) {
100 return st < 7; 100 return st < 7;
101} 101}
102 102
103static int 103static int
104lz_st_get_char(int st) { 104lz_st_get_char(int st) {
105 return lz_st_next[st]; 105 return lz_st_next[st];
106} 106}
107 107
108static int 108static int
109lz_st_get_match(int st) { 109lz_st_get_match(int st) {
110 return st < 7 ? 7 : 10; 110 return st < 7 ? 7 : 10;
111} 111}
112 112
113static int 113static int
114lz_st_get_rep(int st) { 114lz_st_get_rep(int st) {
115 return st < 7 ? 8 : 11; 115 return st < 7 ? 8 : 11;
116} 116}
117 117
118static int 118static int
119lz_st_get_short_rep(int st) { 119lz_st_get_short_rep(int st) {
120 return st < 7 ? 9 : 11; 120 return st < 7 ? 9 : 11;
121} 121}
122 122
123struct lz_len_model { 123struct lz_len_model {
124 int choice1; 124 int choice1;
125 int choice2; 125 int choice2;
126 int bm_low[POS_STATES][LOW_SYMBOLS]; 126 int bm_low[POS_STATES][LOW_SYMBOLS];
127 int bm_mid[POS_STATES][MID_SYMBOLS]; 127 int bm_mid[POS_STATES][MID_SYMBOLS];
128 int bm_high[HIGH_SYMBOLS]; 128 int bm_high[HIGH_SYMBOLS];
129}; 129};
130 130
131static uint32_t lz_crc[256]; 131static uint32_t lz_crc[256];
132 132
133static void 133static void
134lz_crc_init(void) 134lz_crc_init(void)
135{ 135{
136 for (unsigned i = 0; i < __arraycount(lz_crc); i++) { 136 for (unsigned i = 0; i < __arraycount(lz_crc); i++) {
137 unsigned c = i; 137 unsigned c = i;
138 for (unsigned j = 0; j < 8; j++) { 138 for (unsigned j = 0; j < 8; j++) {
139 if (c & 1) 139 if (c & 1)
140 c = 0xEDB88320U ^ (c >> 1); 140 c = 0xEDB88320U ^ (c >> 1);
141 else 141 else
142 c >>= 1; 142 c >>= 1;
143 } 143 }
144 lz_crc[i] = c; 144 lz_crc[i] = c;
145 } 145 }
146} 146}
147 147
148static void 148static void
149lz_crc_update(uint32_t *crc, const uint8_t *buf, size_t len) 149lz_crc_update(uint32_t *crc, const uint8_t *buf, size_t len)
150{ 150{
151 for (size_t i = 0; i < len; i++) 151 for (size_t i = 0; i < len; i++)
152 *crc = lz_crc[(*crc ^ buf[i]) & 0xFF] ^ (*crc >> 8); 152 *crc = lz_crc[(*crc ^ buf[i]) & 0xFF] ^ (*crc >> 8);
153} 153}
154 154
155struct lz_range_decoder { 155struct lz_range_decoder {
156 FILE *fp; 156 FILE *fp;
157 uint32_t code; 157 uint32_t code;
158 uint32_t range; 158 uint32_t range;
159}; 159};
160 160
161static int 161static int
162lz_rd_create(struct lz_range_decoder *rd, FILE *fp) 162lz_rd_create(struct lz_range_decoder *rd, FILE *fp)
163{ 163{
164 rd->fp = fp; 164 rd->fp = fp;
165 rd->code = 0; 165 rd->code = 0;
166 rd->range = ~0; 166 rd->range = ~0;
167 for (int i = 0; i < 5; i++) 167 for (int i = 0; i < 5; i++)
168 rd->code = (rd->code << 8) | (uint8_t)getc(rd->fp); 168 rd->code = (rd->code << 8) | (uint8_t)getc(rd->fp);
169 return ferror(rd->fp) ? -1 : 0; 169 return ferror(rd->fp) ? -1 : 0;
170} 170}
171 171
172static unsigned 172static unsigned
173lz_rd_decode(struct lz_range_decoder *rd, int num_bits) 173lz_rd_decode(struct lz_range_decoder *rd, int num_bits)
174{ 174{
175 unsigned symbol = 0; 175 unsigned symbol = 0;
176 176
177 for (int i = num_bits; i > 0; i--) { 177 for (int i = num_bits; i > 0; i--) {
178 rd->range >>= 1; 178 rd->range >>= 1;
179 symbol <<= 1; 179 symbol <<= 1;
180 if (rd->code >= rd->range) { 180 if (rd->code >= rd->range) {
181 rd->code -= rd->range; 181 rd->code -= rd->range;
182 symbol |= 1; 182 symbol |= 1;
183 } 183 }
184 if (rd->range <= 0x00FFFFFFU) { 184 if (rd->range <= 0x00FFFFFFU) {
185 rd->range <<= 8;  185 rd->range <<= 8;
186 rd->code = (rd->code << 8) | (uint8_t)getc(rd->fp); 186 rd->code = (rd->code << 8) | (uint8_t)getc(rd->fp);
187 } 187 }
188 } 188 }
189 189
190 return symbol; 190 return symbol;
191} 191}
192 192
193static unsigned 193static unsigned
194lz_rd_decode_bit(struct lz_range_decoder *rd, int *bm) 194lz_rd_decode_bit(struct lz_range_decoder *rd, int *bm)
195{ 195{
196 unsigned symbol; 196 unsigned symbol;
197 const uint32_t bound = (rd->range >> BIT_MODEL_TOTAL_BITS) * *bm; 197 const uint32_t bound = (rd->range >> BIT_MODEL_TOTAL_BITS) * *bm;
198 198
199 if(rd->code < bound) { 199 if(rd->code < bound) {
200 rd->range = bound; 200 rd->range = bound;
201 *bm += (BIT_MODEL_TOTAL - *bm) >> BIT_MODEL_MOVE_BITS; 201 *bm += (BIT_MODEL_TOTAL - *bm) >> BIT_MODEL_MOVE_BITS;
202 symbol = 0; 202 symbol = 0;
203 } 203 }
204 else { 204 else {
205 rd->range -= bound; 205 rd->range -= bound;
206 rd->code -= bound; 206 rd->code -= bound;
207 *bm -= *bm >> BIT_MODEL_MOVE_BITS; 207 *bm -= *bm >> BIT_MODEL_MOVE_BITS;
208 symbol = 1; 208 symbol = 1;
209 } 209 }
210 210
211 if (rd->range <= 0x00FFFFFFU) { 211 if (rd->range <= 0x00FFFFFFU) {
212 rd->range <<= 8; 212 rd->range <<= 8;
213 rd->code = (rd->code << 8) | (uint8_t)getc(rd->fp); 213 rd->code = (rd->code << 8) | (uint8_t)getc(rd->fp);
214 } 214 }
215 return symbol; 215 return symbol;
216} 216}
217 217
218static unsigned 218static unsigned
219lz_rd_decode_tree(struct lz_range_decoder *rd, int *bm, int num_bits) 219lz_rd_decode_tree(struct lz_range_decoder *rd, int *bm, int num_bits)
220{ 220{
221 unsigned symbol = 1; 221 unsigned symbol = 1;
222 222
223 for (int i = 0; i < num_bits; i++) 223 for (int i = 0; i < num_bits; i++)
224 symbol = (symbol << 1) | lz_rd_decode_bit(rd, &bm[symbol]); 224 symbol = (symbol << 1) | lz_rd_decode_bit(rd, &bm[symbol]);
225 225
226 return symbol - (1 << num_bits); 226 return symbol - (1 << num_bits);
227} 227}
228 228
229static unsigned 229static unsigned
230lz_rd_decode_tree_reversed(struct lz_range_decoder *rd, int *bm, int num_bits) 230lz_rd_decode_tree_reversed(struct lz_range_decoder *rd, int *bm, int num_bits)
231{ 231{
232 unsigned symbol = lz_rd_decode_tree(rd, bm, num_bits); 232 unsigned symbol = lz_rd_decode_tree(rd, bm, num_bits);
233 unsigned reversed_symbol = 0; 233 unsigned reversed_symbol = 0;
234 234
235 for (int i = 0; i < num_bits; i++) { 235 for (int i = 0; i < num_bits; i++) {
236 reversed_symbol = (reversed_symbol << 1) | (symbol & 1); 236 reversed_symbol = (reversed_symbol << 1) | (symbol & 1);
237 symbol >>= 1; 237 symbol >>= 1;
238 } 238 }
239 239
240 return reversed_symbol; 240 return reversed_symbol;
241} 241}
242 242
243static unsigned 243static unsigned
244lz_rd_decode_matched(struct lz_range_decoder *rd, int *bm, int match_byte) 244lz_rd_decode_matched(struct lz_range_decoder *rd, int *bm, int match_byte)
245{ 245{
246 unsigned symbol = 1; 246 unsigned symbol = 1;
247 247
248 for (int i = 7; i >= 0; i--) { 248 for (int i = 7; i >= 0; i--) {
249 const unsigned match_bit = (match_byte >> i) & 1; 249 const unsigned match_bit = (match_byte >> i) & 1;
250 const unsigned bit = lz_rd_decode_bit(rd, 250 const unsigned bit = lz_rd_decode_bit(rd,
251 &bm[symbol + (match_bit << 8) + 0x100]); 251 &bm[symbol + (match_bit << 8) + 0x100]);
252 symbol = (symbol << 1) | bit; 252 symbol = (symbol << 1) | bit;
253 if (match_bit != bit) { 253 if (match_bit != bit) {
254 while (symbol < 0x100) { 254 while (symbol < 0x100) {
255 symbol = (symbol << 1) | 255 symbol = (symbol << 1) |
256 lz_rd_decode_bit(rd, &bm[symbol]); 256 lz_rd_decode_bit(rd, &bm[symbol]);
257 } 257 }
258 break; 258 break;
259 } 259 }
260 } 260 }
261 return symbol & 0xFF; 261 return symbol & 0xFF;
262} 262}
263 263
264static unsigned 264static unsigned
265lz_rd_decode_len(struct lz_range_decoder *rd, struct lz_len_model *lm, 265lz_rd_decode_len(struct lz_range_decoder *rd, struct lz_len_model *lm,
266 int pos_state) 266 int pos_state)
267{ 267{
268 if (lz_rd_decode_bit(rd, &lm->choice1) == 0) 268 if (lz_rd_decode_bit(rd, &lm->choice1) == 0)
269 return lz_rd_decode_tree(rd, lm->bm_low[pos_state], LOW_BITS); 269 return lz_rd_decode_tree(rd, lm->bm_low[pos_state], LOW_BITS);
270 270
271 if (lz_rd_decode_bit(rd, &lm->choice2) == 0) { 271 if (lz_rd_decode_bit(rd, &lm->choice2) == 0) {
272 return LOW_SYMBOLS + 272 return LOW_SYMBOLS +
273 lz_rd_decode_tree(rd, lm->bm_mid[pos_state], MID_BITS); 273 lz_rd_decode_tree(rd, lm->bm_mid[pos_state], MID_BITS);
274 } 274 }
275 275
276 return LOW_SYMBOLS + MID_SYMBOLS + 276 return LOW_SYMBOLS + MID_SYMBOLS +
277 lz_rd_decode_tree(rd, lm->bm_high, HIGH_BITS); 277 lz_rd_decode_tree(rd, lm->bm_high, HIGH_BITS);
278} 278}
279 279
280struct lz_decoder { 280struct lz_decoder {
281 FILE *fin, *fout; 281 FILE *fin, *fout;
282 off_t pos, ppos, spos, dict_size; 282 off_t pos, ppos, spos, dict_size;
283 bool wrapped; 283 bool wrapped;
284 uint32_t crc; 284 uint32_t crc;
285 uint8_t *obuf; 285 uint8_t *obuf;
286 struct lz_range_decoder rdec; 286 struct lz_range_decoder rdec;
287}; 287};
288 288
289static int 289static int
290lz_flush(struct lz_decoder *lz) 290lz_flush(struct lz_decoder *lz)
291{ 291{
292 off_t offs = lz->pos - lz->spos; 292 off_t offs = lz->pos - lz->spos;
293 if (offs <= 0) 293 if (offs <= 0)
294 return -1; 294 return -1;
295 295
296 size_t size = (size_t)offs; 296 size_t size = (size_t)offs;
297 lz_crc_update(&lz->crc, lz->obuf + lz->spos, size); 297 lz_crc_update(&lz->crc, lz->obuf + lz->spos, size);
298 if (fwrite(lz->obuf + lz->spos, 1, size, lz->fout) != size) 298 if (fwrite(lz->obuf + lz->spos, 1, size, lz->fout) != size)
299 return -1; 299 return -1;
300 300
301 lz->wrapped = lz->pos >= lz->dict_size; 301 lz->wrapped = lz->pos >= lz->dict_size;
302 if (lz->wrapped) { 302 if (lz->wrapped) {
303 lz->ppos += lz->pos; 303 lz->ppos += lz->pos;
304 lz->pos = 0; 304 lz->pos = 0;
305 } 305 }
306 lz->spos = lz->pos; 306 lz->spos = lz->pos;
307 return 0; 307 return 0;
308} 308}
309 309
310static void 310static void
311lz_destroy(struct lz_decoder *lz) 311lz_destroy(struct lz_decoder *lz)
312{ 312{
313 if (lz->fin) 313 if (lz->fin)
314 fclose(lz->fin); 314 fclose(lz->fin);
315 if (lz->fout) 315 if (lz->fout)
316 fclose(lz->fout); 316 fclose(lz->fout);
317 free(lz->obuf); 317 free(lz->obuf);
318} 318}
319 319
320static int 320static int
321lz_create(struct lz_decoder *lz, int fin, int fdout, int dict_size) 321lz_create(struct lz_decoder *lz, int fin, int fdout, int dict_size)
322{ 322{
323 memset(lz, 0, sizeof(*lz)); 323 memset(lz, 0, sizeof(*lz));
324 324
325 lz->fin = fdopen(dup(fin), "r"); 325 lz->fin = fdopen(dup(fin), "r");
326 if (lz->fin == NULL) 326 if (lz->fin == NULL)
327 goto out; 327 goto out;
328 328
329 lz->fout = fdopen(dup(fdout), "w"); 329 lz->fout = fdopen(dup(fdout), "w");
330 if (lz->fout == NULL) 330 if (lz->fout == NULL)
331 goto out; 331 goto out;
332 332
333 lz->pos = lz->ppos = lz->spos = 0; 333 lz->pos = lz->ppos = lz->spos = 0;
334 lz->crc = ~0; 334 lz->crc = ~0;
335 lz->dict_size = dict_size; 335 lz->dict_size = dict_size;
336 lz->wrapped = false; 336 lz->wrapped = false;
337 337
338 lz->obuf = malloc(dict_size); 338 lz->obuf = malloc(dict_size);
339 if (lz->obuf == NULL) 339 if (lz->obuf == NULL)
340 goto out; 340 goto out;
341 341
342 if (lz_rd_create(&lz->rdec, lz->fin) == -1) 342 if (lz_rd_create(&lz->rdec, lz->fin) == -1)
343 goto out; 343 goto out;
344 return 0; 344 return 0;
345out: 345out:
346 lz_destroy(lz); 346 lz_destroy(lz);
347 return -1; 347 return -1;
348} 348}
349 349
350static uint8_t 350static uint8_t
351lz_peek(const struct lz_decoder *lz, unsigned ahead) 351lz_peek(const struct lz_decoder *lz, unsigned ahead)
352{ 352{
353 off_t diff = lz->pos - ahead - 1; 353 off_t diff = lz->pos - ahead - 1;
354 354
355 if (diff >= 0) 355 if (diff >= 0)
356 return lz->obuf[diff]; 356 return lz->obuf[diff];
357 357
358 if (lz->wrapped) 358 if (lz->wrapped)
359 return lz->obuf[lz->dict_size + diff]; 359 return lz->obuf[lz->dict_size + diff];
360 360
361 return 0; 361 return 0;
362} 362}
363 363
364static void 364static void
365lz_put(struct lz_decoder *lz, uint8_t b) 365lz_put(struct lz_decoder *lz, uint8_t b)
366{ 366{
367 lz->obuf[lz->pos++] = b; 367 lz->obuf[lz->pos++] = b;
368 if (lz->dict_size == lz->pos) 368 if (lz->dict_size == lz->pos)
369 lz_flush(lz); 369 lz_flush(lz);
370} 370}
371 371
372static off_t 372static off_t
373lz_get_data_position(const struct lz_decoder *lz) 373lz_get_data_position(const struct lz_decoder *lz)
374{ 374{
375 return lz->ppos + lz->pos; 375 return lz->ppos + lz->pos;
376} 376}
377 377
378static unsigned 378static unsigned
379lz_get_crc(const struct lz_decoder *lz) 379lz_get_crc(const struct lz_decoder *lz)
380{ 380{
381 return lz->crc ^ 0xffffffffU; 381 return lz->crc ^ 0xffffffffU;
382} 382}
383 383
384static void 384static void
385lz_bm_init(int *a, size_t l) 385lz_bm_init(int *a, size_t l)
386{ 386{
387 for (size_t i = 0; i < l; i++) 387 for (size_t i = 0; i < l; i++)
388 a[i] = BIT_MODEL_INIT; 388 a[i] = BIT_MODEL_INIT;
389} 389}
390 390
391#define LZ_BM_INIT(a) lz_bm_init(a, __arraycount(a)) 391#define LZ_BM_INIT(a) lz_bm_init(a, __arraycount(a))
392#define LZ_BM_INIT2(a) do { \ 392#define LZ_BM_INIT2(a) do { \
393 size_t l = __arraycount(a[0]); \ 393 size_t l = __arraycount(a[0]); \
394 for (size_t i = 0; i < __arraycount(a); i++) \ 394 for (size_t i = 0; i < __arraycount(a); i++) \
395 lz_bm_init(a[i], l); \ 395 lz_bm_init(a[i], l); \
396} while (0) 396} while (0)
397 397
398#define LZ_MODEL_INIT(a) do { \ 398#define LZ_MODEL_INIT(a) do { \
399 a.choice1 = BIT_MODEL_INIT; \ 399 a.choice1 = BIT_MODEL_INIT; \
400 a.choice2 = BIT_MODEL_INIT; \ 400 a.choice2 = BIT_MODEL_INIT; \
401 LZ_BM_INIT2(a.bm_low); \ 401 LZ_BM_INIT2(a.bm_low); \
402 LZ_BM_INIT2(a.bm_mid); \ 402 LZ_BM_INIT2(a.bm_mid); \
403 LZ_BM_INIT(a.bm_high); \ 403 LZ_BM_INIT(a.bm_high); \
404} while (0) 404} while (0)
405  405
406static bool 406static bool
407lz_decode_member(struct lz_decoder *lz) 407lz_decode_member(struct lz_decoder *lz)
408{ 408{
409 int bm_literal[1 << LITERAL_CONTEXT_BITS][0x300]; 409 int bm_literal[1 << LITERAL_CONTEXT_BITS][0x300];
410 int bm_match[LZ_STATES][POS_STATES]; 410 int bm_match[LZ_STATES][POS_STATES];
411 int bm_rep[4][LZ_STATES]; 411 int bm_rep[4][LZ_STATES];
412 int bm_len[LZ_STATES][POS_STATES]; 412 int bm_len[LZ_STATES][POS_STATES];
413 int bm_dis_slot[LZ_STATES][1 << DIS_SLOT_BITS]; 413 int bm_dis_slot[LZ_STATES][1 << DIS_SLOT_BITS];
414 int bm_dis[MODELED_DISTANCES - DIS_MODEL_END + 1]; 414 int bm_dis[MODELED_DISTANCES - DIS_MODEL_END + 1];
415 int bm_align[DIS_ALIGN_SIZE]; 415 int bm_align[DIS_ALIGN_SIZE];
416 416
417 LZ_BM_INIT2(bm_literal); 417 LZ_BM_INIT2(bm_literal);
418 LZ_BM_INIT2(bm_match); 418 LZ_BM_INIT2(bm_match);
419 LZ_BM_INIT2(bm_rep); 419 LZ_BM_INIT2(bm_rep);
420 LZ_BM_INIT2(bm_len); 420 LZ_BM_INIT2(bm_len);
421 LZ_BM_INIT2(bm_dis_slot); 421 LZ_BM_INIT2(bm_dis_slot);
422 LZ_BM_INIT(bm_dis); 422 LZ_BM_INIT(bm_dis);
423 LZ_BM_INIT(bm_align); 423 LZ_BM_INIT(bm_align);
424 424
425 struct lz_len_model match_len_model; 425 struct lz_len_model match_len_model;
426 struct lz_len_model rep_len_model; 426 struct lz_len_model rep_len_model;
427 427
428 LZ_MODEL_INIT(match_len_model); 428 LZ_MODEL_INIT(match_len_model);
429 LZ_MODEL_INIT(rep_len_model); 429 LZ_MODEL_INIT(rep_len_model);
430 430
431 struct lz_range_decoder *rd = &lz->rdec; 431 struct lz_range_decoder *rd = &lz->rdec;
432 unsigned rep[4] = { 0 }; 432 unsigned rep[4] = { 0 };
433 433
434 434
435 int state = 0; 435 int state = 0;
436 436
437 while (!feof(lz->fin) && !ferror(lz->fin)) { 437 while (!feof(lz->fin) && !ferror(lz->fin)) {
438 const int pos_state = lz_get_data_position(lz) & POS_STATE_MASK; 438 const int pos_state = lz_get_data_position(lz) & POS_STATE_MASK;
439 // bit 1 439 // bit 1
440 if (lz_rd_decode_bit(rd, &bm_match[state][pos_state]) == 0) { 440 if (lz_rd_decode_bit(rd, &bm_match[state][pos_state]) == 0) {
441 const uint8_t prev_byte = lz_peek(lz, 0); 441 const uint8_t prev_byte = lz_peek(lz, 0);
442 const int literal_state = 442 const int literal_state =
443 prev_byte >> (8 - LITERAL_CONTEXT_BITS); 443 prev_byte >> (8 - LITERAL_CONTEXT_BITS);
444 int *bm = bm_literal[literal_state]; 444 int *bm = bm_literal[literal_state];
445 if (lz_st_is_char(state)) 445 if (lz_st_is_char(state))
446 lz_put(lz, lz_rd_decode_tree(rd, bm, 8)); 446 lz_put(lz, lz_rd_decode_tree(rd, bm, 8));
447 else { 447 else {
448 int peek = lz_peek(lz, rep[0]); 448 int peek = lz_peek(lz, rep[0]);
449 lz_put(lz, lz_rd_decode_matched(rd, bm, peek)); 449 lz_put(lz, lz_rd_decode_matched(rd, bm, peek));
450 } 450 }
451 state = lz_st_get_char(state); 451 state = lz_st_get_char(state);
452 continue; 452 continue;
453 } 453 }
454 int len; 454 int len;
455 // bit 2 455 // bit 2
456 if (lz_rd_decode_bit(rd, &bm_rep[0][state]) != 0) { 456 if (lz_rd_decode_bit(rd, &bm_rep[0][state]) != 0) {
457 // bit 3 457 // bit 3
458 if (lz_rd_decode_bit(rd, &bm_rep[1][state]) == 0) { 458 if (lz_rd_decode_bit(rd, &bm_rep[1][state]) == 0) {
459 // bit 4 459 // bit 4
460 if (lz_rd_decode_bit(rd, 460 if (lz_rd_decode_bit(rd,
461 &bm_len[state][pos_state]) == 0) 461 &bm_len[state][pos_state]) == 0)
462 { 462 {
463 state = lz_st_get_short_rep(state); 463 state = lz_st_get_short_rep(state);
464 lz_put(lz, lz_peek(lz, rep[0])); 464 lz_put(lz, lz_peek(lz, rep[0]));
465 continue; 465 continue;
466 } 466 }
467 } else { 467 } else {
468 unsigned distance; 468 unsigned distance;
469 // bit 4 469 // bit 4
470 if (lz_rd_decode_bit(rd, &bm_rep[2][state]) 470 if (lz_rd_decode_bit(rd, &bm_rep[2][state])
471 == 0) 471 == 0)
472 distance = rep[1]; 472 distance = rep[1];
473 else { 473 else {
474 // bit 5 474 // bit 5
475 if (lz_rd_decode_bit(rd, 475 if (lz_rd_decode_bit(rd,
476 &bm_rep[3][state]) == 0) 476 &bm_rep[3][state]) == 0)
477 distance = rep[2]; 477 distance = rep[2];
478 else { 478 else {
479 distance = rep[3]; 479 distance = rep[3];
480 rep[3] = rep[2]; 480 rep[3] = rep[2];
481 } 481 }
482 rep[2] = rep[1]; 482 rep[2] = rep[1];
483 } 483 }
484 rep[1] = rep[0]; 484 rep[1] = rep[0];
485 rep[0] = distance; 485 rep[0] = distance;
486 } 486 }
487 state = lz_st_get_rep(state); 487 state = lz_st_get_rep(state);
488 len = MIN_MATCH_LEN + 488 len = MIN_MATCH_LEN +
489 lz_rd_decode_len(rd, &rep_len_model, pos_state); 489 lz_rd_decode_len(rd, &rep_len_model, pos_state);
490 } else { 490 } else {
491 rep[3] = rep[2]; rep[2] = rep[1]; rep[1] = rep[0]; 491 rep[3] = rep[2]; rep[2] = rep[1]; rep[1] = rep[0];
492 len = MIN_MATCH_LEN + 492 len = MIN_MATCH_LEN +
493 lz_rd_decode_len(rd, &match_len_model, pos_state); 493 lz_rd_decode_len(rd, &match_len_model, pos_state);
494 const int len_state = 494 const int len_state =
495 MIN(len - MIN_MATCH_LEN, STATES - 1); 495 MIN(len - MIN_MATCH_LEN, STATES - 1);
496 rep[0] = lz_rd_decode_tree(rd, bm_dis_slot[len_state], 496 rep[0] = lz_rd_decode_tree(rd, bm_dis_slot[len_state],
497 DIS_SLOT_BITS); 497 DIS_SLOT_BITS);
498 if (rep[0] >= DIS_MODEL_START) { 498 if (rep[0] >= DIS_MODEL_START) {
499 const unsigned dis_slot = rep[0]; 499 const unsigned dis_slot = rep[0];
500 const int direct_bits = (dis_slot >> 1) - 1; 500 const int direct_bits = (dis_slot >> 1) - 1;
501 rep[0] = (2 | (dis_slot & 1)) << direct_bits; 501 rep[0] = (2 | (dis_slot & 1)) << direct_bits;
502 if (dis_slot < DIS_MODEL_END) 502 if (dis_slot < DIS_MODEL_END)
503 rep[0] += lz_rd_decode_tree_reversed(rd, 503 rep[0] += lz_rd_decode_tree_reversed(rd,
504 &bm_dis[rep[0] - dis_slot], 504 &bm_dis[rep[0] - dis_slot],
505 direct_bits); 505 direct_bits);
506 else { 506 else {
507 rep[0] += lz_rd_decode(rd, direct_bits 507 rep[0] += lz_rd_decode(rd, direct_bits
508 - DIS_ALIGN_BITS) << DIS_ALIGN_BITS; 508 - DIS_ALIGN_BITS) << DIS_ALIGN_BITS;
509 rep[0] += lz_rd_decode_tree_reversed(rd, 509 rep[0] += lz_rd_decode_tree_reversed(rd,
510 bm_align, DIS_ALIGN_BITS); 510 bm_align, DIS_ALIGN_BITS);
511 if (rep[0] == 0xFFFFFFFFU) { 511 if (rep[0] == 0xFFFFFFFFU) {
512 lz_flush(lz); 512 lz_flush(lz);
513 return len == MIN_MATCH_LEN; 513 return len == MIN_MATCH_LEN;
514 } 514 }
515 } 515 }
516 } 516 }
517 state = lz_st_get_match(state); 517 state = lz_st_get_match(state);
518 if (rep[0] >= lz->dict_size || 518 if (rep[0] >= lz->dict_size ||
519 (rep[0] >= lz->pos && !lz->wrapped)) { 519 (rep[0] >= lz->pos && !lz->wrapped)) {
520 lz_flush(lz); 520 lz_flush(lz);
521 return false; 521 return false;
522 } 522 }
523 } 523 }
524 for (int i = 0; i < len; i++) 524 for (int i = 0; i < len; i++)
525 lz_put(lz, lz_peek(lz, rep[0])); 525 lz_put(lz, lz_peek(lz, rep[0]));
526 } 526 }
527 lz_flush(lz); 527 lz_flush(lz);
528 return false; 528 return false;
529} 529}
530 530
531/* 531/*
532 * 0-3 CRC32 of the uncompressed data 532 * 0-3 CRC32 of the uncompressed data
533 * 4-11 size of the uncompressed data 533 * 4-11 size of the uncompressed data
534 * 12-19 member size including header and trailer 534 * 12-19 member size including header and trailer
535 */ 535 */
536#define TRAILER_SIZE 20 536#define TRAILER_SIZE 20
537 537
538 538
539static off_t 539static off_t
540lz_decode(int fin, int fdout, unsigned dict_size, off_t *insize) 540lz_decode(int fin, int fdout, unsigned dict_size, off_t *insize)
541{ 541{
542 struct lz_decoder lz; 542 struct lz_decoder lz;
543 off_t rv = -1; 543 off_t rv = -1;
544 544
545 if (lz_create(&lz, fin, fdout, dict_size) == -1) 545 if (lz_create(&lz, fin, fdout, dict_size) == -1)
546 return -1; 546 return -1;
547 547
548 if (!lz_decode_member(&lz)) 548 if (!lz_decode_member(&lz))
549 goto out; 549 goto out;
550 550
551 uint8_t trailer[TRAILER_SIZE]; 551 uint8_t trailer[TRAILER_SIZE];
552 552
553 for(size_t i = 0; i < __arraycount(trailer); i++)  553 for(size_t i = 0; i < __arraycount(trailer); i++)
554 trailer[i] = (uint8_t)getc(lz.fin); 554 trailer[i] = (uint8_t)getc(lz.fin);
555 555
556 unsigned crc = 0; 556 unsigned crc = 0;
557 for (int i = 3; i >= 0; --i) { 557 for (int i = 3; i >= 0; --i) {
558 crc <<= 8; 558 crc <<= 8;
559 crc += trailer[i]; 559 crc += trailer[i];
560 } 560 }
561 561
562 int64_t data_size = 0; 562 int64_t data_size = 0;
563 for (int i = 11; i >= 4; --i) { 563 for (int i = 11; i >= 4; --i) {
564 data_size <<= 8; 564 data_size <<= 8;
565 data_size += trailer[i]; 565 data_size += trailer[i];
566 } 566 }
567 567
568 if (crc != lz_get_crc(&lz) || data_size != lz_get_data_position(&lz)) 568 if (crc != lz_get_crc(&lz) || data_size != lz_get_data_position(&lz))
569 goto out; 569 goto out;
570 570
571 rv = 0; 571 rv = 0;
572 for (int i = 19; i >= 12; --i) { 572 for (int i = 19; i >= 12; --i) {
573 rv <<= 8; 573 rv <<= 8;
574 rv += trailer[i]; 574 rv += trailer[i];
575 } 575 }
576 if (insize) 576 if (insize)
577 *insize = rv; 577 *insize = rv;
578#if 0 578#if 0
579 /* Does not work with pipes */ 579 /* Does not work with pipes */
580 rv = ftello(lz.fout); 580 rv = ftello(lz.fout);
581#else 581#else
582 rv = data_size; 582 rv = data_size;
583#endif 583#endif
584out: 584out:
585 lz_destroy(&lz); 585 lz_destroy(&lz);
586 return rv; 586 return rv;
587} 587}
588 588
589 589
590/* 590/*
591 * 0-3 magic 591 * 0-3 magic
592 * 4 version 592 * 4 version
593 * 5 coded dict_size 593 * 5 coded dict_size
594 */ 594 */
595#define HDR_SIZE 6 595#define HDR_SIZE 6
596#define MIN_DICTIONARY_SIZE (1 << 12) 596#define MIN_DICTIONARY_SIZE (1 << 12)
597#define MAX_DICTIONARY_SIZE (1 << 29) 597#define MAX_DICTIONARY_SIZE (1 << 29)
598 598
599static const char hdrmagic[] = { 'L', 'Z', 'I', 'P', 1 }; 599static const char hdrmagic[] = { 'L', 'Z', 'I', 'P', 1 };
600 600
601static unsigned 601static unsigned
602lz_get_dict_size(unsigned char c) 602lz_get_dict_size(unsigned char c)
603{ 603{
604 unsigned dict_size = 1 << (c & 0x1f); 604 unsigned dict_size = 1 << (c & 0x1f);
605 dict_size -= (dict_size >> 2) * ( (c >> 5) & 0x7); 605 dict_size -= (dict_size >> 2) * ( (c >> 5) & 0x7);
606 if (dict_size < MIN_DICTIONARY_SIZE || dict_size > MAX_DICTIONARY_SIZE) 606 if (dict_size < MIN_DICTIONARY_SIZE || dict_size > MAX_DICTIONARY_SIZE)
607 return 0; 607 return 0;
608 return dict_size; 608 return dict_size;
609} 609}
610 610
611static off_t 611static off_t
612unlz(int fin, int fout, char *pre, size_t prelen, off_t *bytes_in) 612unlz(int fin, int fout, char *pre, size_t prelen, off_t *bytes_in)
613{ 613{
614 if (lz_crc[0] == 0) 614 if (lz_crc[0] == 0)
615 lz_crc_init(); 615 lz_crc_init();
616 616
617 char header[HDR_SIZE]; 617 char header[HDR_SIZE];
618 618
619 if (prelen > sizeof(header)) 
620 return -1; 
621 if (pre && prelen) 619 if (pre && prelen)
622 memcpy(header, pre, prelen); 620 memcpy(header, pre, prelen);
623  621
624 ssize_t nr = read(fin, header + prelen, sizeof(header) - prelen); 622 ssize_t nr = read(fin, header + prelen, sizeof(header) - prelen);
625 switch (nr) { 623 switch (nr) {
626 case -1: 624 case -1:
627 return -1; 625 return -1;
628 case 0: 626 case 0:
629 return prelen ? -1 : 0; 627 return prelen ? -1 : 0;
630 default: 628 default:
631 if ((size_t)nr != sizeof(header) - prelen) 629 if ((size_t)nr != sizeof(header) - prelen)
632 return -1; 630 return -1;
633 break; 631 break;
634 } 632 }
635 633
636 if (memcmp(header, hdrmagic, sizeof(hdrmagic)) != 0) 634 if (memcmp(header, hdrmagic, sizeof(hdrmagic)) != 0)
637 return -1; 635 return -1;
638 636
639 unsigned dict_size = lz_get_dict_size(header[5]); 637 unsigned dict_size = lz_get_dict_size(header[5]);
640 if (dict_size == 0) 638 if (dict_size == 0)
641 return -1; 639 return -1;
642 640
643 return lz_decode(fin, fout, dict_size, bytes_in); 641 return lz_decode(fin, fout, dict_size, bytes_in);
644} 642}

cvs diff -r1.3 -r1.4 src/usr.bin/gzip/unpack.c (switch to unified diff)

--- src/usr.bin/gzip/unpack.c 2017/08/04 07:27:08 1.3
+++ src/usr.bin/gzip/unpack.c 2023/06/10 04:45:25 1.4
@@ -1,331 +1,328 @@ @@ -1,331 +1,328 @@
1/* $FreeBSD: head/usr.bin/gzip/unpack.c 194579 2009-06-21 09:39:43Z delphij $ */ 1/* $FreeBSD: head/usr.bin/gzip/unpack.c 194579 2009-06-21 09:39:43Z delphij $ */
2/* $NetBSD: unpack.c,v 1.3 2017/08/04 07:27:08 mrg Exp $ */ 2/* $NetBSD: unpack.c,v 1.4 2023/06/10 04:45:25 simonb Exp $ */
3 3
4/*- 4/*-
5 * Copyright (c) 2009 Xin LI <delphij@FreeBSD.org> 5 * Copyright (c) 2009 Xin LI <delphij@FreeBSD.org>
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution. 15 * documentation and/or other materials provided with the distribution.
16 * 16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE. 27 * SUCH DAMAGE.
28 */ 28 */
29 29
30/* This file is #included by gzip.c */ 30/* This file is #included by gzip.c */
31 31
32/* 32/*
33 * pack(1) file format: 33 * pack(1) file format:
34 * 34 *
35 * The first 7 bytes is the header: 35 * The first 7 bytes is the header:
36 * 00, 01 - Signature (US, RS), we already validated it earlier. 36 * 00, 01 - Signature (US, RS), we already validated it earlier.
37 * 02..05 - Uncompressed size 37 * 02..05 - Uncompressed size
38 * 06 - Level for the huffman tree (<=24) 38 * 06 - Level for the huffman tree (<=24)
39 * 39 *
40 * pack(1) will then store symbols (leaf) nodes count in each huffman 40 * pack(1) will then store symbols (leaf) nodes count in each huffman
41 * tree levels, each level would consume 1 byte (See [1]). 41 * tree levels, each level would consume 1 byte (See [1]).
42 * 42 *
43 * After the symbol count table, there is the symbol table, storing 43 * After the symbol count table, there is the symbol table, storing
44 * symbols represented by corresponding leaf node. EOB is not being 44 * symbols represented by corresponding leaf node. EOB is not being
45 * explicitly transmitted (not necessary anyway) in the symbol table. 45 * explicitly transmitted (not necessary anyway) in the symbol table.
46 * 46 *
47 * Compressed data goes after the symbol table. 47 * Compressed data goes after the symbol table.
48 * 48 *
49 * NOTES 49 * NOTES
50 * 50 *
51 * [1] If we count EOB into the symbols, that would mean that we will 51 * [1] If we count EOB into the symbols, that would mean that we will
52 * have at most 256 symbols in the huffman tree. pack(1) rejects empty 52 * have at most 256 symbols in the huffman tree. pack(1) rejects empty
53 * file and files that just repeats one character, which means that we 53 * file and files that just repeats one character, which means that we
54 * will have at least 2 symbols. Therefore, pack(1) would reduce the 54 * will have at least 2 symbols. Therefore, pack(1) would reduce the
55 * last level symbol count by 2 which makes it a number in 55 * last level symbol count by 2 which makes it a number in
56 * range [0..254], so all levels' symbol count would fit into 1 byte. 56 * range [0..254], so all levels' symbol count would fit into 1 byte.
57 */ 57 */
58 58
59#define PACK_HEADER_LENGTH 7 59#define PACK_HEADER_LENGTH 7
60#define HTREE_MAXLEVEL 24 60#define HTREE_MAXLEVEL 24
61 61
62/* 62/*
63 * unpack descriptor 63 * unpack descriptor
64 * 64 *
65 * Represent the huffman tree in a similar way that pack(1) would 65 * Represent the huffman tree in a similar way that pack(1) would
66 * store in a packed file. We store all symbols in a linear table, 66 * store in a packed file. We store all symbols in a linear table,
67 * and store pointers to each level's first symbol. In addition to 67 * and store pointers to each level's first symbol. In addition to
68 * that, maintain two counts for each level: inner nodes count and 68 * that, maintain two counts for each level: inner nodes count and
69 * leaf nodes count. 69 * leaf nodes count.
70 */ 70 */
71typedef struct { 71typedef struct {
72 int symbol_size; /* Size of the symbol table */ 72 int symbol_size; /* Size of the symbol table */
73 int treelevels; /* Levels for the huffman tree */ 73 int treelevels; /* Levels for the huffman tree */
74 74
75 int *symbolsin; /* Table of leaf symbols count in 75 int *symbolsin; /* Table of leaf symbols count in
76 each level */ 76 each level */
77 int *inodesin; /* Table of internal nodes count in 77 int *inodesin; /* Table of internal nodes count in
78 each level */ 78 each level */
79 79
80 char *symbol; /* The symbol table */ 80 char *symbol; /* The symbol table */
81 char *symbol_eob; /* Pointer to the EOB symbol */ 81 char *symbol_eob; /* Pointer to the EOB symbol */
82 char **tree; /* Decoding huffman tree (pointers to 82 char **tree; /* Decoding huffman tree (pointers to
83 first symbol of each tree level */ 83 first symbol of each tree level */
84 84
85 off_t uncompressed_size; /* Uncompressed size */ 85 off_t uncompressed_size; /* Uncompressed size */
86 FILE *fpIn; /* Input stream */ 86 FILE *fpIn; /* Input stream */
87 FILE *fpOut; /* Output stream */ 87 FILE *fpOut; /* Output stream */
88} unpack_descriptor_t; 88} unpack_descriptor_t;
89 89
90/* 90/*
91 * Release resource allocated to an unpack descriptor. 91 * Release resource allocated to an unpack descriptor.
92 * 92 *
93 * Caller is responsible to make sure that all of these pointers are 93 * Caller is responsible to make sure that all of these pointers are
94 * initialized (in our case, they all point to valid memory block). 94 * initialized (in our case, they all point to valid memory block).
95 * We don't zero out pointers here because nobody else would ever 95 * We don't zero out pointers here because nobody else would ever
96 * reference the memory block without scrubbing them. 96 * reference the memory block without scrubbing them.
97 */ 97 */
98static void 98static void
99unpack_descriptor_fini(unpack_descriptor_t *unpackd) 99unpack_descriptor_fini(unpack_descriptor_t *unpackd)
100{ 100{
101 101
102 free(unpackd->symbolsin); 102 free(unpackd->symbolsin);
103 free(unpackd->inodesin); 103 free(unpackd->inodesin);
104 free(unpackd->symbol); 104 free(unpackd->symbol);
105 free(unpackd->tree); 105 free(unpackd->tree);
106 106
107 fclose(unpackd->fpIn); 107 fclose(unpackd->fpIn);
108 fclose(unpackd->fpOut); 108 fclose(unpackd->fpOut);
109} 109}
110 110
111/* 111/*
112 * Recursively fill the internal node count table 112 * Recursively fill the internal node count table
113 */ 113 */
114static void 114static void
115unpackd_fill_inodesin(const unpack_descriptor_t *unpackd, int level) 115unpackd_fill_inodesin(const unpack_descriptor_t *unpackd, int level)
116{ 116{
117 117
118 /* 118 /*
119 * The internal nodes would be 1/2 of total internal nodes and 119 * The internal nodes would be 1/2 of total internal nodes and
120 * leaf nodes in the next level. For the last level there 120 * leaf nodes in the next level. For the last level there
121 * would be no internal node by definition. 121 * would be no internal node by definition.
122 */ 122 */
123 if (level < unpackd->treelevels) { 123 if (level < unpackd->treelevels) {
124 unpackd_fill_inodesin(unpackd, level + 1); 124 unpackd_fill_inodesin(unpackd, level + 1);
125 unpackd->inodesin[level] = (unpackd->inodesin[level + 1] + 125 unpackd->inodesin[level] = (unpackd->inodesin[level + 1] +
126 unpackd->symbolsin[level + 1]) / 2; 126 unpackd->symbolsin[level + 1]) / 2;
127 } else 127 } else
128 unpackd->inodesin[level] = 0; 128 unpackd->inodesin[level] = 0;
129} 129}
130 130
131/* 131/*
132 * Update counter for accepted bytes 132 * Update counter for accepted bytes
133 */ 133 */
134static void 134static void
135accepted_bytes(off_t *bytes_in, off_t newbytes) 135accepted_bytes(off_t *bytes_in, off_t newbytes)
136{ 136{
137 137
138 if (bytes_in != NULL) 138 if (bytes_in != NULL)
139 (*bytes_in) += newbytes; 139 (*bytes_in) += newbytes;
140} 140}
141 141
142/* 142/*
143 * Read file header and construct the tree. Also, prepare the buffered I/O 143 * Read file header and construct the tree. Also, prepare the buffered I/O
144 * for decode routine. 144 * for decode routine.
145 * 145 *
146 * Return value is uncompressed size. 146 * Return value is uncompressed size.
147 */ 147 */
148static void 148static void
149unpack_parse_header(int in, int out, char *pre, size_t prelen, off_t *bytes_in, 149unpack_parse_header(int in, int out, char *pre, size_t prelen, off_t *bytes_in,
150 unpack_descriptor_t *unpackd) 150 unpack_descriptor_t *unpackd)
151{ 151{
152 unsigned char hdr[PACK_HEADER_LENGTH]; /* buffer for header */ 152 unsigned char hdr[PACK_HEADER_LENGTH]; /* buffer for header */
153 ssize_t bytesread; /* Bytes read from the file */ 153 ssize_t bytesread; /* Bytes read from the file */
154 int i, j, thisbyte; 154 int i, j, thisbyte;
155 155
156 if (prelen > sizeof hdr) 
157 maybe_err("prelen too long"); 
158 
159 /* Prepend the header buffer if we already read some data */ 156 /* Prepend the header buffer if we already read some data */
160 if (prelen != 0) 157 if (prelen != 0)
161 memcpy(hdr, pre, prelen); 158 memcpy(hdr, pre, prelen);
162 159
163 /* Read in and fill the rest bytes of header */ 160 /* Read in and fill the rest bytes of header */
164 bytesread = read(in, hdr + prelen, PACK_HEADER_LENGTH - prelen); 161 bytesread = read(in, hdr + prelen, PACK_HEADER_LENGTH - prelen);
165 if (bytesread < 0) 162 if (bytesread < 0)
166 maybe_err("Error reading pack header"); 163 maybe_err("Error reading pack header");
167 infile_newdata(bytesread); 164 infile_newdata(bytesread);
168 165
169 accepted_bytes(bytes_in, PACK_HEADER_LENGTH); 166 accepted_bytes(bytes_in, PACK_HEADER_LENGTH);
170 167
171 /* Obtain uncompressed length (bytes 2,3,4,5)*/ 168 /* Obtain uncompressed length (bytes 2,3,4,5)*/
172 unpackd->uncompressed_size = 0; 169 unpackd->uncompressed_size = 0;
173 for (i = 2; i <= 5; i++) { 170 for (i = 2; i <= 5; i++) {
174 unpackd->uncompressed_size <<= 8; 171 unpackd->uncompressed_size <<= 8;
175 unpackd->uncompressed_size |= hdr[i]; 172 unpackd->uncompressed_size |= hdr[i];
176 } 173 }
177 174
178 /* Get the levels of the tree */ 175 /* Get the levels of the tree */
179 unpackd->treelevels = hdr[6]; 176 unpackd->treelevels = hdr[6];
180 if (unpackd->treelevels > HTREE_MAXLEVEL || unpackd->treelevels < 1) 177 if (unpackd->treelevels > HTREE_MAXLEVEL || unpackd->treelevels < 1)
181 maybe_errx("Huffman tree has insane levels"); 178 maybe_errx("Huffman tree has insane levels");
182 179
183 /* Let libc take care for buffering from now on */ 180 /* Let libc take care for buffering from now on */
184 if ((unpackd->fpIn = fdopen(in, "r")) == NULL) 181 if ((unpackd->fpIn = fdopen(in, "r")) == NULL)
185 maybe_err("Can not fdopen() input stream"); 182 maybe_err("Can not fdopen() input stream");
186 if ((unpackd->fpOut = fdopen(out, "w")) == NULL) 183 if ((unpackd->fpOut = fdopen(out, "w")) == NULL)
187 maybe_err("Can not fdopen() output stream"); 184 maybe_err("Can not fdopen() output stream");
188 185
189 /* Allocate for the tables of bounds and the tree itself */ 186 /* Allocate for the tables of bounds and the tree itself */
190 unpackd->inodesin = 187 unpackd->inodesin =
191 calloc(unpackd->treelevels, sizeof(*(unpackd->inodesin))); 188 calloc(unpackd->treelevels, sizeof(*(unpackd->inodesin)));
192 unpackd->symbolsin = 189 unpackd->symbolsin =
193 calloc(unpackd->treelevels, sizeof(*(unpackd->symbolsin))); 190 calloc(unpackd->treelevels, sizeof(*(unpackd->symbolsin)));
194 unpackd->tree = 191 unpackd->tree =
195 calloc(unpackd->treelevels, (sizeof (*(unpackd->tree)))); 192 calloc(unpackd->treelevels, (sizeof (*(unpackd->tree))));
196 if (unpackd->inodesin == NULL || unpackd->symbolsin == NULL || 193 if (unpackd->inodesin == NULL || unpackd->symbolsin == NULL ||
197 unpackd->tree == NULL) 194 unpackd->tree == NULL)
198 maybe_err("calloc"); 195 maybe_err("calloc");
199 196
200 /* We count from 0 so adjust to match array upper bound */ 197 /* We count from 0 so adjust to match array upper bound */
201 unpackd->treelevels--; 198 unpackd->treelevels--;
202 199
203 /* Read the levels symbol count table and calculate total */ 200 /* Read the levels symbol count table and calculate total */
204 unpackd->symbol_size = 1; /* EOB */ 201 unpackd->symbol_size = 1; /* EOB */
205 for (i = 0; i <= unpackd->treelevels; i++) { 202 for (i = 0; i <= unpackd->treelevels; i++) {
206 if ((thisbyte = fgetc(unpackd->fpIn)) == EOF) 203 if ((thisbyte = fgetc(unpackd->fpIn)) == EOF)
207 maybe_err("File appears to be truncated"); 204 maybe_err("File appears to be truncated");
208 unpackd->symbolsin[i] = (unsigned char)thisbyte; 205 unpackd->symbolsin[i] = (unsigned char)thisbyte;
209 unpackd->symbol_size += unpackd->symbolsin[i]; 206 unpackd->symbol_size += unpackd->symbolsin[i];
210 } 207 }
211 accepted_bytes(bytes_in, unpackd->treelevels); 208 accepted_bytes(bytes_in, unpackd->treelevels);
212 if (unpackd->symbol_size > 256) 209 if (unpackd->symbol_size > 256)
213 maybe_errx("Bad symbol table"); 210 maybe_errx("Bad symbol table");
214 infile_newdata(unpackd->treelevels); 211 infile_newdata(unpackd->treelevels);
215 212
216 /* Allocate for the symbol table, point symbol_eob at the beginning */ 213 /* Allocate for the symbol table, point symbol_eob at the beginning */
217 unpackd->symbol_eob = unpackd->symbol = calloc(1, unpackd->symbol_size); 214 unpackd->symbol_eob = unpackd->symbol = calloc(1, unpackd->symbol_size);
218 if (unpackd->symbol == NULL) 215 if (unpackd->symbol == NULL)
219 maybe_err("calloc"); 216 maybe_err("calloc");
220 217
221 /* 218 /*
222 * Read in the symbol table, which contain [2, 256] symbols. 219 * Read in the symbol table, which contain [2, 256] symbols.
223 * In order to fit the count in one byte, pack(1) would offset 220 * In order to fit the count in one byte, pack(1) would offset
224 * it by reducing 2 from the actual number from the last level. 221 * it by reducing 2 from the actual number from the last level.
225 * 222 *
226 * We adjust the last level's symbol count by 1 here, because 223 * We adjust the last level's symbol count by 1 here, because
227 * the EOB symbol is not being transmitted explicitly. Another 224 * the EOB symbol is not being transmitted explicitly. Another
228 * adjustment would be done later afterward. 225 * adjustment would be done later afterward.
229 */ 226 */
230 unpackd->symbolsin[unpackd->treelevels]++; 227 unpackd->symbolsin[unpackd->treelevels]++;
231 for (i = 0; i <= unpackd->treelevels; i++) { 228 for (i = 0; i <= unpackd->treelevels; i++) {
232 unpackd->tree[i] = unpackd->symbol_eob; 229 unpackd->tree[i] = unpackd->symbol_eob;
233 for (j = 0; j < unpackd->symbolsin[i]; j++) { 230 for (j = 0; j < unpackd->symbolsin[i]; j++) {
234 if ((thisbyte = fgetc(unpackd->fpIn)) == EOF) 231 if ((thisbyte = fgetc(unpackd->fpIn)) == EOF)
235 maybe_errx("Symbol table truncated"); 232 maybe_errx("Symbol table truncated");
236 *unpackd->symbol_eob++ = (char)thisbyte; 233 *unpackd->symbol_eob++ = (char)thisbyte;
237 } 234 }
238 infile_newdata(unpackd->symbolsin[i]); 235 infile_newdata(unpackd->symbolsin[i]);
239 accepted_bytes(bytes_in, unpackd->symbolsin[i]); 236 accepted_bytes(bytes_in, unpackd->symbolsin[i]);
240 } 237 }
241 238
242 /* Now, take account for the EOB symbol as well */ 239 /* Now, take account for the EOB symbol as well */
243 unpackd->symbolsin[unpackd->treelevels]++; 240 unpackd->symbolsin[unpackd->treelevels]++;
244 241
245 /* 242 /*
246 * The symbolsin table has been constructed now. 243 * The symbolsin table has been constructed now.
247 * Calculate the internal nodes count table based on it. 244 * Calculate the internal nodes count table based on it.
248 */ 245 */
249 unpackd_fill_inodesin(unpackd, 0); 246 unpackd_fill_inodesin(unpackd, 0);
250} 247}
251 248
252/* 249/*
253 * Decode huffman stream, based on the huffman tree. 250 * Decode huffman stream, based on the huffman tree.
254 */ 251 */
255static void 252static void
256unpack_decode(const unpack_descriptor_t *unpackd, off_t *bytes_in) 253unpack_decode(const unpack_descriptor_t *unpackd, off_t *bytes_in)
257{ 254{
258 int thislevel, thiscode, thisbyte, inlevelindex; 255 int thislevel, thiscode, thisbyte, inlevelindex;
259 int i; 256 int i;
260 off_t bytes_out = 0; 257 off_t bytes_out = 0;
261 const char *thissymbol; /* The symbol pointer decoded from stream */ 258 const char *thissymbol; /* The symbol pointer decoded from stream */
262 259
263 /* 260 /*
264 * Decode huffman. Fetch every bytes from the file, get it 261 * Decode huffman. Fetch every bytes from the file, get it
265 * into 'thiscode' bit-by-bit, then output the symbol we got 262 * into 'thiscode' bit-by-bit, then output the symbol we got
266 * when one has been found. 263 * when one has been found.
267 * 264 *
268 * Assumption: sizeof(int) > ((max tree levels + 1) / 8). 265 * Assumption: sizeof(int) > ((max tree levels + 1) / 8).
269 * bad things could happen if not. 266 * bad things could happen if not.
270 */ 267 */
271 thislevel = 0; 268 thislevel = 0;
272 thiscode = thisbyte = 0; 269 thiscode = thisbyte = 0;
273 270
274 while ((thisbyte = fgetc(unpackd->fpIn)) != EOF) { 271 while ((thisbyte = fgetc(unpackd->fpIn)) != EOF) {
275 accepted_bytes(bytes_in, 1); 272 accepted_bytes(bytes_in, 1);
276 infile_newdata(1); 273 infile_newdata(1);
277 check_siginfo(); 274 check_siginfo();
278 275
279 /* 276 /*
280 * Split one bit from thisbyte, from highest to lowest, 277 * Split one bit from thisbyte, from highest to lowest,
281 * feed the bit into thiscode, until we got a symbol from 278 * feed the bit into thiscode, until we got a symbol from
282 * the tree. 279 * the tree.
283 */ 280 */
284 for (i = 7; i >= 0; i--) { 281 for (i = 7; i >= 0; i--) {
285 thiscode = (thiscode << 1) | ((thisbyte >> i) & 1); 282 thiscode = (thiscode << 1) | ((thisbyte >> i) & 1);
286 283
287 /* Did we got a symbol? (referencing leaf node) */ 284 /* Did we got a symbol? (referencing leaf node) */
288 if (thiscode >= unpackd->inodesin[thislevel]) { 285 if (thiscode >= unpackd->inodesin[thislevel]) {
289 inlevelindex = 286 inlevelindex =
290 thiscode - unpackd->inodesin[thislevel]; 287 thiscode - unpackd->inodesin[thislevel];
291 if (inlevelindex > unpackd->symbolsin[thislevel]) 288 if (inlevelindex > unpackd->symbolsin[thislevel])
292 maybe_errx("File corrupt"); 289 maybe_errx("File corrupt");
293 290
294 thissymbol = 291 thissymbol =
295 &(unpackd->tree[thislevel][inlevelindex]); 292 &(unpackd->tree[thislevel][inlevelindex]);
296 if ((thissymbol == unpackd->symbol_eob) && 293 if ((thissymbol == unpackd->symbol_eob) &&
297 (bytes_out == unpackd->uncompressed_size)) 294 (bytes_out == unpackd->uncompressed_size))
298 goto finished; 295 goto finished;
299 296
300 fputc((*thissymbol), unpackd->fpOut); 297 fputc((*thissymbol), unpackd->fpOut);
301 bytes_out++; 298 bytes_out++;
302 299
303 /* Prepare for next input */ 300 /* Prepare for next input */
304 thislevel = 0; thiscode = 0; 301 thislevel = 0; thiscode = 0;
305 } else { 302 } else {
306 thislevel++; 303 thislevel++;
307 if (thislevel > unpackd->treelevels) 304 if (thislevel > unpackd->treelevels)
308 maybe_errx("File corrupt"); 305 maybe_errx("File corrupt");
309 } 306 }
310 } 307 }
311 } 308 }
312 309
313finished: 310finished:
314 if (bytes_out != unpackd->uncompressed_size) 311 if (bytes_out != unpackd->uncompressed_size)
315 maybe_errx("Premature EOF"); 312 maybe_errx("Premature EOF");
316} 313}
317 314
318/* Handler for pack(1)'ed file */ 315/* Handler for pack(1)'ed file */
319static off_t 316static off_t
320unpack(int in, int out, char *pre, size_t prelen, off_t *bytes_in) 317unpack(int in, int out, char *pre, size_t prelen, off_t *bytes_in)
321{ 318{
322 unpack_descriptor_t unpackd; 319 unpack_descriptor_t unpackd;
323 320
324 unpack_parse_header(dup(in), dup(out), pre, prelen, bytes_in, &unpackd); 321 unpack_parse_header(dup(in), dup(out), pre, prelen, bytes_in, &unpackd);
325 unpack_decode(&unpackd, bytes_in); 322 unpack_decode(&unpackd, bytes_in);
326 unpack_descriptor_fini(&unpackd); 323 unpack_descriptor_fini(&unpackd);
327 324
328 /* If we reached here, the unpack was successful */ 325 /* If we reached here, the unpack was successful */
329 return (unpackd.uncompressed_size); 326 return (unpackd.uncompressed_size);
330} 327}
331 328