The magic code to uncompress a kernel.

Reviewed by:	phk
Obtained from:	Linux via 386BSD.
This commit is contained in:
Poul-Henning Kamp 1995-04-15 08:23:55 +00:00
parent 3e4ece9108
commit 7970b29866
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=7845
8 changed files with 923 additions and 0 deletions

View file

@ -0,0 +1,23 @@
# $Id$
PROG= kzip.o
SRCS= head.S boot.c unzip.c misc.c malloc.c inflate.c
BINDIR= /usr/lib
.PATH: ${.CURDIR}/../../../kern
NOMAN= toobad
# Where to load the kernel
KADDR = 0x100000
# What segment our code lives in
CSEG = 0x8
STRIP= # very important!! don't let kzip.o be stripped
CFLAGS+= -DKADDR=$(KADDR) -DCSEG=$(CSEG)
CFLAGS+= -DUSE_KERNEL_INFLATE -DKZIP -DCOMCONSOLE=0x3F8
kzip.o: ${OBJS}
$(LD) -r -x -o kzip.o $(OBJS)
.include <bsd.prog.mk>

View file

@ -0,0 +1,49 @@
/* Beware: mostly obsolete info */
This is the first (alpha) release of kernel packer/unpacker
for FreeBSD. It is based on xBoot from Linux, but
hardly rewritten.
It assumes that:
1) The kernel should be loaded at 0x100000 phys address.
2) The CS selector is equal to 8, which is OK for all
current secondary boot programs.
Run "make install" to install it. It will place
"kzip" shell script into /usr/sbin, and several files
into /usr/libexec/kzip directory.
Then try to zip your kernel, for example:
% kzip /kernel
System size is 462848
Compressed size 247027
It will create file /kernel.kz:
% ls -l /kernel /kernel.kz
-rwxr-xr-x 1 root 497297 Oct 8 12:41 /386bsd
-rwxrwxr-x 1 root 262144 Oct 8 13:37 /386bsd.kz
Then rename /kernel.kz to /kernel and reboot.
% mv /kernel /o3kernel
% mv /kernel.kz /kernel
% sync
% reboot
During booting, you will see the message:
Uncompressing kernel...done
Booting the kernel
The packed kernel should load and run.
The main problem with packed kernel is the lack of symbol table,
so all commands that require it, will not run.
Among them: ps, savecore, *stat, etc.
Packed kernels are good for install and fixit floppies.
Serge Vakulenko, <vak@zebub.msk.su>
Opdated for FreeBSD 2.1 by Gary Jennejohn 12FEB95

View file

