GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/compress/gzopen.c Lines: 119 235 50.6 %
Date: 2016-12-06 Branches: 53 146 36.3 %

Line Branch Exec Source
1
/*	$OpenBSD: gzopen.c,v 1.31 2016/04/29 13:50:35 millert Exp $	*/
2
3
/*
4
 * Copyright (c) 1997 Michael Shalayeff
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 */
29
/* this is partially derived from the zlib's gzio.c file, so the notice: */
30
/*
31
  zlib.h -- interface of the 'zlib' general purpose compression library
32
  version 1.0.4, Jul 24th, 1996.
33
34
  Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler
35
36
  This software is provided 'as-is', without any express or implied
37
  warranty.  In no event will the authors be held liable for any damages
38
  arising from the use of this software.
39
40
  Permission is granted to anyone to use this software for any purpose,
41
  including commercial applications, and to alter it and redistribute it
42
  freely, subject to the following restrictions:
43
44
  1. The origin of this software must not be misrepresented; you must not
45
     claim that you wrote the original software. If you use this software
46
     in a product, an acknowledgment in the product documentation would be
47
     appreciated but is not required.
48
  2. Altered source versions must be plainly marked as such, and must not be
49
     misrepresented as being the original software.
50
  3. This notice may not be removed or altered from any source distribution.
51
52
  Jean-loup Gailly        Mark Adler
53
  gzip@prep.ai.mit.edu    madler@alumni.caltech.edu
54
55
56
  The data format used by the zlib library is described by RFCs (Request for
57
  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
58
  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
59
*/
60
61
#include <sys/stat.h>
62
#include <sys/uio.h>
63
#include <stdio.h>
64
#include <stdlib.h>
65
#include <string.h>
66
#include <errno.h>
67
#include <unistd.h>
68
#include <limits.h>
69
#include <zlib.h>
70
#include "compress.h"
71
72
/* gzip flag byte */
73
#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
74
#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
75
#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
76
#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
77
#define COMMENT      0x10 /* bit 4 set: file comment present */
78
#define RESERVED     0xE0 /* bits 5..7: reserved */
79
80
#define DEF_MEM_LEVEL 8
81
#define OS_CODE 0x03 /* unix */
82
83
typedef
84
struct gz_stream {
85
	int	z_fd;		/* .gz file */
86
	int	z_eof;		/* set if end of input file */
87
	z_stream z_stream;	/* libz stream */
88
	u_char	z_buf[Z_BUFSIZE]; /* i/o buffer */
89
	char	z_mode;		/* 'w' or 'r' */
90
	u_int32_t z_time;	/* timestamp (mtime) */
91
	u_int32_t z_crc;	/* crc32 of uncompressed data */
92
	u_int32_t z_hlen;	/* length of the gz header */
93
	u_int64_t z_total_in;	/* # bytes in */
94
	u_int64_t z_total_out;	/* # bytes out */
95
} gz_stream;
96
97
static const u_char gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
98
99
static int put_int32(gz_stream *, u_int32_t);
100
static u_int32_t get_int32(gz_stream *);
101
static int get_header(gz_stream *, char *, int);
102
static int put_header(gz_stream *, char *, u_int32_t, int);
103
static int get_byte(gz_stream *);
104
105
void *
106
gz_open(int fd, const char *mode, char *name, int bits,
107
    u_int32_t mtime, int gotmagic)
108
3
{
109
	gz_stream *s;
110
111
3
	if (fd < 0 || !mode)
112
		return NULL;
113
114

3
	if ((mode[0] != 'r' && mode[0] != 'w') || mode[1] != '\0' ||
115
	    bits < 0 || bits > Z_BEST_COMPRESSION) {
116
		errno = EINVAL;
117
		return NULL;
118
	}
119
3
	if ((s = calloc(1, sizeof(gz_stream))) == NULL)
120
		return NULL;
121
122
3
	s->z_stream.zalloc = (alloc_func)0;
123
3
	s->z_stream.zfree = (free_func)0;
124
3
	s->z_stream.opaque = (voidpf)0;
125
3
	s->z_stream.next_in = Z_NULL;
126
3
	s->z_stream.next_out = Z_NULL;
127
3
	s->z_stream.avail_in = s->z_stream.avail_out = 0;
128
3
	s->z_fd = 0;
129
3
	s->z_eof = 0;
130
3
	s->z_time = 0;
131
3
	s->z_hlen = 0;
132
3
	s->z_total_in = 0;
133
3
	s->z_total_out = 0;
134
3
	s->z_crc = crc32(0L, Z_NULL, 0);
135
3
	s->z_mode = mode[0];
136
137
3
	if (s->z_mode == 'w') {
138
#ifndef SMALL
139
		/* windowBits is passed < 0 to suppress zlib header */
140
		if (deflateInit2(&(s->z_stream), bits, Z_DEFLATED,
141
				 -MAX_WBITS, DEF_MEM_LEVEL, 0) != Z_OK) {
142
			free (s);
143
			return NULL;
144
		}
145
		s->z_stream.next_out = s->z_buf;
146
#else
147
		free(s);
148
		return (NULL);
149
#endif
150
	} else {
151
3
		if (inflateInit2(&(s->z_stream), -MAX_WBITS) != Z_OK) {
152
			free (s);
153
			return NULL;
154
		}
155
3
		s->z_stream.next_in = s->z_buf;
156
	}
157
3
	s->z_stream.avail_out = Z_BUFSIZE;
158
159
3
	errno = 0;
160
3
	s->z_fd = fd;
161
162
3
	if (s->z_mode == 'w') {
163
		/* write the .gz header */
164
		if (put_header(s, name, mtime, bits) != 0) {
165
			gz_close(s, NULL, NULL, NULL);
166
			s = NULL;
167
		}
168
	} else {
169
		/* read the .gz header */
170
3
		if (get_header(s, name, gotmagic) != 0) {
171
			gz_close(s, NULL, NULL, NULL);
172
			s = NULL;
173
		}
174
	}
175
176
3
	return s;
177
}
178
179
int
180
gz_close(void *cookie, struct z_info *info, const char *name, struct stat *sb)
181
3
{
182
3
	gz_stream *s = (gz_stream*)cookie;
183
3
	int err = 0;
184
185
3
	if (s == NULL)
186
		return -1;
187
188
#ifndef SMALL
189

3
	if (s->z_mode == 'w' && (err = gz_flush (s, Z_FINISH)) == Z_OK) {
190
		if ((err = put_int32 (s, s->z_crc)) == Z_OK) {
191
			s->z_hlen += sizeof(int32_t);
192
			if ((err = put_int32 (s, s->z_stream.total_in)) == Z_OK)
193
				s->z_hlen += sizeof(int32_t);
194
		}
195
	}
196
#endif
197

3
	if (!err && s->z_stream.state != NULL) {
198
3
		if (s->z_mode == 'w')
199
#ifndef SMALL
200
			err = deflateEnd(&s->z_stream);
201
#else
202
			err = -1;
203
#endif
204
3
		else if (s->z_mode == 'r')
205
3
			err = inflateEnd(&s->z_stream);
206
	}
207
208
3
	if (info != NULL) {
209
3
		info->mtime = s->z_time;
210
3
		info->crc = s->z_crc;
211
3
		info->hlen = s->z_hlen;
212
3
		info->total_in = s->z_total_in;
213
3
		info->total_out = s->z_total_out;
214
	}
215
216
3
	setfile(name, s->z_fd, sb);
217
3
	if (!err)
218
3
		err = close(s->z_fd);
219
	else
220
		(void)close(s->z_fd);
221
222
3
	free(s);
223
224
3
	return err;
225
}
226
227
#ifndef SMALL
228
int
229
gz_flush(void *cookie, int flush)
230
{
231
	gz_stream *s = (gz_stream*)cookie;
232
	size_t len;
233
	int done = 0;
234
	int err;
235
236
	if (s == NULL || s->z_mode != 'w') {
237
		errno = EBADF;
238
		return Z_ERRNO;
239
	}
240
241
	s->z_stream.avail_in = 0; /* should be zero already anyway */
242
243
	for (;;) {
244
		len = Z_BUFSIZE - s->z_stream.avail_out;
245
246
		if (len != 0) {
247
			if (write(s->z_fd, s->z_buf, len) != len)
248
				return Z_ERRNO;
249
			s->z_stream.next_out = s->z_buf;
250
			s->z_stream.avail_out = Z_BUFSIZE;
251
		}
252
		if (done)
253
			break;
254
		if ((err = deflate(&(s->z_stream), flush)) != Z_OK &&
255
		    err != Z_STREAM_END)
256
			return err;
257
258
		/* deflate has finished flushing only when it hasn't
259
		 * used up all the available space in the output buffer
260
		 */
261
		done = (s->z_stream.avail_out != 0 || err == Z_STREAM_END);
262
	}
263
	return 0;
264
}
265
#endif
266
267
static int
268
put_int32(gz_stream *s, u_int32_t x)
269
{
270
	u_int32_t y = htole32(x);
271
272
	if (write(s->z_fd, &y, sizeof(y)) != sizeof(y))
273
		return Z_ERRNO;
274
	return 0;
275
}
276
277
static int
278
get_byte(gz_stream *s)
279
68
{
280
68
	if (s->z_eof)
281
		return EOF;
282
283
68
	if (s->z_stream.avail_in == 0) {
284
6
		errno = 0;
285
6
		s->z_stream.avail_in = read(s->z_fd, s->z_buf, Z_BUFSIZE);
286
6
		if ((int)s->z_stream.avail_in <= 0) {
287
3
			s->z_eof = 1;
288
3
			return EOF;
289
		}
290
3
		s->z_stream.next_in = s->z_buf;
291
	}
292
65
	s->z_stream.avail_in--;
293
65
	return *s->z_stream.next_in++;
294
}
295
296
static u_int32_t
297
get_int32(gz_stream *s)
298
9
{
299
	u_int32_t x;
300
301
9
	x  = ((u_int32_t)(get_byte(s) & 0xff));
302
9
	x |= ((u_int32_t)(get_byte(s) & 0xff))<<8;
303
9
	x |= ((u_int32_t)(get_byte(s) & 0xff))<<16;
304
9
	x |= ((u_int32_t)(get_byte(s) & 0xff))<<24;
305
9
	return x;
306
}
307
308
static int
309
get_header(gz_stream *s, char *name, int gotmagic)
310
6
{
311
	int method; /* method byte */
312
	int flags;  /* flags byte */
313
	char *ep;
314
	uInt len;
315
	int c;
316
317
	/* Check the gzip magic header */
318
6
	if (!gotmagic) {
319
3
		for (len = 0; len < 2; len++) {
320
3
			c = get_byte(s);
321
3
			if (c != gz_magic[len]) {
322
3
				errno = EFTYPE;
323
3
				return -1;
324
			}
325
		}
326
	}
327
328
3
	method = get_byte(s);
329
3
	flags = get_byte(s);
330

3
	if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
331
		errno = EFTYPE;
332
		return -1;
333
	}
