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/9.2/sys/kern/kern_gzio.c 233353 2012-03-23 11:26: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     int vfslocked;
  223 
  224     if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
  225 
  226     s->stream.next_in = (Bytef*)buf;
  227     s->stream.avail_in = len;
  228 
  229     curoff = s->outoff;
  230     while (s->stream.avail_in != 0) {
  231 
  232         if (s->stream.avail_out == 0) {
  233 
  234             s->stream.next_out = s->outbuf;
  235             vfslocked = VFS_LOCK_GIANT(s->file->v_mount);
  236             error = vn_rdwr_inchunks(UIO_WRITE, s->file, s->outbuf, Z_BUFSIZE,
  237                         curoff, UIO_SYSSPACE, IO_UNIT,
  238                         curproc->p_ucred, NOCRED, &resid, curthread);
  239             VFS_UNLOCK_GIANT(vfslocked);
  240             if (error) {
  241                 log(LOG_ERR, "gzwrite: vn_rdwr return %d\n", error);
  242                 curoff += Z_BUFSIZE - resid;
  243                 s->z_err = Z_ERRNO;
  244                 break;
  245             }
  246             curoff += Z_BUFSIZE;
  247             s->stream.avail_out = Z_BUFSIZE;
  248         }
  249         s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
  250         if (s->z_err != Z_OK) {
  251             log(LOG_ERR,
  252                 "gzwrite: deflate returned error %d\n", s->z_err);
  253             break;
  254         }
  255     }
  256 
  257     s->crc = ~crc32_raw(buf, len, ~s->crc);
  258     s->outoff = curoff;
  259 
  260     return (int)(len - s->stream.avail_in);
  261 }
  262 
  263 
  264 /* ===========================================================================
  265      Flushes all pending output into the compressed file. The parameter
  266    flush is as in the deflate() function.
  267 */
  268 local int do_flush (file, flush)
  269     gzFile file;
  270     int flush;
  271 {
  272     uInt len;
  273     int done = 0;
  274     gz_stream *s = (gz_stream*)file;
  275     off_t curoff = s->outoff;
  276     size_t resid;
  277     int vfslocked = 0;
  278     int error;
  279 
  280     if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
  281 
  282     if (s->stream.avail_in) {
  283         log(LOG_WARNING, "do_flush: avail_in non-zero on entry\n");
  284     } 
  285 
  286     s->stream.avail_in = 0; /* should be zero already anyway */
  287 
  288     for (;;) {
  289         len = Z_BUFSIZE - s->stream.avail_out;
  290 
  291         if (len != 0) {
  292             vfslocked = VFS_LOCK_GIANT(s->file->v_mount);
  293             error = vn_rdwr_inchunks(UIO_WRITE, s->file, s->outbuf, len, curoff,
  294                         UIO_SYSSPACE, IO_UNIT, curproc->p_ucred,
  295                         NOCRED, &resid, curthread);
  296             VFS_UNLOCK_GIANT(vfslocked);
  297             if (error) {
  298                 s->z_err = Z_ERRNO;
  299                 s->outoff = curoff + len - resid;
  300                 return Z_ERRNO;
  301             }
  302             s->stream.next_out = s->outbuf;
  303             s->stream.avail_out = Z_BUFSIZE;
  304             curoff += len;
  305         }
  306         if (done) break;
  307         s->z_err = deflate(&(s->stream), flush);
  308 
  309         /* Ignore the second of two consecutive flushes: */
  310         if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
  311 
  312         /* deflate has finished flushing only when it hasn't used up
  313          * all the available space in the output buffer: 
  314          */
  315         done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
  316  
  317         if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
  318     }
  319     s->outoff = curoff;
  320 
  321     return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
  322 }
  323 
  324 int ZEXPORT gzflush (file, flush)
  325      gzFile file;
  326      int flush;
  327 {
  328     gz_stream *s = (gz_stream*)file;
  329     int err = do_flush (file, flush);
  330 
  331     if (err) return err;
  332     return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
  333 }
  334 
  335 
  336 /* ===========================================================================
  337    Outputs a long in LSB order to the given file
  338 */
  339 local void putU32 (s, x)
  340     gz_stream *s;
  341     uint32_t x;
  342 {
  343     uint32_t xx;
  344     off_t curoff = s->outoff;
  345     ssize_t resid;
  346 
  347 #if BYTE_ORDER == BIG_ENDIAN
  348     xx = bswap32(x);
  349 #else
  350     xx = x;
  351 #endif
  352     vn_rdwr(UIO_WRITE, s->file, (caddr_t)&xx, sizeof(xx), curoff,
  353             UIO_SYSSPACE, IO_UNIT, curproc->p_ucred,
  354             NOCRED, &resid, curthread);
  355     s->outoff += sizeof(xx) - resid;
  356 }
  357 
  358 
  359 /* ===========================================================================
  360      Flushes all pending output if necessary, closes the compressed file
  361    and deallocates all the (de)compression state.
  362 */
  363 int ZEXPORT gzclose (file)
  364     gzFile file;
  365 {
  366     int err;
  367     gz_stream *s = (gz_stream*)file;
  368 
  369     if (s == NULL) return Z_STREAM_ERROR;
  370 
  371     if (s->mode == 'w') {
  372         err = do_flush (file, Z_FINISH);
  373         if (err != Z_OK) {
  374             log(LOG_ERR, "gzclose: do_flush failed (err %d)\n", err);
  375             return destroy((gz_stream*)file);
  376         }
  377 #if 0
  378         printf("gzclose: putting crc: %lld total: %lld\n",
  379             (long long)s->crc, (long long)s->stream.total_in);
  380         printf("sizeof uLong = %d\n", (int)sizeof(uLong));
  381 #endif
  382         putU32 (s, s->crc);
  383         putU32 (s, (uint32_t) s->stream.total_in);
  384     }
  385     return destroy((gz_stream*)file);
  386 }
  387 
  388 /*
  389  * Space allocation and freeing routines for use by zlib routines when called
  390  * from gzip modules.
  391  */
  392 static void *
  393 gz_alloc(void *notused __unused, u_int items, u_int size)
  394 {
  395     void *ptr;
  396 
  397     MALLOC(ptr, void *, items * size, M_TEMP, M_NOWAIT | M_ZERO);
  398     return ptr;
  399 }
  400                                      
  401 static void
  402 gz_free(void *opaque __unused, void *ptr)
  403 {
  404     FREE(ptr, M_TEMP);
  405 }
  406 

Cache object: 541e2286790d1c9be783591243a11da4


[ 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.