Annotation of sys/lib/libsa/cread.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: cread.c,v 1.12 2004/04/02 04:39:51 deraadt Exp $ */
2: /* $NetBSD: cread.c,v 1.2 1997/02/04 18:38:20 thorpej Exp $ */
3:
4: /*
5: * Copyright (c) 1996
6: * Matthias Drochner. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: *
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
19: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27: *
28: */
29:
30: /* support for compressed bootfiles
31: (only read)
32: replaces open(), close(), read(), lseek().
33: original libsa open(), close(), read(), lseek() are called
34: as oopen(), oclose(), oread() resp. olseek().
35: compression parts stripped from zlib:gzio.c
36: */
37:
38: /* gzio.c -- IO on .gz files
39: * Copyright (C) 1995-1996 Jean-loup Gailly.
40: * For conditions of distribution and use, see copyright notice in zlib.h
41: */
42:
43: #include "stand.h"
44: #include "../libz/zlib.h"
45:
46: #define EOF (-1) /* needed by compression code */
47:
48: #define zmemcpy memcpy
49:
50: #ifdef SAVE_MEMORY
51: #define Z_BUFSIZE 1024
52: #else
53: #define Z_BUFSIZE 4096
54: #endif
55:
56: static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
57:
58: /* gzip flag byte */
59: #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
60: #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
61: #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
62: #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
63: #define COMMENT 0x10 /* bit 4 set: file comment present */
64: #define RESERVED 0xE0 /* bits 5..7: reserved */
65:
66: static struct sd {
67: z_stream stream;
68: int z_err; /* error code for last stream operation */
69: int z_eof; /* set if end of input file */
70: int fd;
71: unsigned char *inbuf; /* input buffer */
72: unsigned long crc; /* crc32 of uncompressed data */
73: int transparent; /* 1 if input file is not a .gz file */
74: } *ss[SOPEN_MAX];
75:
76: #ifdef DEBUG
77: int z_verbose = 0;
78: #endif
79:
80: /*
81: * compression utilities
82: */
83:
84: void *zcalloc(void *, unsigned int, unsigned int);
85: void zcfree(void *, void *);
86:
87: void *
88: zcalloc(void *opaque, unsigned int items, unsigned int size)
89: {
90: return(alloc(items * size));
91: }
92:
93: void
94: zcfree(void *opaque, void *ptr)
95: {
96: free(ptr, 0); /* XXX works only with modified allocator */
97: }
98:
99: static int
100: get_byte(struct sd *s)
101: {
102: if (s->z_eof)
103: return EOF;
104: if (s->stream.avail_in == 0) {
105: errno = 0;
106: s->stream.avail_in = oread(s->fd, s->inbuf, Z_BUFSIZE);
107: if (s->stream.avail_in <= 0) {
108: s->z_eof = 1;
109: if (errno)
110: s->z_err = Z_ERRNO;
111: return EOF;
112: }
113: s->stream.next_in = s->inbuf;
114: }
115: s->stream.avail_in--;
116: return *(s->stream.next_in)++;
117: }
118:
119: static unsigned long
120: getLong(struct sd *s)
121: {
122: unsigned long x = (unsigned long)get_byte(s);
123: int c;
124:
125: x += ((unsigned long)get_byte(s))<<8;
126: x += ((unsigned long)get_byte(s))<<16;
127: c = get_byte(s);
128: if (c == EOF)
129: s->z_err = Z_DATA_ERROR;
130: x += ((unsigned long)c)<<24;
131: return x;
132: }
133:
134: static void
135: check_header(struct sd *s)
136: {
137: int method; /* method byte */
138: int flags; /* flags byte */
139: unsigned int len;
140: int c;
141:
142: /* Check the gzip magic header */
143: for (len = 0; len < 2; len++) {
144: c = get_byte(s);
145: if (c != gz_magic[len]) {
146: if (len != 0) {
147: s->stream.avail_in++;
148: s->stream.next_in--;
149: }
150: if (c != EOF) {
151: s->stream.avail_in++;
152: s->stream.next_in--;
153: s->transparent = 1;
154: }
155:
156: s->z_err = s->stream.avail_in != 0 ? Z_OK :
157: Z_STREAM_END;
158: return;
159: }
160: }
161: method = get_byte(s);
162: flags = get_byte(s);
163: if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
164: s->z_err = Z_DATA_ERROR;
165: return;
166: }
167:
168: /* Discard time, xflags and OS code: */
169: for (len = 0; len < 6; len++)
170: (void)get_byte(s);
171:
172: if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
173: len = (unsigned int)get_byte(s);
174: len += ((unsigned int)get_byte(s))<<8;
175: /* len is garbage if EOF but the loop below will quit anyway */
176: while (len-- != 0 && get_byte(s) != EOF)
177: ;
178: }
179: if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
180: while ((c = get_byte(s)) != 0 && c != EOF)
181: ;
182: }
183: if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
184: while ((c = get_byte(s)) != 0 && c != EOF)
185: ;
186: }
187: if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
188: for (len = 0; len < 2; len++)
189: (void)get_byte(s);
190: }
191: s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
192: }
193:
194: /*
195: * new open(), close(), read(), lseek()
196: */
197:
198: int
199: open(const char *fname, int mode)
200: {
201: int fd;
202: struct sd *s = 0;
203:
204: if (((fd = oopen(fname, mode)) == -1) ||
205: (mode != 0)) /* compression only for read */
206: return(fd);
207:
208: ss[fd] = s = alloc(sizeof(struct sd));
209: if (!s)
210: goto errout;
211: bzero(s, sizeof(struct sd));
212:
213: #ifdef SAVE_MEMORY
214: if (inflateInit2(&(s->stream), -11) != Z_OK)
215: #else
216: if (inflateInit2(&(s->stream), -15) != Z_OK)
217: #endif
218: goto errout;
219:
220: s->stream.next_in = s->inbuf = (unsigned char *)alloc(Z_BUFSIZE);
221: if (!s->inbuf) {
222: inflateEnd(&(s->stream));
223: goto errout;
224: }
225:
226: s->fd = fd;
227: check_header(s); /* skip the .gz header */
228: return(fd);
229:
230: errout:
231: if (s)
232: free(s, sizeof(struct sd));
233: oclose(fd);
234: return(-1);
235: }
236:
237: int
238: close(int fd)
239: {
240: struct open_file *f;
241: struct sd *s;
242:
243: if ((unsigned)fd >= SOPEN_MAX) {
244: errno = EBADF;
245: return (-1);
246: }
247: f = &files[fd];
248:
249: if (!(f->f_flags & F_READ))
250: return(oclose(fd));
251:
252: s = ss[fd];
253:
254: inflateEnd(&(s->stream));
255:
256: free(s->inbuf, Z_BUFSIZE);
257: free(s, sizeof(struct sd));
258:
259: return(oclose(fd));
260: }
261:
262: ssize_t
263: read(int fd, void *buf, size_t len)
264: {
265: struct sd *s;
266: unsigned char *start = buf; /* starting point for crc computation */
267:
268: s = ss[fd];
269:
270: if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)
271: return -1;
272: if (s->z_err == Z_STREAM_END)
273: return 0; /* EOF */
274:
275: s->stream.next_out = buf;
276: s->stream.avail_out = len;
277:
278: while (s->stream.avail_out != 0) {
279:
280: if (s->transparent) {
281: /* Copy first the lookahead bytes: */
282: unsigned int n = s->stream.avail_in;
283:
284: if (n > s->stream.avail_out)
285: n = s->stream.avail_out;
286: if (n > 0) {
287: zmemcpy(s->stream.next_out, s->stream.next_in, n);
288: s->stream.next_out += n;
289: s->stream.next_in += n;
290: s->stream.avail_out -= n;
291: s->stream.avail_in -= n;
292: }
293: if (s->stream.avail_out > 0) {
294: int n;
295:
296: n = oread(fd, s->stream.next_out,
297: s->stream.avail_out);
298: if (n <= 0) {
299: s->z_eof = 1;
300: if (errno) {
301: s->z_err = Z_ERRNO;
302: break;
303: }
304: }
305: s->stream.avail_out -= n;
306: }
307: len -= s->stream.avail_out;
308: s->stream.total_in += (unsigned long)len;
309: s->stream.total_out += (unsigned long)len;
310: if (len == 0)
311: s->z_eof = 1;
312: return (int)len;
313: }
314:
315: if (s->stream.avail_in == 0 && !s->z_eof) {
316: errno = 0;
317: s->stream.avail_in = oread(fd, s->inbuf, Z_BUFSIZE);
318: if (s->stream.avail_in <= 0) {
319: s->z_eof = 1;
320: if (errno) {
321: s->z_err = Z_ERRNO;
322: break;
323: }
324: }
325: s->stream.next_in = s->inbuf;
326: }
327: s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
328:
329: if (s->z_err == Z_STREAM_END) {
330: /* Check CRC and original size */
331: s->crc = crc32(s->crc, start,
332: (unsigned int)(s->stream.next_out - start));
333: start = s->stream.next_out;
334:
335: if (getLong(s) != s->crc) {
336: s->z_err = Z_DATA_ERROR;
337: } else {
338: (void)getLong(s);
339:
340: /* The uncompressed length returned by
341: * above getlong() may be different from
342: * s->stream.total_out in case of concatenated
343: * .gz files. Check for such files:
344: */
345: check_header(s);
346: if (s->z_err == Z_OK) {
347: unsigned long total_in = s->stream.total_in;
348: unsigned long total_out = s->stream.total_out;
349:
350: inflateReset(&(s->stream));
351: s->stream.total_in = total_in;
352: s->stream.total_out = total_out;
353: s->crc = crc32(0L, Z_NULL, 0);
354: }
355: }
356: }
357: if (s->z_err != Z_OK || s->z_eof)
358: break;
359: }
360: s->crc = crc32(s->crc, start, (unsigned int)(s->stream.next_out - start));
361:
362: return (int)(len - s->stream.avail_out);
363: }
364:
365: off_t
366: lseek(int fd, off_t offset, int where)
367: {
368: struct open_file *f;
369: struct sd *s;
370:
371: if ((unsigned)fd >= SOPEN_MAX) {
372: errno = EBADF;
373: return (-1);
374: }
375: f = &files[fd];
376:
377: if (!(f->f_flags & F_READ))
378: return(olseek(fd, offset, where));
379:
380: s = ss[fd];
381:
382: if (s->transparent) {
383: off_t res = olseek(fd, offset, where);
384: if (res != (off_t)-1) {
385: /* make sure the lookahead buffer is invalid */
386: s->stream.avail_in = 0;
387: }
388: return(res);
389: }
390:
391: switch(where) {
392: case SEEK_CUR:
393: offset += s->stream.total_out;
394: case SEEK_SET:
395:
396: /* if seek backwards, simply start from
397: the beginning */
398: if (offset < s->stream.total_out) {
399: off_t res;
400: void *sav_inbuf;
401:
402: res = olseek(fd, 0, SEEK_SET);
403: if (res == (off_t)-1)
404: return(res);
405: /* ??? perhaps fallback to close / open */
406:
407: inflateEnd(&(s->stream));
408:
409: sav_inbuf = s->inbuf; /* don't allocate again */
410: bzero(s, sizeof(struct sd)); /* this resets total_out to 0! */
411:
412: inflateInit2(&(s->stream), -15);
413: s->stream.next_in = s->inbuf = sav_inbuf;
414:
415: s->fd = fd;
416: check_header(s); /* skip the .gz header */
417: }
418:
419: /* to seek forwards, throw away data */
420: if (offset > s->stream.total_out) {
421: off_t toskip = offset - s->stream.total_out;
422:
423: while(toskip > 0) {
424: #define DUMMYBUFSIZE 256
425: char dummybuf[DUMMYBUFSIZE];
426: off_t len = toskip;
427:
428: if (len > DUMMYBUFSIZE)
429: len = DUMMYBUFSIZE;
430: if (read(fd, dummybuf, len) != len) {
431: errno = EOFFSET;
432: return((off_t)-1);
433: }
434: toskip -= len;
435: }
436: }
437: #ifdef DEBUG
438: if (offset != s->stream.total_out)
439: panic("lseek compressed");
440: #endif
441: return(offset);
442: case SEEK_END:
443: errno = EOFFSET;
444: break;
445: default:
446: errno = EINVAL;
447: }
448: return((off_t)-1);
449: }
CVSweb