@ -0,0 +1,142 @@
/*
* FreeBSD kernel unpacker.
* 1993 by Serge Vakulenko
* modified for FreeBSD 2.1 by Gary Jennejohn - 12FEB95
*/
#include <machine/cpufunc.h> /* for inb/outb */
#include <sys/reboot.h> /* for RB_SERIAL */
short *videomem;
int curs;
int cols;
int lines;
unsigned int port;
unsigned char bios[0x100];
extern int end, edata;
void decompress_kernel (void *dest);
#if 0
inline void outb (unsigned short x, unsigned char y)
{
asm volatile ("outb %0, %1" : : "a" (y) , "d" (x));
}
inline unsigned char inb (unsigned short x, unsigned char y)
{
asm volatile ("inb %0, %1" : : "a" (y) , "d" (x));
}
#endif
int memcmp (const void *arg1, const void *arg2, unsigned len)
{
unsigned char *a = (unsigned char*) arg1;
unsigned char *b = (unsigned char*) arg2;
for (; len-- > 0; ++a, ++b)
if (*a < *b)
return (-1);
else if (*a > *b)
return (1);
return (0);
}
void *memcpy (void *to, const void *from, unsigned len)
{
char *f = (char*) from;
char *t = (char*) to;
while (len-- > 0)
*t++ = *f++;
return (to);
}
void serial_putchar (unsigned char c)
{
unsigned char stat;
do {
stat = inb (COMCONSOLE+5);
} while (stat & 0x20);
outb (COMCONSOLE, c);
}
void putchar (unsigned char c)
{
switch (c) {
case '\n': curs = (curs + cols) / cols * cols; break;
default: videomem[curs++] = 0x0700 | c; break;
}
while (curs >= cols*lines) {
memcpy (videomem, videomem+cols, (lines-1) * cols * 2);
curs -= cols;
}
/* set cursor position */
outb (port, 0x0e); outb (port+1, curs>>8);
outb (port, 0x0f); outb (port+1, curs);
}
int use_serial;
void putstr (char *s)
{
while (*s) {
if (use_serial)
serial_putchar (*s++);
else
putchar (*s++);
}
}
void error (char *s)
{
putstr ("\n\n");
putstr (s);
putstr ("\n\n -- System halted");
while (1); /* Halt */
}
void boot (int howto)
{
int l, c, *p;
/* clear bss */
for (p = &edata; p < &end; ++p)
*p = 0;
if (!(use_serial = (howto & RB_SERIAL))) {
/* Test for monochrome video adapter */
if ((*((unsigned char*) 0x410) & 0x30) == 0x30)
videomem = (void*) 0xb0000; /* monochrome */
else
videomem = (void*) 0xb8000; /* color */
port = *(unsigned short*) 0x463;
cols = *(unsigned short*) 0x44a;
lines = 1 + *(unsigned char*) 0x484;
c = *(unsigned char*) 0x450;
l = *(unsigned char*) 0x451;
if (lines < 25)
lines = 25;
curs = l*cols + c;
if (curs > lines*cols)
curs = (lines-1) * cols;
}
/* save bios area */
memcpy (bios, (void*) 0x400, sizeof (bios));
putstr ("Uncompressing kernel...");
decompress_kernel ((void*) KADDR);
putstr ("done\n");
/* restore bios area */
memcpy ((void*) 0x400, bios, sizeof (bios));
putstr ("Booting the kernel\n");
}

View file

@ -0,0 +1,84 @@
/*
* gzip.h -- common declarations for all gzip modules
* Copyright (C) 1992-1993 Jean-loup Gailly.
* Adapted for FreeBSD boot unpacker by Serge Vakulenko.
* This is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, see the file COPYING.
*/
typedef unsigned char uchar;
#ifndef USE_KERNEL_INFLATE
typedef unsigned short ushort;
#endif
typedef unsigned long ulong;
#define NULL 0
#define STORED 0 /* Compression methods */
#define COMPRESSED 1
#define PACKED 2
#define DEFLATED 8 /* methods 3 to 7 reserved */
#define INBUFSIZ 0x8000 /* input buffer size */
#define OUTBUFSIZ 16384 /* output buffer size */
#define OUTBUF_EXTRA 2048 /* required by unlzw() */
#define GZIP_MAGIC "\037\213" /* gzip files, 1F 8B */
#define OLD_GZIP_MAGIC "\037\236" /* gzip 0.5 = freeze 1.x */
#define PKZIP_MAGIC "PK\003\004" /* pkzip files */
#define PACK_MAGIC "\037\036" /* packed files */
#define LZW_MAGIC "\037\235" /* lzw files, 1F 9D */
/* gzip flag byte */
#define ASCII_FLAG 0x01 /* file probably ascii text */
#define CONTINUATION 0x02 /* cont. of multi-part gzip file */
#define EXTRA_FIELD 0x04 /* extra field present */
#define ORIG_NAME 0x08 /* original file name present */
#define COMMENT 0x10 /* file comment present */
#define ENCRYPTED 0x20 /* file is encrypted */
#define RESERVED 0xC0 /* reserved */
/* window size--must be a power of two, and */
/* at least 32K for zip's deflate method */
#define WSIZE 0x8000
extern int method; /* compression method */
extern uchar inbuf[]; /* input buffer */
extern uchar outbuf[]; /* output buffer */
extern uchar window[]; /* Sliding window and suffix table (unlzw) */
extern unsigned insize; /* valid bytes in inbuf */
extern unsigned inptr; /* index of next byte to be processed in inbuf */
extern unsigned outcnt; /* bytes in output buffer */
extern int pkzip; /* set for a pkzip file */
extern int extended; /* set if extended local header */
extern ulong crc; /* shift register contents */
extern ulong output_ptr; /* total output bytes */
extern void unzip (void);
extern void check_zipfile (void);
extern void updcrc (uchar *s, unsigned n);
extern void clear_bufs (void);
extern void fill_inbuf (void);
extern void flush_window (void);
extern void error (char *m);
#ifndef USE_KERNEL_INFLATE
extern int inflate (void);
#endif
static inline uchar get_byte ()
{
if (inptr >= insize)
fill_inbuf ();
return (inbuf[inptr++]);
}
static inline void put_char (uchar c)
{
window[outcnt++] = c;
if (outcnt == WSIZE)
flush_window();
}

View file

@ -0,0 +1,10 @@
/*
* Boot unpacker startup routine.
* Copyright (C) Serge Vakulenko
*/
.text
start:
cli # disable interrupts
call _boot # unpack the kernel image
ljmp $CSEG, $KADDR # jump to unpacked kernel
. = start + 0x500 # skip over warm boot shit

View file

@ -0,0 +1,229 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. 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 by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*/
/*
* malloc.c (Caltech) 2/21/82
* Chris Kingsley, kingsley@cit-20.
*
* This is a very fast storage allocator. It allocates blocks of a small
* number of different sizes, and keeps free lists of each size. Blocks that
* don't exactly fit are passed up to the next larger size. In this
* implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
* This is designed for use in a virtual memory environment.
*
* Modified for stand-alone use (for kzip) by Gary Jennejohn - 12FEB95
*/
#ifdef USE_KERNEL_INFLATE
#include <sys/types.h>
#define NULL 0
/*
* The overhead on a block is at least 4 bytes. When free, this space
* contains a pointer to the next free block, and the bottom two bits must
* be zero. When in use, the first byte is set to MAGIC, and the second
* byte is the size index. The remaining bytes are for alignment.
* If range checking is enabled then a second word holds the size of the
* requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
* The order of elements is critical: ov_magic must overlay the low order
* bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
*/
union overhead {
union overhead *ov_next; /* when free */
struct {
u_char ovu_magic; /* magic number */
u_char ovu_index; /* bucket # */
} ovu;
#define ov_magic ovu.ovu_magic
#define ov_index ovu.ovu_index
#define ov_rmagic ovu.ovu_rmagic
#define ov_size ovu.ovu_size
};
#define MAGIC 0xef /* magic # on accounting info */
#define RMAGIC 0x5555 /* magic # on range info */
#define RSLOP 0
/*
* nextf[i] is the pointer to the next free block of size 2^(i+3). The
* smallest allocatable block is 8 bytes. The overhead information
* precedes the data area returned to the user.
*/
#define NBUCKETS 30
static union overhead *nextf[NBUCKETS];
static int pagesz; /* page size */
static int pagebucket; /* page size bucket */
#define STORAGE 40960 /* must be at least this big to handle GENERIC */
unsigned char storage [STORAGE];
int next_free; /* need this to emulate sbrk() */
#define ASSERT(p)
static void morecore (int);
void *
malloc(nbytes, junk1, junk2) /* junk? not used */
size_t nbytes;
int junk1, junk2;
{
register union overhead *op;
register int bucket, n;
register unsigned amt;
/*
* First time malloc is called, setup page size and
* align break pointer so all data will be page aligned.
*/
if (pagesz == 0) {
pagesz = n = 4096;
op = (union overhead *)storage;
n = n - sizeof (*op) - ((int)op & (n - 1));
if (n < 0)
n += pagesz;
if (n > STORAGE)
return (NULL);
next_free = n;
bucket = 0;
amt = 8;
while (pagesz > amt) {
amt <<= 1;
bucket++;
}
pagebucket = bucket;
}
/*
* Convert amount of memory requested into closest block size
* stored in hash buckets which satisfies request.
* Account for space used per block for accounting.
*/
if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
amt = 8; /* size of first bucket */
bucket = 0;
n = -(sizeof (*op) + RSLOP);
} else {
amt = pagesz;
bucket = pagebucket;
}
while (nbytes > amt + n) {
amt <<= 1;
if (amt == 0)
return (NULL);
bucket++;
}
/*
* If nothing in hash bucket right now,
* request more memory from the system.
*/
if ((op = nextf[bucket]) == NULL) {
morecore(bucket);
if ((op = nextf[bucket]) == NULL)
return (NULL);
}
/* remove from linked list */
nextf[bucket] = op->ov_next;
op->ov_magic = MAGIC;
op->ov_index = bucket;
return ((char *)(op + 1));
}
/*
* Allocate more memory to the indicated bucket.
*/
static void
morecore(bucket)
int bucket;
{
register union overhead *op;
register int sz; /* size of desired block */
int amt; /* amount to allocate */
int nblks; /* how many blocks we get */
/*
* sbrk_size <= 0 only for big, FLUFFY, requests (about
* 2^30 bytes on a VAX, I think) or for a negative arg.
*/
sz = 1 << (bucket + 3);
if (sz <= 0)
return;
if (sz < pagesz) {
amt = pagesz;
nblks = amt / sz;
} else {
amt = sz + pagesz;
nblks = 1;
}
/* no more room! */
if (amt > (STORAGE - next_free))
return;
op = (union overhead *)&storage [next_free];
next_free += amt;
/*
* Add new memory allocated to that on
* free list for this hash bucket.
*/
nextf[bucket] = op;
while (--nblks > 0) {
op->ov_next = (union overhead *)((caddr_t)op + sz);
op = (union overhead *)((caddr_t)op + sz);
}
}
void
free(cp, junk) /* junk not used */
void *cp;
int junk;
{
register int size;
register union overhead *op;
if (cp == NULL)
return;
op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
if (op->ov_magic != MAGIC)
return; /* sanity */
size = op->ov_index;
ASSERT(size < NBUCKETS);
op->ov_next = nextf[size]; /* also clobbers ov_magic */
nextf[size] = op;
}
#endif /* USE_KERNEL_INFLATE */

