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