The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_gzio.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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.2/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: 576ca6f1df6a89297496ff1c26b493c5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.