Annotation of src/usr.bin/compress/gzopen.c, Revision 1.33
1.33 ! tedu 1: /* $OpenBSD: gzopen.c,v 1.32 2016/08/17 12:02:38 millert Exp $ */
1.1 mickey 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: *
1.5 mickey 16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1.1 mickey 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: */
1.5 mickey 60:
1.1 mickey 61: #include <sys/stat.h>
1.13 millert 62: #include <sys/uio.h>
1.1 mickey 63: #include <stdio.h>
64: #include <stdlib.h>
1.11 david 65: #include <string.h>
1.1 mickey 66: #include <errno.h>
67: #include <unistd.h>
1.28 deraadt 68: #include <limits.h>
1.1 mickey 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 */
1.30 millert 86: int z_eof; /* set if end of input file */
1.1 mickey 87: z_stream z_stream; /* libz stream */
88: u_char z_buf[Z_BUFSIZE]; /* i/o buffer */
1.30 millert 89: char z_mode; /* 'w' or 'r' */
1.13 millert 90: u_int32_t z_time; /* timestamp (mtime) */
1.30 millert 91: u_int32_t z_crc; /* crc32 of uncompressed data */
1.13 millert 92: u_int32_t z_hlen; /* length of the gz header */
1.30 millert 93: u_int64_t z_total_in; /* # bytes in */
94: u_int64_t z_total_out; /* # bytes out */
1.1 mickey 95: } gz_stream;
96:
1.5 mickey 97: static const u_char gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
1.1 mickey 98:
1.3 millert 99: static int put_int32(gz_stream *, u_int32_t);
100: static u_int32_t get_int32(gz_stream *);
1.13 millert 101: static int get_header(gz_stream *, char *, int);
1.22 mickey 102: static int put_header(gz_stream *, char *, u_int32_t, int);
1.3 millert 103: static int get_byte(gz_stream *);
1.1 mickey 104:
105: void *
1.33 ! tedu 106: gz_wopen(int fd, char *name, int bits, u_int32_t mtime)
1.1 mickey 107: {
108: gz_stream *s;
109:
1.33 ! tedu 110: if (fd < 0)
1.1 mickey 111: return NULL;
112:
1.33 ! tedu 113: if (bits < 0 || bits > Z_BEST_COMPRESSION) {
1.1 mickey 114: errno = EINVAL;
115: return NULL;
116: }
1.29 deraadt 117: if ((s = calloc(1, sizeof(gz_stream))) == NULL)
1.1 mickey 118: return NULL;
119:
120: s->z_stream.zalloc = (alloc_func)0;
121: s->z_stream.zfree = (free_func)0;
122: s->z_stream.opaque = (voidpf)0;
123: s->z_stream.next_in = Z_NULL;
124: s->z_stream.next_out = Z_NULL;
125: s->z_stream.avail_in = s->z_stream.avail_out = 0;
126: s->z_fd = 0;
127: s->z_eof = 0;
1.13 millert 128: s->z_time = 0;
129: s->z_hlen = 0;
1.30 millert 130: s->z_total_in = 0;
131: s->z_total_out = 0;
1.1 mickey 132: s->z_crc = crc32(0L, Z_NULL, 0);
1.33 ! tedu 133: s->z_mode = 'w';
1.1 mickey 134:
1.20 henning 135: #ifndef SMALL
1.33 ! tedu 136: /* windowBits is passed < 0 to suppress zlib header */
! 137: if (deflateInit2(&(s->z_stream), bits, Z_DEFLATED,
! 138: -MAX_WBITS, DEF_MEM_LEVEL, 0) != Z_OK) {
! 139: free (s);
! 140: return NULL;
! 141: }
! 142: s->z_stream.next_out = s->z_buf;
1.20 henning 143: #else
1.33 ! tedu 144: free(s);
! 145: return (NULL);
1.20 henning 146: #endif
1.33 ! tedu 147: s->z_stream.avail_out = Z_BUFSIZE;
! 148:
! 149: errno = 0;
! 150: s->z_fd = fd;
! 151:
! 152: /* write the .gz header */
! 153: if (put_header(s, name, mtime, bits) != 0) {
! 154: gz_close(s, NULL, NULL, NULL);
! 155: s = NULL;
! 156: }
! 157:
! 158: return s;
! 159: }
! 160:
! 161: void *
! 162: gz_ropen(int fd, char *name, int gotmagic)
! 163: {
! 164: gz_stream *s;
! 165:
! 166: if (fd < 0)
! 167: return NULL;
! 168:
! 169: if ((s = calloc(1, sizeof(gz_stream))) == NULL)
! 170: return NULL;
! 171:
! 172: s->z_stream.zalloc = (alloc_func)0;
! 173: s->z_stream.zfree = (free_func)0;
! 174: s->z_stream.opaque = (voidpf)0;
! 175: s->z_stream.next_in = Z_NULL;
! 176: s->z_stream.next_out = Z_NULL;
! 177: s->z_stream.avail_in = s->z_stream.avail_out = 0;
! 178: s->z_fd = 0;
! 179: s->z_eof = 0;
! 180: s->z_time = 0;
! 181: s->z_hlen = 0;
! 182: s->z_total_in = 0;
! 183: s->z_total_out = 0;
! 184: s->z_crc = crc32(0L, Z_NULL, 0);
! 185: s->z_mode = 'r';
! 186:
! 187: if (inflateInit2(&(s->z_stream), -MAX_WBITS) != Z_OK) {
! 188: free (s);
! 189: return NULL;
1.1 mickey 190: }
1.33 ! tedu 191: s->z_stream.next_in = s->z_buf;
1.1 mickey 192: s->z_stream.avail_out = Z_BUFSIZE;
193:
194: errno = 0;
195: s->z_fd = fd;
196:
1.33 ! tedu 197: /* read the .gz header */
! 198: if (get_header(s, name, gotmagic) != 0) {
! 199: gz_close(s, NULL, NULL, NULL);
! 200: s = NULL;
1.1 mickey 201: }
202:
203: return s;
204: }
205:
206: int
1.23 otto 207: gz_close(void *cookie, struct z_info *info, const char *name, struct stat *sb)
1.1 mickey 208: {
1.2 mpech 209: gz_stream *s = (gz_stream*)cookie;
1.1 mickey 210: int err = 0;
211:
212: if (s == NULL)
213: return -1;
214:
1.20 henning 215: #ifndef SMALL
1.1 mickey 216: if (s->z_mode == 'w' && (err = gz_flush (s, Z_FINISH)) == Z_OK) {
1.13 millert 217: if ((err = put_int32 (s, s->z_crc)) == Z_OK) {
218: s->z_hlen += sizeof(int32_t);
219: if ((err = put_int32 (s, s->z_stream.total_in)) == Z_OK)
220: s->z_hlen += sizeof(int32_t);
221: }
1.1 mickey 222: }
1.20 henning 223: #endif
1.1 mickey 224: if (!err && s->z_stream.state != NULL) {
225: if (s->z_mode == 'w')
1.20 henning 226: #ifndef SMALL
1.1 mickey 227: err = deflateEnd(&s->z_stream);
1.20 henning 228: #else
229: err = -1;
1.21 deraadt 230: #endif
1.1 mickey 231: else if (s->z_mode == 'r')
232: err = inflateEnd(&s->z_stream);
233: }
1.10 mickey 234:
1.13 millert 235: if (info != NULL) {
236: info->mtime = s->z_time;
237: info->crc = s->z_crc;
238: info->hlen = s->z_hlen;
1.32 millert 239: if (s->z_mode == 'r') {
240: info->total_in = s->z_total_in;
241: info->total_out = s->z_total_out;
242: } else {
243: info->total_in = s->z_stream.total_in;
244: info->total_out = s->z_stream.total_out;
245: }
246:
1.13 millert 247: }
248:
1.23 otto 249: setfile(name, s->z_fd, sb);
1.10 mickey 250: if (!err)
251: err = close(s->z_fd);
252: else
253: (void)close(s->z_fd);
1.1 mickey 254:
255: free(s);
256:
257: return err;
258: }
259:
1.20 henning 260: #ifndef SMALL
1.1 mickey 261: int
1.7 deraadt 262: gz_flush(void *cookie, int flush)
1.1 mickey 263: {
1.2 mpech 264: gz_stream *s = (gz_stream*)cookie;
1.1 mickey 265: size_t len;
266: int done = 0;
267: int err;
268:
269: if (s == NULL || s->z_mode != 'w') {
270: errno = EBADF;
271: return Z_ERRNO;
272: }
273:
274: s->z_stream.avail_in = 0; /* should be zero already anyway */
275:
276: for (;;) {
277: len = Z_BUFSIZE - s->z_stream.avail_out;
278:
279: if (len != 0) {
280: if (write(s->z_fd, s->z_buf, len) != len)
281: return Z_ERRNO;
282: s->z_stream.next_out = s->z_buf;
283: s->z_stream.avail_out = Z_BUFSIZE;
284: }
285: if (done)
286: break;
287: if ((err = deflate(&(s->z_stream), flush)) != Z_OK &&
288: err != Z_STREAM_END)
289: return err;
290:
291: /* deflate has finished flushing only when it hasn't
292: * used up all the available space in the output buffer
293: */
294: done = (s->z_stream.avail_out != 0 || err == Z_STREAM_END);
295: }
296: return 0;
297: }
1.20 henning 298: #endif
1.1 mickey 299:
300: static int
1.7 deraadt 301: put_int32(gz_stream *s, u_int32_t x)
1.1 mickey 302: {
1.8 millert 303: u_int32_t y = htole32(x);
304:
305: if (write(s->z_fd, &y, sizeof(y)) != sizeof(y))
1.1 mickey 306: return Z_ERRNO;
307: return 0;
308: }
309:
310: static int
1.7 deraadt 311: get_byte(gz_stream *s)
1.1 mickey 312: {
313: if (s->z_eof)
314: return EOF;
1.5 mickey 315:
1.1 mickey 316: if (s->z_stream.avail_in == 0) {
317: errno = 0;
318: s->z_stream.avail_in = read(s->z_fd, s->z_buf, Z_BUFSIZE);
1.24 pedro 319: if ((int)s->z_stream.avail_in <= 0) {
1.1 mickey 320: s->z_eof = 1;
321: return EOF;
322: }
323: s->z_stream.next_in = s->z_buf;
324: }
325: s->z_stream.avail_in--;
326: return *s->z_stream.next_in++;
327: }
328:
1.5 mickey 329: static u_int32_t
1.7 deraadt 330: get_int32(gz_stream *s)
1.1 mickey 331: {
1.2 mpech 332: u_int32_t x;
1.1 mickey 333:
334: x = ((u_int32_t)(get_byte(s) & 0xff));
335: x |= ((u_int32_t)(get_byte(s) & 0xff))<<8;
336: x |= ((u_int32_t)(get_byte(s) & 0xff))<<16;
337: x |= ((u_int32_t)(get_byte(s) & 0xff))<<24;
338: return x;
339: }
340:
341: static int
1.13 millert 342: get_header(gz_stream *s, char *name, int gotmagic)
1.1 mickey 343: {
344: int method; /* method byte */
345: int flags; /* flags byte */
1.13 millert 346: char *ep;
1.1 mickey 347: uInt len;
348: int c;
349:
350: /* Check the gzip magic header */
1.12 millert 351: if (!gotmagic) {
352: for (len = 0; len < 2; len++) {
353: c = get_byte(s);
354: if (c != gz_magic[len]) {
355: errno = EFTYPE;
356: return -1;
357: }
1.1 mickey 358: }
359: }
360:
361: method = get_byte(s);
362: flags = get_byte(s);
363: if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
364: errno = EFTYPE;
365: return -1;
366: }
367:
1.13 millert 368: /* Stash timestamp (mtime) */
369: s->z_time = get_int32(s);
370:
371: /* Discard xflags and OS code */
372: (void)get_byte(s);
373: (void)get_byte(s);
1.1 mickey 374:
1.30 millert 375: s->z_hlen += 10; /* magic, method, flags, time, xflags, OS code */
1.1 mickey 376: if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
377: len = (uInt)get_byte(s);
378: len += ((uInt)get_byte(s))<<8;
1.13 millert 379: s->z_hlen += 2;
1.1 mickey 380: /* len is garbage if EOF but the loop below will quit anyway */
381: while (len-- != 0 && get_byte(s) != EOF)
1.13 millert 382: s->z_hlen++;
1.1 mickey 383: }
384:
1.13 millert 385: if ((flags & ORIG_NAME) != 0) { /* read/save the original file name */
386: if ((ep = name) != NULL)
1.28 deraadt 387: ep += PATH_MAX - 1;
1.13 millert 388: while ((c = get_byte(s)) != EOF) {
389: s->z_hlen++;
390: if (c == '\0')
391: break;
392: if (name < ep)
393: *name++ = c;
394: }
395: if (name != NULL)
396: *name = '\0';
1.1 mickey 397: }
398:
399: if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
1.13 millert 400: while ((c = get_byte(s)) != EOF) {
401: s->z_hlen++;
402: if (c == '\0')
403: break;
404: }
1.1 mickey 405: }
406:
407: if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
1.14 mickey 408: (void)get_byte(s);
409: (void)get_byte(s);
1.13 millert 410: s->z_hlen += 2;
1.1 mickey 411: }
412:
413: if (s->z_eof) {
414: errno = EFTYPE;
415: return -1;
416: }
417:
418: return 0;
419: }
420:
1.13 millert 421: static int
1.22 mickey 422: put_header(gz_stream *s, char *name, u_int32_t mtime, int bits)
1.13 millert 423: {
424: struct iovec iov[2];
425: u_char buf[10];
426:
427: buf[0] = gz_magic[0];
428: buf[1] = gz_magic[1];
429: buf[2] = Z_DEFLATED;
430: buf[3] = name ? ORIG_NAME : 0;
431: buf[4] = mtime & 0xff;
432: buf[5] = (mtime >> 8) & 0xff;
433: buf[6] = (mtime >> 16) & 0xff;
434: buf[7] = (mtime >> 24) & 0xff;
1.22 mickey 435: buf[8] = bits == 1 ? 4 : bits == 9 ? 2 : 0; /* xflags */
1.13 millert 436: buf[9] = OS_CODE;
437: iov[0].iov_base = buf;
438: iov[0].iov_len = sizeof(buf);
439: s->z_hlen = sizeof(buf);
440:
441: if (name != NULL) {
442: iov[1].iov_base = name;
443: iov[1].iov_len = strlen(name) + 1;
444: s->z_hlen += iov[1].iov_len;
445: }
446: if (writev(s->z_fd, iov, name ? 2 : 1) == -1)
447: return (-1);
448: return (0);
449: }
450:
1.1 mickey 451: int
1.7 deraadt 452: gz_read(void *cookie, char *buf, int len)
1.1 mickey 453: {
1.2 mpech 454: gz_stream *s = (gz_stream*)cookie;
1.1 mickey 455: u_char *start = buf; /* starting point for crc computation */
1.17 millert 456: int error = Z_OK;
1.1 mickey 457:
458: s->z_stream.next_out = buf;
459: s->z_stream.avail_out = len;
460:
1.17 millert 461: while (error == Z_OK && !s->z_eof && s->z_stream.avail_out != 0) {
1.1 mickey 462:
463: if (s->z_stream.avail_in == 0) {
464:
465: errno = 0;
1.24 pedro 466: s->z_stream.avail_in = read(s->z_fd, s->z_buf,
467: Z_BUFSIZE);
468: if ((int)s->z_stream.avail_in <= 0)
1.1 mickey 469: s->z_eof = 1;
470: s->z_stream.next_in = s->z_buf;
471: }
472:
1.17 millert 473: error = inflate(&(s->z_stream), Z_NO_FLUSH);
1.25 mpf 474:
475: if (error == Z_DATA_ERROR) {
476: errno = EINVAL;
1.30 millert 477: goto bad;
1.25 mpf 478: }
479: if (error == Z_BUF_ERROR) {
480: errno = EIO;
1.30 millert 481: goto bad;
1.25 mpf 482: }
1.17 millert 483: if (error == Z_STREAM_END) {
1.1 mickey 484: /* Check CRC and original size */
485: s->z_crc = crc32(s->z_crc, start,
1.7 deraadt 486: (uInt)(s->z_stream.next_out - start));
1.1 mickey 487: start = s->z_stream.next_out;
488:
1.9 millert 489: if (get_int32(s) != s->z_crc) {
490: errno = EINVAL;
1.30 millert 491: goto bad;
1.9 millert 492: }
1.18 henning 493: if (get_int32(s) != (u_int32_t)s->z_stream.total_out) {
1.7 deraadt 494: errno = EIO;
1.1 mickey 495: return -1;
496: }
1.13 millert 497: s->z_hlen += 2 * sizeof(int32_t);
1.30 millert 498:
499: /* Add byte counts from the finished stream. */
500: s->z_total_in += s->z_stream.total_in;
501: s->z_total_out += s->z_stream.total_out;
502:
1.16 millert 503: /* Check for the existence of an appended file. */
504: if (get_header(s, NULL, 0) != 0) {
505: s->z_eof = 1;
506: break;
507: }
508: inflateReset(&(s->z_stream));
509: s->z_crc = crc32(0L, Z_NULL, 0);
1.17 millert 510: error = Z_OK;
1.1 mickey 511: }
512: }
513: s->z_crc = crc32(s->z_crc, start,
1.7 deraadt 514: (uInt)(s->z_stream.next_out - start));
1.15 millert 515: len -= s->z_stream.avail_out;
516:
517: return (len);
1.30 millert 518: bad:
519: /* Add byte counts from the finished stream. */
520: s->z_total_in += s->z_stream.total_in;
521: s->z_total_out += s->z_stream.total_out;
522: return (-1);
1.1 mickey 523: }
524:
525: int
1.7 deraadt 526: gz_write(void *cookie, const char *buf, int len)
1.1 mickey 527: {
1.20 henning 528: #ifndef SMALL
1.2 mpech 529: gz_stream *s = (gz_stream*)cookie;
1.1 mickey 530:
531: s->z_stream.next_in = (char *)buf;
532: s->z_stream.avail_in = len;
533:
534: while (s->z_stream.avail_in != 0) {
535: if (s->z_stream.avail_out == 0) {
536: if (write(s->z_fd, s->z_buf, Z_BUFSIZE) != Z_BUFSIZE)
537: break;
538: s->z_stream.next_out = s->z_buf;
539: s->z_stream.avail_out = Z_BUFSIZE;
540: }
541: if (deflate(&(s->z_stream), Z_NO_FLUSH) != Z_OK)
542: break;
543: }
544: s->z_crc = crc32(s->z_crc, buf, len);
545:
546: return (int)(len - s->z_stream.avail_in);
1.20 henning 547: #endif
1.1 mickey 548: }