8990 /opt/onbld/gk is useless
[unleashed.git] / usr / src / common / fs / decompress.c
blob4f6b5b4d85754ee37b0ca8d72ec3dc441f2faf9c
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Decompression module for stand alone file systems.
31 #include <sys/param.h>
32 #include <sys/sysmacros.h>
33 #include <sys/vnode.h>
34 #include <sys/bootvfs.h>
35 #include <sys/filep.h>
36 #include <zmod/zlib.h>
38 #ifdef _BOOT
39 #include "../common/util.h"
40 #else
41 #include <sys/sunddi.h>
42 #endif
44 #define MAX_DECOMP_BUFS 8
45 #define GZIP_ID_BYTE_1 0x1f
46 #define GZIP_ID_BYTE_2 0x8b
47 #define GZIP_CM_DEFLATE 0x08
48 #define SEEKBUFSIZE 8192
50 extern void prom_printf(const char *fmt, ...);
52 #ifdef _BOOT
53 #define dprintf if (cf_debug) prom_printf
54 #else
55 #define dprintf if (cf_debug) prom_printf
57 #endif
59 extern int bootrd_debug;
60 extern void *bkmem_alloc(size_t);
61 extern void bkmem_free(void *, size_t);
63 caddr_t scratch_bufs[MAX_DECOMP_BUFS]; /* array of free scratch mem bufs */
64 int decomp_bufcnt; /* total no, of allocated decomp bufs */
65 int free_dcomp_bufs; /* no. of free decomp bufs */
66 char seek_scrbuf[SEEKBUFSIZE]; /* buffer for seeking */
67 int cf_debug = 0; /* non-zero enables debug prints */
69 void *
70 cf_alloc(void *opaque, unsigned int items, unsigned int size)
72 fileid_t *filep;
73 unsigned int nbytes;
74 caddr_t ptr;
76 filep = (fileid_t *)opaque;
77 nbytes = roundup(items * size, sizeof (long));
78 if (nbytes > (DECOMP_BUFSIZE - filep->fi_dcscrused)) {
79 ptr = bkmem_alloc(nbytes);
80 } else {
81 ptr = &filep->fi_dcscrbuf[filep->fi_dcscrused];
82 filep->fi_dcscrused += nbytes;
84 bzero(ptr, nbytes);
85 return (ptr);
89 * Decompression scratch memory free routine, does nothing since we free
90 * the entire scratch area all at once on file close.
92 /* ARGSUSED */
93 void
94 cf_free(void *opaque, void *addr)
99 * Read the first block of the file described by filep and determine if
100 * the file is gzip-compressed. If so, the compressed flag will be set
101 * in the fileid_t struct pointed to by filep and it will be initialized
102 * for doing decompression on reads to the file.
105 cf_check_compressed(fileid_t *filep)
107 unsigned char *filebytes;
108 z_stream *zsp;
111 * checking for a dcfs compressed file first would involve:
113 * if (filep->fi_inode->i_cflags & ICOMPRESS)
114 * filep->fi_flags |= FI_COMPRESSED;
118 * If the file is not long enough to check for a
119 * decompression header then return not compressed.
121 if (filep->fi_inode->i_size < 3)
122 return (0);
123 filep->fi_offset = 0;
124 if ((filep->fi_getblock)(filep) == -1)
125 return (-1);
126 filep->fi_offset = 0;
127 filep->fi_count = 0;
128 filep->fi_cfoff = 0;
129 filebytes = (unsigned char *)filep->fi_memp;
130 if (filebytes[0] != GZIP_ID_BYTE_1 ||
131 filebytes[1] != GZIP_ID_BYTE_2 ||
132 filebytes[2] != GZIP_CM_DEFLATE)
133 return (0); /* not compressed */
134 filep->fi_flags |= FI_COMPRESSED;
136 dprintf("file %s is compressed\n", filep->fi_path);
139 * Allocate decompress scratch buffer
141 if (free_dcomp_bufs) {
142 filep->fi_dcscrbuf = scratch_bufs[--free_dcomp_bufs];
143 } else {
144 filep->fi_dcscrbuf = bkmem_alloc(DECOMP_BUFSIZE);
145 decomp_bufcnt++;
147 filep->fi_dcscrused = 0;
148 zsp = bkmem_alloc(sizeof (*zsp));
149 filep->fi_dcstream = zsp;
151 * Initialize the decompression stream. Adding 16 to the window size
152 * indicates that zlib should expect a gzip header.
154 bzero(zsp, sizeof (*zsp));
155 zsp->opaque = filep;
156 zsp->zalloc = cf_alloc;
157 zsp->zfree = cf_free;
158 zsp->avail_in = 0;
159 zsp->next_in = NULL;
160 zsp->avail_out = 0;
161 zsp->next_out = NULL;
162 if (inflateInit2(zsp, MAX_WBITS | 0x20) != Z_OK) {
163 dprintf("inflateInit2() failed\n");
164 return (-1);
166 return (0);
170 * If the file described by fileid_t struct at *filep is compressed
171 * free any resources associated with the decompression. (decompression
172 * buffer, etc.).
174 void
175 cf_close(fileid_t *filep)
177 if ((filep->fi_flags & FI_COMPRESSED) == 0)
178 return;
179 dprintf("cf_close: %s\n", filep->fi_path);
180 (void) inflateEnd(filep->fi_dcstream);
181 bkmem_free(filep->fi_dcstream, sizeof (z_stream));
182 if (free_dcomp_bufs == MAX_DECOMP_BUFS) {
183 bkmem_free(filep->fi_dcscrbuf, DECOMP_BUFSIZE);
184 } else {
185 scratch_bufs[free_dcomp_bufs++] = filep->fi_dcscrbuf;
189 void
190 cf_rewind(fileid_t *filep)
192 z_stream *zsp;
194 dprintf("cf_rewind: %s\n", filep->fi_path);
195 zsp = filep->fi_dcstream;
196 zsp->avail_in = 0;
197 zsp->next_in = NULL;
198 (void) inflateReset(zsp);
199 filep->fi_cfoff = 0;
202 #define FLG_FHCRC 0x02 /* crc field present */
203 #define FLG_FEXTRA 0x04 /* "extra" field present */
204 #define FLG_FNAME 0x08 /* file name field present */
205 #define FLG_FCOMMENT 0x10 /* comment field present */
208 * Read at the current uncompressed offset from the compressed file described
209 * by *filep. Will return decompressed data.
212 cf_read(fileid_t *filep, caddr_t buf, size_t count)
214 z_stream *zsp;
215 struct inode *ip;
216 int err = Z_OK;
217 int infbytes;
218 off_t soff;
219 caddr_t smemp;
221 dprintf("cf_read: %s ", filep->fi_path);
222 dprintf("%lx bytes\n", count);
223 zsp = filep->fi_dcstream;
224 ip = filep->fi_inode;
225 dprintf(" reading at offset %lx\n", zsp->total_out);
226 zsp->next_out = (unsigned char *)buf;
227 zsp->avail_out = count;
228 while (zsp->avail_out != 0) {
229 if (zsp->avail_in == 0 && filep->fi_cfoff < ip->i_size) {
231 * read a block of the file to inflate
233 soff = filep->fi_offset;
234 smemp = filep->fi_memp;
235 filep->fi_memp = NULL;
236 filep->fi_offset = filep->fi_cfoff;
237 filep->fi_count = 0;
238 if ((*filep->fi_getblock)(filep) == -1)
239 return (-1);
240 filep->fi_offset = soff;
241 zsp->next_in = (unsigned char *)filep->fi_memp;
242 zsp->avail_in = filep->fi_count;
243 filep->fi_memp = smemp;
244 filep->fi_cfoff += filep->fi_count;
246 infbytes = zsp->avail_out;
247 dprintf("attempting inflate of %x bytes to buf at: %lx\n",
248 zsp->avail_out, (unsigned long)zsp->next_out);
249 err = inflate(zsp, Z_NO_FLUSH);
250 infbytes -= zsp->avail_out;
251 dprintf("inflated %x bytes, errcode=%d\n", infbytes, err);
253 * break out if we hit end of the compressed file
254 * or the end of the compressed byte stream
256 if (filep->fi_cfoff >= ip->i_size || err == Z_STREAM_END)
257 break;
259 dprintf("cf_read: returned %lx bytes\n", count - zsp->avail_out);
260 return (count - zsp->avail_out);
264 * Seek to the location specified by addr
266 void
267 cf_seek(fileid_t *filep, off_t addr, int whence)
269 z_stream *zsp;
270 int readsz;
272 dprintf("cf_seek: %s ", filep->fi_path);
273 dprintf("to %lx\n", addr);
274 zsp = filep->fi_dcstream;
275 if (whence == SEEK_CUR)
276 addr += zsp->total_out;
278 * To seek backwards, must rewind and seek forwards
280 if (addr < zsp->total_out) {
281 cf_rewind(filep);
282 filep->fi_offset = 0;
283 } else {
284 addr -= zsp->total_out;
286 while (addr > 0) {
287 readsz = MIN(addr, SEEKBUFSIZE);
288 (void) cf_read(filep, seek_scrbuf, readsz);
289 addr -= readsz;