View file

@ -0,0 +1,211 @@
/*
* misc.c
*
* This is a collection of several routines from gzip-1.0.3
* adapted for Linux.
*
* Ported to 386bsd by Serge Vakulenko
*/
#include "gzip.h"
uchar inbuf [INBUFSIZ];
uchar outbuf [OUTBUFSIZ+OUTBUF_EXTRA];
uchar window [WSIZE];
unsigned outcnt;
unsigned insize;
unsigned inptr;
extern const char input_data[];
extern const int input_len;
int input_ptr;
int method;
char *output_data;
ulong output_ptr;
void makecrc (void);
void putstr (char *c);
void *memcpy (void *to, const void *from, unsigned len);
int memcmp (const void *arg1, const void *arg2, unsigned len);
ulong crc; /* shift register contents */
ulong crc_32_tab[256]; /* crc table, defined below */
/*
* Run a set of bytes through the crc shift register. If s is a NULL
* pointer, then initialize the crc shift register contents instead.
* Return the current crc in either case.
*/
void updcrc(s, n)
uchar *s; /* pointer to bytes to pump through */
unsigned n; /* number of bytes in s[] */
{
while (n--)
crc = crc_32_tab[(uchar)crc ^ (*s++)] ^ (crc >> 8);
}
/*
* Clear input and output buffers
*/
void clear_bufs()
{
outcnt = 0;
insize = inptr = 0;
}
/*
* Fill the input buffer. This is called only when the buffer is empty
* and at least one byte is really needed.
*/
void fill_inbuf ()
{
int len, i;
/* Read as much as possible */
insize = 0;
do {
len = INBUFSIZ - insize;
if (len > input_len - input_ptr + 1)
len = input_len-input_ptr+1;
if (len <= 0)
break;
for (i=0; i<len; i++)
inbuf[insize+i] = input_data[input_ptr+i];
insize += len;
input_ptr += len;
} while (insize < INBUFSIZ);
if (insize == 0)
error("unable to fill buffer");
inptr = 0;
}
/*
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
* (Used for the decompressed data only.)
*/
void flush_window()
{
if (outcnt == 0) return;
updcrc(window, outcnt);
memcpy(&output_data[output_ptr], (char *)window, outcnt);
output_ptr += outcnt;
outcnt = 0;
}
/*
* Code to compute the CRC-32 table. Borrowed from
* gzip-1.0.3/makecrc.c.
* Not copyrighted 1990 Mark Adler
*/
void makecrc(void)
{
ulong c; /* crc shift register */
ulong e; /* polynomial exclusive-or pattern */
int i; /* counter for all possible eight bit values */
int k; /* byte being shifted into crc apparatus */
/* terms of polynomial defining this crc (except x^32): */
static const uchar poly[] = { 0,1,2,4,5,7,8,10,11,12,16,22,23,26, };
/* Make exclusive-or pattern from polynomial */
e = 0;
for (i = 0; i < sizeof(poly)/sizeof(*poly); i++)
e |= 1L << (31 - poly[i]);
crc_32_tab[0] = 0;
for (i = 1; i < 256; i++) {
c = 0;
for (k = i | 256; k != 1; k >>= 1) {
c = c & 1 ? (c >> 1) ^ e : c >> 1;
if (k & 1)
c ^= e;
}
crc_32_tab[i] = c;
}
}
/*
* Check the magic number of the input file and update ofname if an
* original name was given and to_stdout is not set.
* Set inptr to the offset of the next byte to be processed.
*/
static void get_method()
{
uchar flags;
char magic[2]; /* magic header */
magic[0] = get_byte();
magic[1] = get_byte();
method = -1; /* unknown yet */
extended = pkzip = 0;
/* assume multiple members in gzip file except for record oriented I/O */
if (memcmp(magic, GZIP_MAGIC, 2) == 0
|| memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
method = get_byte();
flags = get_byte();
if (flags & ENCRYPTED)
error("Input is encrypted");
if (flags & CONTINUATION)
error("Multi part input");
if (flags & RESERVED)
error("Input has invalid flags");
(void) get_byte(); /* Get timestamp */
(void) get_byte();
(void) get_byte();
(void) get_byte();
(void) get_byte(); /* Ignore extra flags for the moment */
(void) get_byte(); /* Ignore OS type for the moment */
if (flags & EXTRA_FIELD) {
unsigned len = get_byte();
len |= get_byte() << 8;
while (len--)
(void) get_byte();
}
/* Discard file comment if any */
if (flags & COMMENT)
while (get_byte())
continue;
} else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
&& memcmp(inbuf, PKZIP_MAGIC, 4) == 0) {
/*
* To simplify the code, we support a zip file when alone only.
* We are thus guaranteed that the entire local header fits in inbuf.
*/
inptr = 0;
check_zipfile();
} else if (memcmp(magic, PACK_MAGIC, 2) == 0)
error("packed input");
else if (memcmp(magic, LZW_MAGIC, 2) == 0)
error("compressed input");
if (method == -1)
error("Corrupted input");
}
void
decompress_kernel (void *dest)
{
output_data = dest;
output_ptr = 0;
input_ptr = 0;
clear_bufs ();
makecrc ();
get_method ();
unzip ();
}