334
335
	/* Stash timestamp (mtime) */
336
3
	s->z_time = get_int32(s);
337
338
	/* Discard xflags and OS code */
339
3
	(void)get_byte(s);
340
3
	(void)get_byte(s);
341
342
3
	s->z_hlen += 10; /* magic, method, flags, time, xflags, OS code */
343
3
	if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
344
		len  =  (uInt)get_byte(s);
345
		len += ((uInt)get_byte(s))<<8;
346
		s->z_hlen += 2;
347
		/* len is garbage if EOF but the loop below will quit anyway */
348
		while (len-- != 0 && get_byte(s) != EOF)
349
			s->z_hlen++;
350
	}
351
352
3
	if ((flags & ORIG_NAME) != 0) { /* read/save the original file name */
353
2
		if ((ep = name) != NULL)
354
2
			ep += PATH_MAX - 1;
355
17
		while ((c = get_byte(s)) != EOF) {
356
17
			s->z_hlen++;
357
17
			if (c == '\0')
358
2
				break;
359
15
			if (name < ep)
360
15
				*name++ = c;
361
		}
362
2
		if (name != NULL)
363
2
			*name = '\0';
364
	}
365
366
3
	if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
367
		while ((c = get_byte(s)) != EOF) {
368
			s->z_hlen++;
369
			if (c == '\0')
370
				break;
371
		}
372
	}
373
374
3
	if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
375
		(void)get_byte(s);
376
		(void)get_byte(s);
377
		s->z_hlen += 2;
378
	}
379
380
3
	if (s->z_eof) {
381
		errno = EFTYPE;
382
		return -1;
383
	}
384
385
3
	return 0;
386
}
387
388
static int
389
put_header(gz_stream *s, char *name, u_int32_t mtime, int bits)
390
{
391
	struct iovec iov[2];
392
	u_char buf[10];
393
394
	buf[0] = gz_magic[0];
395
	buf[1] = gz_magic[1];
396
	buf[2] = Z_DEFLATED;
397
	buf[3] = name ? ORIG_NAME : 0;
398
	buf[4] = mtime & 0xff;
399
	buf[5] = (mtime >> 8) & 0xff;
400
	buf[6] = (mtime >> 16) & 0xff;
401
	buf[7] = (mtime >> 24) & 0xff;
402
	buf[8] = bits == 1 ? 4 : bits == 9 ? 2 : 0;	/* xflags */
403
	buf[9] = OS_CODE;
404
	iov[0].iov_base = buf;
405
	iov[0].iov_len = sizeof(buf);
406
	s->z_hlen = sizeof(buf);
407
408
	if (name != NULL) {
409
		iov[1].iov_base = name;
410
		iov[1].iov_len = strlen(name) + 1;
411
		s->z_hlen += iov[1].iov_len;
412
	}
413
	if (writev(s->z_fd, iov, name ? 2 : 1) == -1)
414
		return (-1);
415
	return (0);
416
}
417
418
int
419
gz_read(void *cookie, char *buf, int len)
420
7
{
421
7
	gz_stream *s = (gz_stream*)cookie;
422
7
	u_char *start = buf; /* starting point for crc computation */
423
7
	int error = Z_OK;
424
425
7
	s->z_stream.next_out = buf;
426
7
	s->z_stream.avail_out = len;
427
428

15
	while (error == Z_OK && !s->z_eof && s->z_stream.avail_out != 0) {
429
430
4
		if (s->z_stream.avail_in == 0) {
431
432
			errno = 0;
433
			s->z_stream.avail_in = read(s->z_fd, s->z_buf,
434
			    Z_BUFSIZE);
435
			if ((int)s->z_stream.avail_in <= 0)
436
				s->z_eof = 1;
437
			s->z_stream.next_in = s->z_buf;
438
		}
439
440
4
		error = inflate(&(s->z_stream), Z_NO_FLUSH);
441
442
4
		if (error == Z_DATA_ERROR) {
443
			errno = EINVAL;
444
			goto bad;
445
		}
446
4
		if (error == Z_BUF_ERROR) {
447
			errno = EIO;
448
			goto bad;
449
		}
450
4
		if (error == Z_STREAM_END) {
451
			/* Check CRC and original size */
452
3
			s->z_crc = crc32(s->z_crc, start,
453
			    (uInt)(s->z_stream.next_out - start));
454
3
			start = s->z_stream.next_out;
455
456
3
			if (get_int32(s) != s->z_crc) {
457
				errno = EINVAL;
458
				goto bad;
459
			}
460
3
			if (get_int32(s) != (u_int32_t)s->z_stream.total_out) {
461
				errno = EIO;
462
				return -1;
463
			}
464
3
			s->z_hlen += 2 * sizeof(int32_t);
465
466
			/* Add byte counts from the finished stream. */
467
3
			s->z_total_in += s->z_stream.total_in;
468
3
			s->z_total_out += s->z_stream.total_out;
469
470
			/* Check for the existence of an appended file. */
471
3
			if (get_header(s, NULL, 0) != 0) {
472
3
				s->z_eof = 1;
473
3
				break;
474
			}
475
			inflateReset(&(s->z_stream));
476
			s->z_crc = crc32(0L, Z_NULL, 0);
477
			error = Z_OK;
478
		}
479
	}
480
7
	s->z_crc = crc32(s->z_crc, start,
481
	    (uInt)(s->z_stream.next_out - start));
482
7
	len -= s->z_stream.avail_out;
483
484
7
	return (len);
485
bad:
486
	/* Add byte counts from the finished stream. */
487
	s->z_total_in += s->z_stream.total_in;
488
	s->z_total_out += s->z_stream.total_out;
489
	return (-1);
490
}
491
492
int
493
gz_write(void *cookie, const char *buf, int len)
494
{
495
#ifndef SMALL
496
	gz_stream *s = (gz_stream*)cookie;
497
498
	s->z_stream.next_in = (char *)buf;
499
	s->z_stream.avail_in = len;
500
501
	while (s->z_stream.avail_in != 0) {
502
		if (s->z_stream.avail_out == 0) {
503
			if (write(s->z_fd, s->z_buf, Z_BUFSIZE) != Z_BUFSIZE)
504
				break;
505
			s->z_stream.next_out = s->z_buf;
506
			s->z_stream.avail_out = Z_BUFSIZE;
507
		}
508
		if (deflate(&(s->z_stream), Z_NO_FLUSH) != Z_OK)
509
			break;
510
	}
511
	s->z_crc = crc32(s->z_crc, buf, len);
512
	s->z_total_in += s->z_stream.total_in;
513
	s->z_total_out += s->z_stream.total_out;
514
515
	return (int)(len - s->z_stream.avail_in);
516
#endif
517
}