Home | History | Annotate | Download | only in zlib
      1 /* gzlib.c -- zlib functions common to reading and writing gzip files
      2  * Copyright (C) 2004-2017 Mark Adler
      3  * For conditions of distribution and use, see copyright notice in zlib.h
      4  */
      5 
      6 #include "gzguts.h"
      7 
      8 #if defined(_WIN32) && !defined(__BORLANDC__) && !defined(__MINGW32__)
      9 #  define LSEEK _lseeki64
     10 #else
     11 #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
     12 #  define LSEEK lseek64
     13 #else
     14 #  define LSEEK lseek
     15 #endif
     16 #endif
     17 
     18 /* Local functions */
     19 local void gz_reset OF((gz_statep));
     20 local gzFile gz_open OF((const void *, int, const char *));
     21 
     22 #if defined UNDER_CE
     23 
     24 /* Map the Windows error number in ERROR to a locale-dependent error message
     25    string and return a pointer to it.  Typically, the values for ERROR come
     26    from GetLastError.
     27 
     28    The string pointed to shall not be modified by the application, but may be
     29    overwritten by a subsequent call to gz_strwinerror
     30 
     31    The gz_strwinerror function does not change the current setting of
     32    GetLastError. */
     33 char ZLIB_INTERNAL *gz_strwinerror (error)
     34      DWORD error;
     35 {
     36     static char buf[1024];
     37 
     38     wchar_t *msgbuf;
     39     DWORD lasterr = GetLastError();
     40     DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
     41         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
     42         NULL,
     43         error,
     44         0, /* Default language */
     45         (LPVOID)&msgbuf,
     46         0,
     47         NULL);
     48     if (chars != 0) {
     49         /* If there is an \r\n appended, zap it.  */
     50         if (chars >= 2
     51             && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
     52             chars -= 2;
     53             msgbuf[chars] = 0;
     54         }
     55 
     56         if (chars > sizeof (buf) - 1) {
     57             chars = sizeof (buf) - 1;
     58             msgbuf[chars] = 0;
     59         }
     60 
     61         wcstombs(buf, msgbuf, chars + 1);
     62         LocalFree(msgbuf);
     63     }
     64     else {
     65         sprintf(buf, "unknown win32 error (%ld)", error);
     66     }
     67 
     68     SetLastError(lasterr);
     69     return buf;
     70 }
     71 
     72 #endif /* UNDER_CE */
     73 
     74 /* Reset gzip file state */
     75 local void gz_reset(state)
     76     gz_statep state;
     77 {
     78     state->x.have = 0;              /* no output data available */
     79     if (state->mode == GZ_READ) {   /* for reading ... */
     80         state->eof = 0;             /* not at end of file */
     81         state->past = 0;            /* have not read past end yet */
     82         state->how = LOOK;          /* look for gzip header */
     83     }
     84     state->seek = 0;                /* no seek request pending */
     85     gz_error(state, Z_OK, NULL);    /* clear error */
     86     state->x.pos = 0;               /* no uncompressed data yet */
     87     state->strm.avail_in = 0;       /* no input data yet */
     88 }
     89 
     90 /* Open a gzip file either by name or file descriptor. */
     91 local gzFile gz_open(path, fd, mode)
     92     const void *path;
     93     int fd;
     94     const char *mode;
     95 {
     96     gz_statep state;
     97     z_size_t len;
     98     int oflag;
     99 #ifdef O_CLOEXEC
    100     int cloexec = 0;
    101 #endif
    102 #ifdef O_EXCL
    103     int exclusive = 0;
    104 #endif
    105 
    106     /* check input */
    107     if (path == NULL)
    108         return NULL;
    109 
    110     /* allocate gzFile structure to return */
    111     state = (gz_statep)malloc(sizeof(gz_state));
    112     if (state == NULL)
    113         return NULL;
    114     state->size = 0;            /* no buffers allocated yet */
    115     state->want = GZBUFSIZE;    /* requested buffer size */
    116     state->msg = NULL;          /* no error message yet */
    117 
    118     /* interpret mode */
    119     state->mode = GZ_NONE;
    120     state->level = Z_DEFAULT_COMPRESSION;
    121     state->strategy = Z_DEFAULT_STRATEGY;
    122     state->direct = 0;
    123     while (*mode) {
    124         if (*mode >= '0' && *mode <= '9')
    125             state->level = *mode - '0';
    126         else
    127             switch (*mode) {
    128             case 'r':
    129                 state->mode = GZ_READ;
    130                 break;
    131 #ifndef NO_GZCOMPRESS
    132             case 'w':
    133                 state->mode = GZ_WRITE;
    134                 break;
    135             case 'a':
    136                 state->mode = GZ_APPEND;
    137                 break;
    138 #endif
    139             case '+':       /* can't read and write at the same time */
    140                 free(state);
    141                 return NULL;
    142             case 'b':       /* ignore -- will request binary anyway */
    143                 break;
    144 #ifdef O_CLOEXEC
    145             case 'e':
    146                 cloexec = 1;
    147                 break;
    148 #endif
    149 #ifdef O_EXCL
    150             case 'x':
    151                 exclusive = 1;
    152                 break;
    153 #endif
    154             case 'f':
    155                 state->strategy = Z_FILTERED;
    156                 break;
    157             case 'h':
    158                 state->strategy = Z_HUFFMAN_ONLY;
    159                 break;
    160             case 'R':
    161                 state->strategy = Z_RLE;
    162                 break;
    163             case 'F':
    164                 state->strategy = Z_FIXED;
    165                 break;
    166             case 'T':
    167                 state->direct = 1;
    168                 break;
    169             default:        /* could consider as an error, but just ignore */
    170                 ;
    171             }
    172         mode++;
    173     }
    174 
    175     /* must provide an "r", "w", or "a" */
    176     if (state->mode == GZ_NONE) {
    177         free(state);
    178         return NULL;
    179     }
    180 
    181     /* can't force transparent read */
    182     if (state->mode == GZ_READ) {
    183         if (state->direct) {
    184             free(state);
    185             return NULL;
    186         }
    187         state->direct = 1;      /* for empty file */
    188     }
    189 
    190     /* save the path name for error messages */
    191 #ifdef WIDECHAR
    192     if (fd == -2) {
    193         len = wcstombs(NULL, path, 0);
    194         if (len == (z_size_t)-1)
    195             len = 0;
    196     }
    197     else
    198 #endif
    199         len = strlen((const char *)path);
    200     state->path = (char *)malloc(len + 1);
    201     if (state->path == NULL) {
    202         free(state);
    203         return NULL;
    204     }
    205 #ifdef WIDECHAR
    206     if (fd == -2)
    207         if (len)
    208             wcstombs(state->path, path, len + 1);
    209         else
    210             *(state->path) = 0;
    211     else
    212 #endif
    213 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
    214         (void)snprintf(state->path, len + 1, "%s", (const char *)path);
    215 #else
    216         strcpy(state->path, path);
    217 #endif
    218 
    219     /* compute the flags for open() */
    220     oflag =
    221 #ifdef O_LARGEFILE
    222         O_LARGEFILE |
    223 #endif
    224 #ifdef O_BINARY
    225         O_BINARY |
    226 #endif
    227 #ifdef O_CLOEXEC
    228         (cloexec ? O_CLOEXEC : 0) |
    229 #endif
    230         (state->mode == GZ_READ ?
    231          O_RDONLY :
    232          (O_WRONLY | O_CREAT |
    233 #ifdef O_EXCL
    234           (exclusive ? O_EXCL : 0) |
    235 #endif
    236           (state->mode == GZ_WRITE ?
    237            O_TRUNC :
    238            O_APPEND)));
    239 
    240     /* open the file with the appropriate flags (or just use fd) */
    241     state->fd = fd > -1 ? fd : (
    242 #ifdef WIDECHAR
    243         fd == -2 ? _wopen(path, oflag, 0666) :
    244 #endif
    245         open((const char *)path, oflag, 0666));
    246     if (state->fd == -1) {
    247         free(state->path);
    248         free(state);
    249         return NULL;
    250     }
    251     if (state->mode == GZ_APPEND) {
    252         LSEEK(state->fd, 0, SEEK_END);  /* so gzoffset() is correct */
    253         state->mode = GZ_WRITE;         /* simplify later checks */
    254     }
    255 
    256     /* save the current position for rewinding (only if reading) */
    257     if (state->mode == GZ_READ) {
    258         state->start = LSEEK(state->fd, 0, SEEK_CUR);
    259         if (state->start == -1) state->start = 0;
    260     }
    261 
    262     /* initialize stream */
    263     gz_reset(state);
    264 
    265     /* return stream */
    266     return (gzFile)state;
    267 }
    268 
    269 /* -- see zlib.h -- */
    270 gzFile ZEXPORT gzopen(path, mode)
    271     const char *path;
    272     const char *mode;
    273 {
    274     return gz_open(path, -1, mode);
    275 }
    276 
    277 /* -- see zlib.h -- */
    278 gzFile ZEXPORT gzopen64(path, mode)
    279     const char *path;
    280     const char *mode;
    281 {
    282     return gz_open(path, -1, mode);
    283 }
    284 
    285 /* -- see zlib.h -- */
    286 gzFile ZEXPORT gzdopen(fd, mode)
    287     int fd;
    288     const char *mode;
    289 {
    290     char *path;         /* identifier for error messages */
    291     gzFile gz;
    292 
    293     if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
    294         return NULL;
    295 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
    296     (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
    297 #else
    298     sprintf(path, "<fd:%d>", fd);   /* for debugging */
    299 #endif
    300     gz = gz_open(path, fd, mode);
    301     free(path);
    302     return gz;
    303 }
    304 
    305 /* -- see zlib.h -- */
    306 #ifdef WIDECHAR
    307 gzFile ZEXPORT gzopen_w(path, mode)
    308     const wchar_t *path;
    309     const char *mode;
    310 {
    311     return gz_open(path, -2, mode);
    312 }
    313 #endif
    314 
    315 /* -- see zlib.h -- */
    316 int ZEXPORT gzbuffer(file, size)
    317     gzFile file;
    318     unsigned size;
    319 {
    320     gz_statep state;
    321 
    322     /* get internal structure and check integrity */
    323     if (file == NULL)
    324         return -1;
    325     state = (gz_statep)file;
    326     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    327         return -1;
    328 
    329     /* make sure we haven't already allocated memory */
    330     if (state->size != 0)
    331         return -1;
    332 
    333     /* check and set requested size */
    334     if ((size << 1) < size)
    335         return -1;              /* need to be able to double it */
    336     if (size < 2)
    337         size = 2;               /* need two bytes to check magic header */
    338     state->want = size;
    339     return 0;
    340 }
    341 
    342 /* -- see zlib.h -- */
    343 int ZEXPORT gzrewind(file)
    344     gzFile file;
    345 {
    346     gz_statep state;
    347 
    348     /* get internal structure */
    349     if (file == NULL)
    350         return -1;
    351     state = (gz_statep)file;
    352 
    353     /* check that we're reading and that there's no error */
    354     if (state->mode != GZ_READ ||
    355             (state->err != Z_OK && state->err != Z_BUF_ERROR))
    356         return -1;
    357 
    358     /* back up and start over */
    359     if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
    360         return -1;
    361     gz_reset(state);
    362     return 0;
    363 }
    364 
    365 /* -- see zlib.h -- */
    366 z_off64_t ZEXPORT gzseek64(file, offset, whence)
    367     gzFile file;
    368     z_off64_t offset;
    369     int whence;
    370 {
    371     unsigned n;
    372     z_off64_t ret;
    373     gz_statep state;
    374 
    375     /* get internal structure and check integrity */
    376     if (file == NULL)
    377         return -1;
    378     state = (gz_statep)file;
    379     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    380         return -1;
    381 
    382     /* check that there's no error */
    383     if (state->err != Z_OK && state->err != Z_BUF_ERROR)
    384         return -1;
    385 
    386     /* can only seek from start or relative to current position */
    387     if (whence != SEEK_SET && whence != SEEK_CUR)
    388         return -1;
    389 
    390     /* normalize offset to a SEEK_CUR specification */
    391     if (whence == SEEK_SET)
    392         offset -= state->x.pos;
    393     else if (state->seek)
    394         offset += state->skip;
    395     state->seek = 0;
    396 
    397     /* if within raw area while reading, just go there */
    398     if (state->mode == GZ_READ && state->how == COPY &&
    399             state->x.pos + offset >= 0) {
    400         ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
    401         if (ret == -1)
    402             return -1;
    403         state->x.have = 0;
    404         state->eof = 0;
    405         state->past = 0;
    406         state->seek = 0;
    407         gz_error(state, Z_OK, NULL);
    408         state->strm.avail_in = 0;
    409         state->x.pos += offset;
    410         return state->x.pos;
    411     }
    412 
    413     /* calculate skip amount, rewinding if needed for back seek when reading */
    414     if (offset < 0) {
    415         if (state->mode != GZ_READ)         /* writing -- can't go backwards */
    416             return -1;
    417         offset += state->x.pos;
    418         if (offset < 0)                     /* before start of file! */
    419             return -1;
    420         if (gzrewind(file) == -1)           /* rewind, then skip to offset */
    421             return -1;
    422     }
    423 
    424     /* if reading, skip what's in output buffer (one less gzgetc() check) */
    425     if (state->mode == GZ_READ) {
    426         n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
    427             (unsigned)offset : state->x.have;
    428         state->x.have -= n;
    429         state->x.next += n;
    430         state->x.pos += n;
    431         offset -= n;
    432     }
    433 
    434     /* request skip (if not zero) */
    435     if (offset) {
    436         state->seek = 1;
    437         state->skip = offset;
    438     }
    439     return state->x.pos + offset;
    440 }
    441 
    442 /* -- see zlib.h -- */
    443 z_off_t ZEXPORT gzseek(file, offset, whence)
    444     gzFile file;
    445     z_off_t offset;
    446     int whence;
    447 {
    448     z_off64_t ret;
    449 
    450     ret = gzseek64(file, (z_off64_t)offset, whence);
    451     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
    452 }
    453 
    454 /* -- see zlib.h -- */
    455 z_off64_t ZEXPORT gztell64(file)
    456     gzFile file;
    457 {
    458     gz_statep state;
    459 
    460     /* get internal structure and check integrity */
    461     if (file == NULL)
    462         return -1;
    463     state = (gz_statep)file;
    464     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    465         return -1;
    466 
    467     /* return position */
    468     return state->x.pos + (state->seek ? state->skip : 0);
    469 }
    470 
    471 /* -- see zlib.h -- */
    472 z_off_t ZEXPORT gztell(file)
    473     gzFile file;
    474 {
    475     z_off64_t ret;
    476 
    477     ret = gztell64(file);
    478     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
    479 }
    480 
    481 /* -- see zlib.h -- */
    482 z_off64_t ZEXPORT gzoffset64(file)
    483     gzFile file;
    484 {
    485     z_off64_t offset;
    486     gz_statep state;
    487 
    488     /* get internal structure and check integrity */
    489     if (file == NULL)
    490         return -1;
    491     state = (gz_statep)file;
    492     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    493         return -1;
    494 
    495     /* compute and return effective offset in file */
    496     offset = LSEEK(state->fd, 0, SEEK_CUR);
    497     if (offset == -1)
    498         return -1;
    499     if (state->mode == GZ_READ)             /* reading */
    500         offset -= state->strm.avail_in;     /* don't count buffered input */
    501     return offset;
    502 }
    503 
    504 /* -- see zlib.h -- */
    505 z_off_t ZEXPORT gzoffset(file)
    506     gzFile file;
    507 {
    508     z_off64_t ret;
    509 
    510     ret = gzoffset64(file);
    511     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
    512 }
    513 
    514 /* -- see zlib.h -- */
    515 int ZEXPORT gzeof(file)
    516     gzFile file;
    517 {
    518     gz_statep state;
    519 
    520     /* get internal structure and check integrity */
    521     if (file == NULL)
    522         return 0;
    523     state = (gz_statep)file;
    524     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    525         return 0;
    526 
    527     /* return end-of-file state */
    528     return state->mode == GZ_READ ? state->past : 0;
    529 }
    530 
    531 /* -- see zlib.h -- */
    532 const char * ZEXPORT gzerror(file, errnum)
    533     gzFile file;
    534     int *errnum;
    535 {
    536     gz_statep state;
    537 
    538     /* get internal structure and check integrity */
    539     if (file == NULL)
    540         return NULL;
    541     state = (gz_statep)file;
    542     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    543         return NULL;
    544 
    545     /* return error information */
    546     if (errnum != NULL)
    547         *errnum = state->err;
    548     return state->err == Z_MEM_ERROR ? "out of memory" :
    549                                        (state->msg == NULL ? "" : state->msg);
    550 }
    551 
    552 /* -- see zlib.h -- */
    553 void ZEXPORT gzclearerr(file)
    554     gzFile file;
    555 {
    556     gz_statep state;
    557 
    558     /* get internal structure and check integrity */
    559     if (file == NULL)
    560         return;
    561     state = (gz_statep)file;
    562     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    563         return;
    564 
    565     /* clear error and end-of-file */
    566     if (state->mode == GZ_READ) {
    567         state->eof = 0;
    568         state->past = 0;
    569     }
    570     gz_error(state, Z_OK, NULL);
    571 }
    572 
    573 /* Create an error message in allocated memory and set state->err and
    574    state->msg accordingly.  Free any previous error message already there.  Do
    575    not try to free or allocate space if the error is Z_MEM_ERROR (out of
    576    memory).  Simply save the error message as a static string.  If there is an
    577    allocation failure constructing the error message, then convert the error to
    578    out of memory. */
    579 void ZLIB_INTERNAL gz_error(state, err, msg)
    580     gz_statep state;
    581     int err;
    582     const char *msg;
    583 {
    584     /* free previously allocated message and clear */
    585     if (state->msg != NULL) {
    586         if (state->err != Z_MEM_ERROR)
    587             free(state->msg);
    588         state->msg = NULL;
    589     }
    590 
    591     /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
    592     if (err != Z_OK && err != Z_BUF_ERROR)
    593         state->x.have = 0;
    594 
    595     /* set error code, and if no message, then done */
    596     state->err = err;
    597     if (msg == NULL)
    598         return;
    599 
    600     /* for an out of memory error, return literal string when requested */
    601     if (err == Z_MEM_ERROR)
    602         return;
    603 
    604     /* construct error message with path */
    605     if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
    606             NULL) {
    607         state->err = Z_MEM_ERROR;
    608         return;
    609     }
    610 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
    611     (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
    612                    "%s%s%s", state->path, ": ", msg);
    613 #else
    614     strcpy(state->msg, state->path);
    615     strcat(state->msg, ": ");
    616     strcat(state->msg, msg);
    617 #endif
    618 }
    619 
    620 #ifndef INT_MAX
    621 /* portably return maximum value for an int (when limits.h presumed not
    622    available) -- we need to do this to cover cases where 2's complement not
    623    used, since C standard permits 1's complement and sign-bit representations,
    624    otherwise we could just use ((unsigned)-1) >> 1 */
    625 unsigned ZLIB_INTERNAL gz_intmax()
    626 {
    627     unsigned p, q;
    628 
    629     p = 1;
    630     do {
    631         q = p;
    632         p <<= 1;
    633         p++;
    634     } while (p > q);
    635     return q >> 1;
    636 }
    637 #endif
    638