Home | History | Annotate | Download | only in sys
      1 /* ----------------------------------------------------------------------- *
      2  *
      3  *   Copyright 2003-2008 H. Peter Anvin - All Rights Reserved
      4  *
      5  *   Permission is hereby granted, free of charge, to any person
      6  *   obtaining a copy of this software and associated documentation
      7  *   files (the "Software"), to deal in the Software without
      8  *   restriction, including without limitation the rights to use,
      9  *   copy, modify, merge, publish, distribute, sublicense, and/or
     10  *   sell copies of the Software, and to permit persons to whom
     11  *   the Software is furnished to do so, subject to the following
     12  *   conditions:
     13  *
     14  *   The above copyright notice and this permission notice shall
     15  *   be included in all copies or substantial portions of the Software.
     16  *
     17  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     18  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
     19  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     20  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
     21  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     22  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     23  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     24  *   OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  * ----------------------------------------------------------------------- */
     27 
     28 #include <errno.h>
     29 #include <string.h>
     30 #include <unistd.h>
     31 #include <fcntl.h>
     32 #include <stdlib.h>
     33 #include <syslinux/zio.h>
     34 
     35 #include "file.h"
     36 #include "zlib.h"
     37 
     38 /*
     39  * zopen.c
     40  *
     41  * Open an ordinary file, possibly compressed; if so, insert
     42  * an appropriate decompressor.
     43  */
     44 
     45 int __file_get_block(struct file_info *fp);
     46 int __file_close(struct file_info *fp);
     47 
     48 static ssize_t gzip_file_read(struct file_info *, void *, size_t);
     49 static int gzip_file_close(struct file_info *);
     50 
     51 static const struct input_dev gzip_file_dev = {
     52     .dev_magic = __DEV_MAGIC,
     53     .flags = __DEV_FILE | __DEV_INPUT,
     54     .fileflags = O_RDONLY,
     55     .read = gzip_file_read,
     56     .close = gzip_file_close,
     57     .open = NULL,
     58 };
     59 
     60 static int gzip_file_init(struct file_info *fp)
     61 {
     62     z_streamp zs = calloc(1, sizeof(z_stream));
     63 
     64     if (!zs)
     65 	return -1;
     66 
     67     fp->i.pvt = zs;
     68 
     69     zs->next_in = (void *)fp->i.datap;
     70     zs->avail_in = fp->i.nbytes;
     71 
     72     if (inflateInit2(zs, 15 + 32) != Z_OK) {
     73 	errno = EIO;
     74 	return -1;
     75     }
     76 
     77     fp->iop = &gzip_file_dev;
     78     fp->i.fd.size = -1;		/* Unknown */
     79 
     80     return 0;
     81 }
     82 
     83 static ssize_t gzip_file_read(struct file_info *fp, void *ptr, size_t n)
     84 {
     85     z_streamp zs = fp->i.pvt;
     86     int rv;
     87     ssize_t bytes;
     88     ssize_t nout = 0;
     89     unsigned char *p = ptr;
     90 
     91     while (n) {
     92 	zs->next_out = p;
     93 	zs->avail_out = n;
     94 
     95 	if (!zs->avail_in && fp->i.fd.handle) {
     96 	    if (__file_get_block(fp))
     97 		return nout ? nout : -1;
     98 
     99 	    zs->next_in = (void *)fp->i.datap;
    100 	    zs->avail_in = fp->i.nbytes;
    101 	}
    102 
    103 	rv = inflate(zs, Z_SYNC_FLUSH);
    104 
    105 	bytes = n - zs->avail_out;
    106 	nout += bytes;
    107 	p += bytes;
    108 	n -= bytes;
    109 
    110 	switch (rv) {
    111 	case Z_DATA_ERROR:
    112 	case Z_NEED_DICT:
    113 	case Z_BUF_ERROR:
    114 	case Z_STREAM_ERROR:
    115 	default:
    116 	    errno = EIO;
    117 	    return nout ? nout : -1;
    118 	case Z_MEM_ERROR:
    119 	    errno = ENOMEM;
    120 	    return nout ? nout : -1;
    121 	case Z_STREAM_END:
    122 	    return nout;
    123 	case Z_OK:
    124 	    break;
    125 	}
    126     }
    127 
    128     return nout;
    129 }
    130 
    131 static int gzip_file_close(struct file_info *fp)
    132 {
    133     z_streamp zs = fp->i.pvt;
    134 
    135     inflateEnd(zs);
    136     free(zs);
    137     return __file_close(fp);
    138 }
    139 
    140 int zopen(const char *pathname, int flags, ...)
    141 {
    142     int fd, rv;
    143     struct file_info *fp;
    144 
    145     /* We don't actually give a hoot about the creation bits... */
    146     fd = open(pathname, flags, 0);
    147 
    148     if (fd < 0)
    149 	return -1;
    150 
    151     fp = &__file_info[fd];
    152 
    153     /* Need to get the first block into the buffer, but not consumed */
    154     if (__file_get_block(fp))
    155 	goto err;
    156 
    157     if (fp->i.nbytes >= 14 &&
    158 	(uint8_t) fp->i.buf[0] == 037 &&
    159 	(uint8_t) fp->i.buf[1] == 0213 &&	/* gzip */
    160 	fp->i.buf[2] == 8)	/* deflate */
    161 	rv = gzip_file_init(fp);
    162     else
    163 	rv = 0;			/* Plain file */
    164 
    165     if (!rv)
    166 	return fd;
    167 
    168 err:
    169     close(fd);
    170     return -1;
    171 }
    172