FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_gzio.c
1 /*
2 * $Id: kern_gzio.c,v 1.6 2008-10-18 22:54:45 lbazinet Exp $
3 *
4 * core_gzip.c -- gzip routines used in compressing user process cores
5 *
6 * This file is derived from src/lib/libz/gzio.c in FreeBSD.
7 */
8
9 /* gzio.c -- IO on .gz files
10 * Copyright (C) 1995-1998 Jean-loup Gailly.
11 * For conditions of distribution and use, see copyright notice in zlib.h
12 *
13 */
14
15 /* @(#) $FreeBSD: releng/10.4/sys/kern/kern_gzio.c 241896 2012-10-22 17:50:54Z kib $ */
16
17 #include <sys/param.h>
18 #include <sys/proc.h>
19 #include <sys/malloc.h>
20 #include <sys/vnode.h>
21 #include <sys/syslog.h>
22 #include <sys/endian.h>
23 #include <net/zutil.h>
24 #include <sys/libkern.h>
25
26 #include <sys/vnode.h>
27 #include <sys/mount.h>
28
29 #define GZ_HEADER_LEN 10
30
31 #ifndef Z_BUFSIZE
32 # ifdef MAXSEG_64K
33 # define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
34 # else
35 # define Z_BUFSIZE 16384
36 # endif
37 #endif
38 #ifndef Z_PRINTF_BUFSIZE
39 # define Z_PRINTF_BUFSIZE 4096
40 #endif
41
42 #define ALLOC(size) malloc(size, M_TEMP, M_WAITOK | M_ZERO)
43 #define TRYFREE(p) {if (p) free(p, M_TEMP);}
44
45 static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
46
47 /* gzip flag byte */
48 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
49 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
50 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
51 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
52 #define COMMENT 0x10 /* bit 4 set: file comment present */
53 #define RESERVED 0xE0 /* bits 5..7: reserved */
54
55 typedef struct gz_stream {
56 z_stream stream;
57 int z_err; /* error code for last stream operation */
58 int z_eof; /* set if end of input file */
59 struct vnode *file; /* vnode pointer of .gz file */
60 Byte *inbuf; /* input buffer */
61 Byte *outbuf; /* output buffer */
62 uLong crc; /* crc32 of uncompressed data */
63 char *msg; /* error message */
64 char *path; /* path name for debugging only */
65 int transparent; /* 1 if input file is not a .gz file */
66 char mode; /* 'w' or 'r' */
67 long startpos; /* start of compressed data in file (header skipped) */
68 off_t outoff; /* current offset in output file */
69 int flags;
70 } gz_stream;
71
72
73 local int do_flush OF((gzFile file, int flush));
74 local int destroy OF((gz_stream *s));
75 local void putU32 OF((gz_stream *file, uint32_t x));
76 local void *gz_alloc OF((void *notused, u_int items, u_int size));
77 local void gz_free OF((void *notused, void *ptr));
78
79 /* ===========================================================================
80 Opens a gzip (.gz) file for reading or writing. The mode parameter
81 is as in fopen ("rb" or "wb"). The file is given either by file descriptor
82 or path name (if fd == -1).
83 gz_open return NULL if the file could not be opened or if there was
84 insufficient memory to allocate the (de)compression state; errno
85 can be checked to distinguish the two cases (if errno is zero, the
86 zlib error is Z_MEM_ERROR).
87 */
88 gzFile gz_open (path, mode, vp)
89 const char *path;
90 const char *mode;
91 struct vnode *vp;
92 {
93 int err;
94 int level = Z_DEFAULT_COMPRESSION; /* compression level */
95 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
96 const char *p = mode;
97 gz_stream *s;
98 char fmode[80]; /* copy of mode, without the compression level */
99 char *m = fmode;
100 ssize_t resid;
101 int error;
102 char buf[GZ_HEADER_LEN + 1];
103
104 if (!path || !mode) return Z_NULL;
105
106 s = (gz_stream *)ALLOC(sizeof(gz_stream));
107 if (!s) return Z_NULL;
108
109 s->stream.zalloc = (alloc_func)gz_alloc;
110 s->stream.zfree = (free_func)gz_free;
111 s->stream.opaque = (voidpf)0;
112 s->stream.next_in = s->inbuf = Z_NULL;
113 s->stream.next_out = s->outbuf = Z_NULL;
114 s->stream.avail_in = s->stream.avail_out = 0;
115 s->file = NULL;
116 s->z_err = Z_OK;
117 s->z_eof = 0;
118 s->crc = 0;
119 s->msg = NULL;
120 s->transparent = 0;
121 s->outoff = 0;
122 s->flags = 0;
123
124 s->path = (char*)ALLOC(strlen(path)+1);
125 if (s->path == NULL) {
126 return destroy(s), (gzFile)Z_NULL;
127 }
128 strcpy(s->path, path); /* do this early for debugging */
129
130 s->mode = '\0';
131 do {
132 if (*p == 'r') s->mode = 'r';
133 if (*p == 'w' || *p == 'a') s->mode = 'w';
134 if (*p >= '' && *p <= '9') {
135 level = *p - '';
136 } else if (*p == 'f') {
137 strategy = Z_FILTERED;
138 } else if (*p == 'h') {
139 strategy = Z_HUFFMAN_ONLY;
140 } else {
141 *m++ = *p; /* copy the mode */
142 }
143 } while (*p++ && m != fmode + sizeof(fmode));
144
145 if (s->mode != 'w') {
146 log(LOG_ERR, "gz_open: mode is not w (%c)\n", s->mode);
147 return destroy(s), (gzFile)Z_NULL;
148 }
149
150 err = deflateInit2(&(s->stream), level,
151 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
152 /* windowBits is passed < 0 to suppress zlib header */
153
154 s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
155 if (err != Z_OK || s->outbuf == Z_NULL) {
156 return destroy(s), (gzFile)Z_NULL;
157 }
158
159 s->stream.avail_out = Z_BUFSIZE;
160 s->file = vp;
161
162 /* Write a very simple .gz header:
163 */
164 snprintf(buf, sizeof(buf), "%c%c%c%c%c%c%c%c%c%c", gz_magic[0],
165 gz_magic[1], Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/,
166 0 /*xflags*/, OS_CODE);
167
168 if ((error = vn_rdwr(UIO_WRITE, s->file, buf, GZ_HEADER_LEN, s->outoff,
169 UIO_SYSSPACE, IO_UNIT, curproc->p_ucred,
170 NOCRED, &resid, curthread))) {
171 s->outoff += GZ_HEADER_LEN - resid;
172 return destroy(s), (gzFile)Z_NULL;
173 }
174 s->outoff += GZ_HEADER_LEN;
175 s->startpos = 10L;
176
177 return (gzFile)s;
178 }
179
180
181 /* ===========================================================================
182 * Cleanup then free the given gz_stream. Return a zlib error code.
183 Try freeing in the reverse order of allocations.
184 */
185 local int destroy (s)
186 gz_stream *s;
187 {
188 int err = Z_OK;
189
190 if (!s) return Z_STREAM_ERROR;
191
192 TRYFREE(s->msg);
193
194 if (s->stream.state != NULL) {
195 if (s->mode == 'w') {
196 err = deflateEnd(&(s->stream));
197 }
198 }
199 if (s->z_err < 0) err = s->z_err;
200
201 TRYFREE(s->inbuf);
202 TRYFREE(s->outbuf);
203 TRYFREE(s->path);
204 TRYFREE(s);
205 return err;
206 }
207
208
209 /* ===========================================================================
210 Writes the given number of uncompressed bytes into the compressed file.
211 gzwrite returns the number of bytes actually written (0 in case of error).
212 */
213 int ZEXPORT gzwrite (file, buf, len)
214 gzFile file;
215 const voidp buf;
216 unsigned len;
217 {
218 gz_stream *s = (gz_stream*)file;
219 off_t curoff;
220 size_t resid;
221 int error;
222
223 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
224
225 s->stream.next_in = (Bytef*)buf;
226 s->stream.avail_in = len;
227
228 curoff = s->outoff;
229 while (s->stream.avail_in != 0) {
230
231 if (s->stream.avail_out == 0) {
232
233 s->stream.next_out = s->outbuf;
234 error = vn_rdwr_inchunks(UIO_WRITE, s->file, s->outbuf, Z_BUFSIZE,
235 curoff, UIO_SYSSPACE, IO_UNIT,
236 curproc->p_ucred, NOCRED, &resid, curthread);
237 if (error) {
238 log(LOG_ERR, "gzwrite: vn_rdwr return %d\n", error);
239 curoff += Z_BUFSIZE - resid;
240 s->z_err = Z_ERRNO;
241 break;
242 }
243 curoff += Z_BUFSIZE;
244 s->stream.avail_out = Z_BUFSIZE;
245 }
246 s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
247 if (s->z_err != Z_OK) {
248 log(LOG_ERR,
249 "gzwrite: deflate returned error %d\n", s->z_err);
250 break;
251 }
252 }
253
254 s->crc = ~crc32_raw(buf, len, ~s->crc);
255 s->outoff = curoff;
256
257 return (int)(len - s->stream.avail_in);
258 }
259
260
261 /* ===========================================================================
262 Flushes all pending output into the compressed file. The parameter
263 flush is as in the deflate() function.
264 */
265 local int do_flush (file, flush)
266 gzFile file;
267 int flush;
268 {
269 uInt len;
270 int done = 0;
271 gz_stream *s = (gz_stream*)file;
272 off_t curoff = s->outoff;
273 size_t resid;
274 int error;
275
276 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
277
278 if (s->stream.avail_in) {
279 log(LOG_WARNING, "do_flush: avail_in non-zero on entry\n");
280 }
281
282 s->stream.avail_in = 0; /* should be zero already anyway */
283
284 for (;;) {
285 len = Z_BUFSIZE - s->stream.avail_out;
286
287 if (len != 0) {
288 error = vn_rdwr_inchunks(UIO_WRITE, s->file, s->outbuf, len, curoff,
289 UIO_SYSSPACE, IO_UNIT, curproc->p_ucred,
290 NOCRED, &resid, curthread);
291 if (error) {
292 s->z_err = Z_ERRNO;
293 s->outoff = curoff + len - resid;
294 return Z_ERRNO;
295 }
296 s->stream.next_out = s->outbuf;
297 s->stream.avail_out = Z_BUFSIZE;
298 curoff += len;
299 }
300 if (done) break;
301 s->z_err = deflate(&(s->stream), flush);
302
303 /* Ignore the second of two consecutive flushes: */
304 if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
305
306 /* deflate has finished flushing only when it hasn't used up
307 * all the available space in the output buffer:
308 */
309 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
310
311 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
312 }
313 s->outoff = curoff;
314
315 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
316 }
317
318 int ZEXPORT gzflush (file, flush)
319 gzFile file;
320 int flush;
321 {
322 gz_stream *s = (gz_stream*)file;
323 int err = do_flush (file, flush);
324
325 if (err) return err;
326 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
327 }
328
329
330 /* ===========================================================================
331 Outputs a long in LSB order to the given file
332 */
333 local void putU32 (s, x)
334 gz_stream *s;
335 uint32_t x;
336 {
337 uint32_t xx;
338 off_t curoff = s->outoff;
339 ssize_t resid;
340
341 #if BYTE_ORDER == BIG_ENDIAN
342 xx = bswap32(x);
343 #else
344 xx = x;
345 #endif
346 vn_rdwr(UIO_WRITE, s->file, (caddr_t)&xx, sizeof(xx), curoff,
347 UIO_SYSSPACE, IO_UNIT, curproc->p_ucred,
348 NOCRED, &resid, curthread);
349 s->outoff += sizeof(xx) - resid;
350 }
351
352
353 /* ===========================================================================
354 Flushes all pending output if necessary, closes the compressed file
355 and deallocates all the (de)compression state.
356 */
357 int ZEXPORT gzclose (file)
358 gzFile file;
359 {
360 int err;
361 gz_stream *s = (gz_stream*)file;
362
363 if (s == NULL) return Z_STREAM_ERROR;
364
365 if (s->mode == 'w') {
366 err = do_flush (file, Z_FINISH);
367 if (err != Z_OK) {
368 log(LOG_ERR, "gzclose: do_flush failed (err %d)\n", err);
369 return destroy((gz_stream*)file);
370 }
371 #if 0
372 printf("gzclose: putting crc: %lld total: %lld\n",
373 (long long)s->crc, (long long)s->stream.total_in);
374 printf("sizeof uLong = %d\n", (int)sizeof(uLong));
375 #endif
376 putU32 (s, s->crc);
377 putU32 (s, (uint32_t) s->stream.total_in);
378 }
379 return destroy((gz_stream*)file);
380 }
381
382 /*
383 * Space allocation and freeing routines for use by zlib routines when called
384 * from gzip modules.
385 */
386 static void *
387 gz_alloc(void *notused __unused, u_int items, u_int size)
388 {
389 void *ptr;
390
391 MALLOC(ptr, void *, items * size, M_TEMP, M_NOWAIT | M_ZERO);
392 return ptr;
393 }
394
395 static void
396 gz_free(void *opaque __unused, void *ptr)
397 {
398 FREE(ptr, M_TEMP);
399 }
400
Cache object: ec89981a6c503cfe0a555cef1443f6cf
|