📄 gzip.c
字号:
/* $OpenBSD: cread.c,v 1.8 1999/02/14 20:07:46 mickey Exp $ *//* $NetBSD: cread.c,v 1.2 1997/02/04 18:38:20 thorpej Exp $ *//* * Copyright (c) 1996 * Matthias Drochner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project * by Matthias Drochner. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *//* support for compressed bootfiles(only read)replaces open(), close(), read(), lseek().original libsa open(), close(), read(), lseek() are calledas oopen(), oclose(), oread() resp. olseek().compression parts stripped from zlib:gzio.c*//* gzio.c -- IO on .gz files * Copyright (C) 1995-1996 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <unistd.h>#include <string.h>#undef _KERNEL#include <errno.h>#include <lib/libz/zlib.h>#include <gzipfs.h>#define EOF (-1) /* needed by compression code */#define zmemcpy memcpy#ifdef SAVE_MEMORY#define Z_BUFSIZE 1024#else#define Z_BUFSIZE 4096#endifstatic int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header *//* gzip flag byte */#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */#define ORIG_NAME 0x08 /* bit 3 set: original file name present */#define COMMENT 0x10 /* bit 4 set: file comment present */#define RESERVED 0xE0 /* bits 5..7: reserved */static struct sd { z_stream stream; int z_err; /* error code for last stream operation */ int z_eof; /* set if end of input file */ int fd; unsigned char *inbuf; /* input buffer */ unsigned long crc; /* crc32 of uncompressed data */ int transparent; /* 1 if input file is not a .gz file */} *ss[OPEN_MAX];#ifdef DEBUGint z_verbose = 0;#endif/* * compression utilities */void *zcalloc (void *opaque, unsigned items, unsigned size);void *zcalloc (opaque, items, size)void *opaque;unsigned items;unsigned size;{ return(malloc(items * size));}void zcfree (void *opaque, void *ptr);void zcfree (opaque, ptr)void *opaque;void *ptr;{ free(ptr); /* XXX works only with modified allocator */}static int get_HeaderByte(struct sd *s);static int get_HeaderByte(s)struct sd *s;{ if (s->z_eof) return EOF; if (s->stream.avail_in == 0) { errno = 0; s->stream.avail_in = read(s->fd, s->inbuf, 16); if (s->stream.avail_in <= 0) { s->z_eof = 1; if (errno) s->z_err = Z_ERRNO; return EOF; } s->stream.next_in = s->inbuf; } s->stream.avail_in--; return *(s->stream.next_in)++;}static int get_byte(struct sd *s);static int get_byte(s)struct sd *s;{ if (s->z_eof) return EOF; if (s->stream.avail_in == 0) { errno = 0; s->stream.avail_in = read(s->fd, s->inbuf, Z_BUFSIZE); if (s->stream.avail_in <= 0) { s->z_eof = 1; if (errno) s->z_err = Z_ERRNO; return EOF; } s->stream.next_in = s->inbuf; } s->stream.avail_in--; return *(s->stream.next_in)++;}static unsigned long getLong (struct sd *s);static unsigned long getLong (s)struct sd *s;{ unsigned long x = (unsigned long)get_byte(s); int c; x += ((unsigned long)get_byte(s))<<8; x += ((unsigned long)get_byte(s))<<16; c = get_byte(s); if (c == EOF) s->z_err = Z_DATA_ERROR; x += ((unsigned long)c)<<24; return x;}static void check_header(struct sd *s);static void check_header(s)struct sd *s;{ int method; /* method byte */ int flags; /* flags byte */ unsigned int len; int c; /* Check the gzip magic header */ for (len = 0; len < 2; len++) { c = get_HeaderByte(s); if (c != gz_magic[len]) { if (len != 0) s->stream.avail_in++, s->stream.next_in--; if (c != EOF) { s->stream.avail_in++, s->stream.next_in--; s->transparent = 1; } s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END; return; } } method = get_byte(s); flags = get_byte(s); if (method != Z_DEFLATED || (flags & RESERVED) != 0) { s->z_err = Z_DATA_ERROR; return; } /* Discard time, xflags and OS code: */ for (len = 0; len < 6; len++) (void)get_byte(s); if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ len = (unsigned int)get_byte(s); len += ((unsigned int)get_byte(s))<<8; /* len is garbage if EOF but the loop below will quit anyway */ while (len-- != 0 && get_byte(s) != EOF) ; } if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ while ((c = get_byte(s)) != 0 && c != EOF) ; } if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ while ((c = get_byte(s)) != 0 && c != EOF) ; } if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ for (len = 0; len < 2; len++) (void)get_byte(s); } s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;}/* * new open(), close(), read(), lseek() */int gz_open(int fd){ struct sd *s = 0; ss[fd] = s = malloc(sizeof(struct sd)); if(!s) goto errout; bzero(s, sizeof(struct sd));#ifdef SAVE_MEMORY if(inflateInit2(&(s->stream), -11) != Z_OK) goto errout;#else if(inflateInit2(&(s->stream), -15) != Z_OK) goto errout;#endif s->stream.next_in = s->inbuf = (unsigned char*)malloc(Z_BUFSIZE); if(!s->inbuf) { inflateEnd(&(s->stream)); goto errout; } s->fd = fd; check_header(s); /* skip the .gz header */ return(fd);errout: if(s) free(s); close(fd); return(-1);}int gz_close(fd) int fd;{ struct sd *s; if ((unsigned)fd >= OPEN_MAX) { errno = EBADF; return (-1); } s = ss[fd]; inflateEnd(&(s->stream)); free(s->inbuf); free(s); return(0);}ssize_t gz_read(fd, buf, len) int fd;void *buf;size_t len;{ struct sd *s; unsigned char *start = buf; /* starting point for crc computation */ s = ss[fd]; if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; if (s->z_err == Z_STREAM_END) return 0; /* EOF */ s->stream.next_out = buf; s->stream.avail_out = len; while (s->stream.avail_out != 0) { if (s->transparent) { /* Copy first the lookahead bytes: */ unsigned int n = s->stream.avail_in; if (n > s->stream.avail_out) n = s->stream.avail_out; if (n > 0) { zmemcpy(s->stream.next_out, s->stream.next_in, n); s->stream.next_out += n; s->stream.next_in += n; s->stream.avail_out -= n; s->stream.avail_in -= n; } if (s->stream.avail_out > 0) { int n; n = read(fd, s->stream.next_out, s->stream.avail_out); if (n <= 0) { s->z_eof = 1; if (errno) { s->z_err = Z_ERRNO; break; } } s->stream.avail_out -= n; } len -= s->stream.avail_out; s->stream.total_in += (unsigned long)len; s->stream.total_out += (unsigned long)len; if (len == 0) s->z_eof = 1; return (int)len; } if (s->stream.avail_in == 0 && !s->z_eof) { errno = 0; s->stream.avail_in = read(fd, s->inbuf, Z_BUFSIZE); if (s->stream.avail_in <= 0) { s->z_eof = 1; if (errno) { s->z_err = Z_ERRNO; break; } } s->stream.next_in = s->inbuf; } s->z_err = inflate(&(s->stream), Z_NO_FLUSH); if (s->z_err == Z_STREAM_END) { /* Check CRC and original size */ s->crc = crc32(s->crc, start, (unsigned int)(s->stream.next_out - start)); start = s->stream.next_out; if (getLong(s) != s->crc) { s->z_err = Z_DATA_ERROR; } else { (void)getLong(s); /* The uncompressed length returned by above getlong() may * be different from s->stream.total_out) in case of * concatenated .gz files. Check for such files: */ check_header(s); if (s->z_err == Z_OK) { unsigned long total_in = s->stream.total_in; unsigned long total_out = s->stream.total_out; inflateReset(&(s->stream)); s->stream.total_in = total_in; s->stream.total_out = total_out; s->crc = crc32(0L, Z_NULL, 0); } } } if (s->z_err != Z_OK || s->z_eof) break; } s->crc = crc32(s->crc, start, (unsigned int)(s->stream.next_out - start)); return (int)(len - s->stream.avail_out);}off_t gz_lseek(fd, offset, where)int fd;off_t offset;int where;{ struct sd *s; if ((unsigned)fd >= OPEN_MAX) { errno = EBADF; return (-1); } s = ss[fd]; if(s->transparent) { off_t res; res = lseek(fd, offset, where); if(res != (off_t)-1) { /* make sure the lookahead buffer is invalid */ s->stream.avail_in = 0; } return(res); } switch(where) { case SEEK_CUR: offset += s->stream.total_out; case SEEK_SET: /* if seek backwards, simply start from the beginning */ if(offset < s->stream.total_out) { off_t res; void *sav_inbuf; res = lseek(fd, 0, SEEK_SET); if(res == (off_t)-1) return(res); /* ??? perhaps fallback to close / open */ inflateEnd(&(s->stream)); sav_inbuf = s->inbuf; /* don't allocate again */ bzero(s, sizeof(struct sd)); /* this resets total_out to 0! */ inflateInit2(&(s->stream), -15); s->stream.next_in = s->inbuf = sav_inbuf; s->fd = fd; check_header(s); /* skip the .gz header */ } /* to seek forwards, throw away data */ if(offset > s->stream.total_out) { off_t toskip = offset - s->stream.total_out; while(toskip > 0) {#define DUMMYBUFSIZE 256 char dummybuf[DUMMYBUFSIZE]; off_t len = toskip; if(len > DUMMYBUFSIZE) len = DUMMYBUFSIZE; if(read(fd, dummybuf, len) != len) { errno = ESPIPE; return((off_t)-1); } toskip -= len; } }#ifdef DEBUG if(offset != s->stream.total_out) panic("lseek compressed");#endif return(offset); case SEEK_END: errno = ESPIPE; break; default: errno = EINVAL; } return((off_t)-1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -