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]
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>
39 #include "../common/util.h"
41 #include <sys/sunddi.h>
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
, ...);
53 #define dprintf if (cf_debug) prom_printf
55 #define dprintf if (cf_debug) prom_printf
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 */
70 cf_alloc(void *opaque
, unsigned int items
, unsigned int size
)
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
);
81 ptr
= &filep
->fi_dcscrbuf
[filep
->fi_dcscrused
];
82 filep
->fi_dcscrused
+= nbytes
;
89 * Decompression scratch memory free routine, does nothing since we free
90 * the entire scratch area all at once on file close.
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
;
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)
123 filep
->fi_offset
= 0;
124 if ((filep
->fi_getblock
)(filep
) == -1)
126 filep
->fi_offset
= 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
];
144 filep
->fi_dcscrbuf
= bkmem_alloc(DECOMP_BUFSIZE
);
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
));
156 zsp
->zalloc
= cf_alloc
;
157 zsp
->zfree
= cf_free
;
161 zsp
->next_out
= NULL
;
162 if (inflateInit2(zsp
, MAX_WBITS
| 0x20) != Z_OK
) {
163 dprintf("inflateInit2() failed\n");
170 * If the file described by fileid_t struct at *filep is compressed
171 * free any resources associated with the decompression. (decompression
175 cf_close(fileid_t
*filep
)
177 if ((filep
->fi_flags
& FI_COMPRESSED
) == 0)
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
);
185 scratch_bufs
[free_dcomp_bufs
++] = filep
->fi_dcscrbuf
;
190 cf_rewind(fileid_t
*filep
)
194 dprintf("cf_rewind: %s\n", filep
->fi_path
);
195 zsp
= filep
->fi_dcstream
;
198 (void) inflateReset(zsp
);
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
)
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
;
238 if ((*filep
->fi_getblock
)(filep
) == -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
)
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
267 cf_seek(fileid_t
*filep
, off_t addr
, int whence
)
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
) {
282 filep
->fi_offset
= 0;
284 addr
-= zsp
->total_out
;
287 readsz
= MIN(addr
, SEEKBUFSIZE
);
288 (void) cf_read(filep
, seek_scrbuf
, readsz
);