View file

@ -0,0 +1,175 @@
/*
* unzip.c -- decompress files in gzip or pkzip format.
* Copyright (C) 1992-1993 Jean-loup Gailly
*
* Adapted for Linux booting by Hannu Savolainen 1993
* Adapted for FreeBSD booting by Serge Vakulenko
*
* This is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, see the file COPYING.
*
* The code in this file is derived from the file funzip.c written
* and put in the public domain by Mark Adler.
*/
/*
* This version can extract files in gzip or pkzip format.
* For the latter, only the first entry is extracted, and it has to be
* either deflated or stored.
*/
#include "gzip.h"
#ifdef USE_KERNEL_INFLATE
#include <sys/types.h>
#include <sys/inflate.h>
#endif
/* PKZIP header definitions */
#define LOCSIG 0x04034b50L /* four-byte lead-in (lsb first) */
#define LOCFLG 6 /* offset of bit flag */
#define CRPFLG 1 /* bit for encrypted entry */
#define EXTFLG 8 /* bit for extended local header */
#define LOCHOW 8 /* offset of compression method */
#define LOCTIM 10 /* file mod time (for decryption) */
#define LOCCRC 14 /* offset of crc */
#define LOCSIZ 18 /* offset of compressed size */
#define LOCLEN 22 /* offset of uncompressed length */
#define LOCFIL 26 /* offset of file name field length */
#define LOCEXT 28 /* offset of extra field length */
#define LOCHDR 30 /* size of local header, including sig */
#define EXTHDR 16 /* size of extended local header, inc sig */
int pkzip; /* set for a pkzip file */
int extended; /* set if extended local header */
/* Macros for getting two-byte and four-byte header values */
#define SH(p) ((ushort)(uchar)((p)[0]) | ((ushort)(uchar)((p)[1]) << 8))
#define LG(p) ((ulong)(SH(p)) | ((ulong)(SH((p)+2)) << 16))
/*
* Check zip file and advance inptr to the start of the compressed data.
* Get ofname from the local header if necessary.
*/
void check_zipfile()
{
uchar *h = inbuf + inptr; /* first local header */
/* Check validity of local header, and skip name and extra fields */
inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
if (inptr > insize || LG(h) != LOCSIG)
error("input not a zip");
method = h[LOCHOW];
if (method != STORED && method != DEFLATED)
error("first entry not deflated or stored--can't extract");
/* If entry encrypted, decrypt and validate encryption header */
if (h[LOCFLG] & CRPFLG)
error("encrypted file");
/* Save flags for unzip() */
extended = (h[LOCFLG] & EXTFLG) != 0;
pkzip = 1;
}
#ifdef USE_KERNEL_INFLATE
int
Flush (void *nu, u_char *buf, u_long cnt)
{
outcnt = cnt;
flush_window();
return 0;
}
int
NextByte (void *nu)
{
return ((int) get_byte ());
}
struct inflate infl; /* put it into the BSS */
#endif
/*
* Unzip in to out. This routine works on both gzip and pkzip files.
*
* IN assertions: the buffer inbuf contains already the beginning of
* the compressed data, from offsets inptr to insize-1 included.
* The magic header has already been checked. The output buffer is cleared.
*/
void unzip()
{
ulong orig_crc = 0; /* original crc */
ulong orig_len = 0; /* original uncompressed length */
uchar buf[EXTHDR]; /* extended local header */
int n;
crc = 0xffffffffL; /* initialize crc */
if (pkzip && !extended) { /* crc and length at the end otherwise */
orig_crc = LG(inbuf + LOCCRC);
orig_len = LG(inbuf + LOCLEN);
}
/* Decompress */
if (method == DEFLATED) {
#ifdef USE_KERNEL_INFLATE
int res;
infl.gz_input = NextByte;
infl.gz_output = Flush;
infl.gz_slide = window;
res = inflate (&infl);
#else
int res = inflate();
#endif
if (res == 3)
error("out of memory");
else if (res != 0)
error("invalid compressed format");
} else if (pkzip && method == STORED) {
register ulong n = LG(inbuf + LOCLEN);
if (n != LG(inbuf + LOCSIZ))
error("length mismatch");
while (n--)
put_char(get_byte());
} else
error("internal error, invalid method");
/* Get the crc and original length */
if (!pkzip) {
/* crc32 (see algorithm.doc)
* uncompressed input size modulo 2^32
*/
for (n = 0; n < 8; n++)
buf[n] = get_byte(); /* may cause an error if EOF */
orig_crc = LG(buf);
orig_len = LG(buf+4);
} else if (extended) { /* If extended header, check it */
/* signature - 4bytes: 0x50 0x4b 0x07 0x08
* CRC-32 value
* compressed size 4-bytes
* uncompressed size 4-bytes
*/
for (n = 0; n < EXTHDR; n++)
buf[n] = get_byte(); /* may cause an error if EOF */
orig_crc = LG(buf+4);
orig_len = LG(buf+12);
}
/* Validate decompression */
if (orig_crc != (crc ^ 0xffffffffL))
error("crc error");
if (orig_len != output_ptr)
error("length error");
/* Check if there are more entries in a pkzip file */
if (pkzip && inptr+4 < insize && LG(inbuf+inptr) == LOCSIG)
error("zip file has more than one entry");
}