rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

rpmio/gzdio.c
Go to the documentation of this file.

    00001
    00006 #include "system.h"
    00007
    00008 #if     defined(NOTYET) || defined(__LCLINT__)
    00009 #include <stdbool.h>
    00010 #else
    00011 typedef enum { true = 1, false = 0 } bool;
    00012 #endif
    00013
    00014 #include "rpmio_internal.h"
    00015 #include <rpmmacro.h>
    00016 #include <rpmcb.h>
    00017
    00018 #if defined(WITH_ZLIB)
    00019
    00020 /*@-noparams@*/
    00021 #include <zlib.h>
    00022 /*@=noparams@*/
    00023
    00024 #include "debug.h"
    00025
    00026 /*@access FD_t @*/
    00027
    00028 #define GZDONLY(fd)     assert(fdGetIo(fd) == gzdio)
    00029
    00030 typedef struct cpio_state_s {
    00031     rpmuint32_t n;                      /* byte progress in cpio header */
    00032     rpmuint32_t mode;                   /* file attributes */
    00033     rpmuint32_t nlnk;
    00034     rpmuint32_t size;
    00035 } * cpio_state;
    00036
    00037 #define RSYNC_WIN 4096
    00038
    00039 typedef struct rsync_state_s {
    00040     rpmuint32_t n;                      /* number of elements in the window */
    00041     rpmuint32_t sum;                    /* current sum */
    00042     unsigned char win[RSYNC_WIN];       /* window elements */
    00043 } * rsync_state;
    00044
    00045 typedef struct rpmGZFILE_s {
    00046     gzFile gz;                          /* gzFile is a pointer */
    00047     struct rsync_state_s rs;
    00048     struct cpio_state_s cs;
    00049     rpmuint32_t nb;                     /* bytes pending for sync */
    00050 } * rpmGZFILE;                          /* like FILE, to use with star */
    00051
    00052 /* Should gzflush be called only after RSYNC_WIN boundaries? */
    00053 /*@unchecked@*/
    00054 static int enable_rsync = 1;
    00055
    00056 /* =============================================================== */
    00057 /* from ../lib/cpio.h */
    00058 #define CPIO_NEWC_MAGIC "070701"
    00059 #define PHYS_HDR_SIZE 110
    00060
    00061 #define OFFSET_MODE (sizeof(CPIO_NEWC_MAGIC)-1 + 1*8)
    00062 #define OFFSET_NLNK (sizeof(CPIO_NEWC_MAGIC)-1 + 4*8)
    00063 #define OFFSET_SIZE (sizeof(CPIO_NEWC_MAGIC)-1 + 6*8)
    00064
    00065 static inline
    00066 int hex(char c)
    00067         /*@*/
    00068 {
    00069     if (c >= '0' && c <= '9')
    00070         return (int)(c - '0');
    00071     else if (c >= 'a' && c <= 'f')
    00072         return (int)(c - 'a') + 10;
    00073     else if (c >= 'A' && c <= 'F')
    00074         return (int)(c - 'A') + 10;
    00075     return -1;
    00076 }
    00077
    00078 static inline
    00079 bool cpio_next(cpio_state s, unsigned char c)
    00080         /*@modifies s @*/
    00081 {
    00082     if (s->n >= sizeof(CPIO_NEWC_MAGIC)-1) {
    00083         int d = hex(c);
    00084         if (d < 0) {
    00085             s->n = 0;
    00086             return false;
    00087         }
    00088         if (0){} /* indent */
    00089         else if (s->n >= OFFSET_MODE && s->n < OFFSET_MODE+8) {
    00090             if (s->n == OFFSET_MODE)
    00091                 s->mode = 0;
    00092             else
    00093                 s->mode <<= 4;
    00094             s->mode |= d;
    00095         }
    00096         else if (s->n >= OFFSET_NLNK && s->n < OFFSET_NLNK+8) {
    00097             if (s->n == OFFSET_NLNK)
    00098                 s->nlnk = 0;
    00099             else
    00100                 s->nlnk <<= 4;
    00101             s->nlnk |= d;
    00102         }
    00103         else if (s->n >= OFFSET_SIZE && s->n < OFFSET_SIZE+8) {
    00104             if (s->n == OFFSET_SIZE)
    00105                 s->size = 0;
    00106             else
    00107                 s->size <<= 4;
    00108             s->size |= d;
    00109         }
    00110         s->n++;
    00111         if (s->n >= PHYS_HDR_SIZE) {
    00112             s->n = 0;
    00113             if (!S_ISREG(s->mode) || s->nlnk != 1)
    00114                 /* no file data */
    00115                 s->size = 0;
    00116             return true;
    00117         }
    00118     }
    00119     else if (CPIO_NEWC_MAGIC[s->n] == c) {
    00120         s->n++;
    00121     }
    00122     else {
    00123         s->n = 0;
    00124     }
    00125     return false;
    00126 }
    00127
    00128 /* =============================================================== */
    00129 static inline
    00130 bool rsync_next(rsync_state s, unsigned char c)
    00131         /*@modifies s @*/
    00132 {
    00133     rpmuint32_t i;
    00134
    00135     if (s->n < RSYNC_WIN) {             /* not enough elements */
    00136         s->sum += (rpmuint32_t)c;       /* update the sum */
    00137         s->win[s->n++] = c;             /* remember the element */
    00138         return false;                   /* no match */
    00139     }
    00140     i = s->n++ % RSYNC_WIN;             /* wrap up */
    00141     s->sum -= (rpmuint32_t)s->win[i];   /* move the window on */
    00142     s->sum += (rpmuint32_t)c;
    00143     s->win[i] = c;
    00144     if (s->sum % RSYNC_WIN == 0) {      /* match */
    00145         s->n = 0;                       /* reset */
    00146         s->sum = 0;
    00147         return true;
    00148     }
    00149     return false;
    00150 }
    00151
    00152 #define CHUNK 4096
    00153
    00154 static inline
    00155 bool sync_hint(rpmGZFILE rpmgz, unsigned char c)
    00156         /*@modifies rpmgz @*/
    00157 {
    00158     bool cpio_hint;
    00159     bool rsync_hint;
    00160
    00161     rpmgz->nb++;
    00162     cpio_hint = cpio_next(&rpmgz->cs, c);
    00163     if (cpio_hint) {
    00164         /* cpio header/data boundary */
    00165         rpmgz->rs.n = rpmgz->rs.sum = 0;
    00166         if (rpmgz->nb >= 2*CHUNK)
    00167             /* better sync here */
    00168             goto cpio_sync;
    00169         if (rpmgz->cs.size < CHUNK)
    00170             /* file is too small */
    00171             return false;
    00172         if (rpmgz->nb < CHUNK/2)
    00173             /* not enough pending bytes */
    00174             return false;
    00175     cpio_sync:
    00176         rpmgz->nb = 0;
    00177         return true;
    00178     }
    00179     rsync_hint = rsync_next(&rpmgz->rs, c);
    00180     if (rsync_hint) {
    00181         /* rolling checksum match */
    00182         assert(rpmgz->nb >= RSYNC_WIN);
    00183         rpmgz->nb = 0;
    00184         return true;
    00185     }
    00186     return false;
    00187 }
    00188
    00189 static ssize_t
    00190 rsyncable_gzwrite(rpmGZFILE rpmgz, const unsigned char *const buf, const size_t len)
    00191         /*@modifies rpmgz @*/
    00192 {
    00193     ssize_t rc;
    00194     size_t n;
    00195     ssize_t n_written = 0;
    00196     const unsigned char *begin = buf;
    00197     size_t i;
    00198
    00199     for (i = 0; i < len; i++) {
    00200         if (!sync_hint(rpmgz, buf[i]))
    00201             continue;
    00202         n = i + 1 - (begin - buf);
    00203         rc = gzwrite(rpmgz->gz, begin, (unsigned)n);
    00204         if (rc < 0)
    00205             return (n_written ? n_written : rc);
    00206         n_written += rc;
    00207         if (rc < (ssize_t)n)
    00208             return n_written;
    00209         begin += n;
    00210         rc = gzflush(rpmgz->gz, Z_SYNC_FLUSH);
    00211         if (rc < 0)
    00212             return (n_written ? n_written : rc);
    00213     }
    00214     if (begin < buf + len) {
    00215         n = len - (begin - buf);
    00216         rc = gzwrite(rpmgz->gz, begin, (unsigned)n);
    00217         if (rc < 0)
    00218             return (n_written ? n_written : rc);
    00219         n_written += rc;
    00220     }
    00221     return n_written;
    00222 }
    00223
    00224 /* =============================================================== */
    00225 /*@-moduncon@*/
    00226
    00227 static inline /*@dependent@*/ /*@null@*/ void * gzdFileno(FD_t fd)
    00228         /*@*/
    00229 {
    00230     void * rc = NULL;
    00231     int i;
    00232
    00233     FDSANE(fd);
    00234     for (i = fd->nfps; i >= 0; i--) {
    00235         FDSTACK_t * fps = &fd->fps[i];
    00236         if (fps->io != gzdio)
    00237             continue;
    00238         rc = fps->fp;
    00239         break;
    00240     }
    00241
    00242     return rc;
    00243 }
    00244
    00245 static /*@null@*/
    00246 FD_t gzdOpen(const char * path, const char * fmode)
    00247         /*@globals fileSystem, internalState @*/
    00248         /*@modifies fileSystem, internalState @*/
    00249 {
    00250     FD_t fd;
    00251     rpmGZFILE rpmgz;
    00252     mode_t mode = (fmode && fmode[0] == 'w' ? O_WRONLY : O_RDONLY);
    00253
    00254     rpmgz = xcalloc(1, sizeof(*rpmgz));
    00255     rpmgz->gz = gzopen(path, fmode);
    00256     if (rpmgz->gz == NULL) {
    00257         rpmgz = _free(rpmgz);
    00258         return NULL;
    00259     }
    00260     fd = fdNew("open (gzdOpen)");
    00261     fdPop(fd); fdPush(fd, gzdio, rpmgz, -1);
    00262     fdSetOpen(fd, path, -1, mode);
    00263
    00264 DBGIO(fd, (stderr, "==>\tgzdOpen(\"%s\", \"%s\") fd %p %s\n", path, fmode, (fd ? fd : NULL), fdbg(fd)));
    00265     return fdLink(fd, "gzdOpen");
    00266 }
    00267
    00268 static /*@null@*/ FD_t gzdFdopen(void * cookie, const char *fmode)
    00269         /*@globals fileSystem, internalState @*/
    00270         /*@modifies fileSystem, internalState @*/
    00271 {
    00272     FD_t fd = c2f(cookie);
    00273     int fdno;
    00274     rpmGZFILE rpmgz;
    00275
    00276     if (fmode == NULL) return NULL;
    00277     fdno = fdFileno(fd);
    00278     fdSetFdno(fd, -1);          /* XXX skip the fdio close */
    00279     if (fdno < 0) return NULL;
    00280     rpmgz = xcalloc(1, sizeof(*rpmgz));
    00281     rpmgz->gz = gzdopen(fdno, fmode);
    00282     if (rpmgz->gz == NULL) {
    00283         rpmgz = _free(rpmgz);
    00284         return NULL;
    00285     }
    00286
    00287     fdPush(fd, gzdio, rpmgz, fdno);             /* Push gzdio onto stack */
    00288
    00289     return fdLink(fd, "gzdFdopen");
    00290 }
    00291
    00292 static int gzdFlush(void * cookie)
    00293         /*@*/
    00294 {
    00295     FD_t fd = c2f(cookie);
    00296     rpmGZFILE rpmgz;
    00297     rpmgz = gzdFileno(fd);
    00298     if (rpmgz == NULL) return -2;
    00299     return gzflush(rpmgz->gz, Z_SYNC_FLUSH);    /* XXX W2DO? */
    00300 }
    00301
    00302 /* =============================================================== */
    00303 /*@-mustmod@*/
    00304 static ssize_t gzdRead(void * cookie, /*@out@*/ char * buf, size_t count)
    00305         /*@globals fileSystem, internalState @*/
    00306         /*@modifies buf, fileSystem, internalState @*/
    00307 {
    00308     FD_t fd = c2f(cookie);
    00309     rpmGZFILE rpmgz;
    00310     ssize_t rc;
    00311
    00312     if (fd == NULL || fd->bytesRemain == 0) return 0;   /* XXX simulate EOF */
    00313
    00314     rpmgz = gzdFileno(fd);
    00315     if (rpmgz == NULL) return -2;       /* XXX can't happen */
    00316
    00317     fdstat_enter(fd, FDSTAT_READ);
    00318     rc = gzread(rpmgz->gz, buf, (unsigned)count);
    00319 DBGIO(fd, (stderr, "==>\tgzdRead(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
    00320     if (rc < 0) {
    00321         int zerror = 0;
    00322         fd->errcookie = gzerror(rpmgz->gz, &zerror);
    00323         if (zerror == Z_ERRNO) {
    00324             fd->syserrno = errno;
    00325             fd->errcookie = strerror(fd->syserrno);
    00326         }
    00327     } else {
    00328         fdstat_exit(fd, FDSTAT_READ, (rc > 0 ? rc : 0));
    00329         if (fd->ndigests && rc > 0) fdUpdateDigests(fd, (void *)buf, rc);
    00330     }
    00331     return rc;
    00332 }
    00333 /*@=mustmod@*/
    00334
    00335 static ssize_t gzdWrite(void * cookie, const char * buf, size_t count)
    00336         /*@globals fileSystem, internalState @*/
    00337         /*@modifies fileSystem, internalState @*/
    00338 {
    00339     FD_t fd = c2f(cookie);
    00340     rpmGZFILE rpmgz;
    00341     ssize_t rc;
    00342
    00343     if (fd == NULL || fd->bytesRemain == 0) return 0;   /* XXX simulate EOF */
    00344
    00345     if (fd->ndigests && count > 0) fdUpdateDigests(fd, (void *)buf, count);
    00346
    00347     rpmgz = gzdFileno(fd);
    00348     if (rpmgz == NULL) return -2;       /* XXX can't happen */
    00349
    00350     fdstat_enter(fd, FDSTAT_WRITE);
    00351     if (enable_rsync)
    00352         rc = rsyncable_gzwrite(rpmgz, (void *)buf, (unsigned)count);
    00353     else
    00354         rc = gzwrite(rpmgz->gz, (void *)buf, (unsigned)count);
    00355 DBGIO(fd, (stderr, "==>\tgzdWrite(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
    00356     if (rc < (ssize_t)count) {
    00357         int zerror = 0;
    00358         fd->errcookie = gzerror(rpmgz->gz, &zerror);
    00359         if (zerror == Z_ERRNO) {
    00360             fd->syserrno = errno;
    00361             fd->errcookie = strerror(fd->syserrno);
    00362         }
    00363     }
    00364     if (rc > 0)
    00365         fdstat_exit(fd, FDSTAT_WRITE, rc);
    00366     return rc;
    00367 }
    00368
    00369 /* XXX zlib-1.0.4 has not */
    00370 #define HAVE_GZSEEK     /* XXX autoFu doesn't set this anymore. */
    00371 static inline int gzdSeek(void * cookie, _libio_pos_t pos, int whence)
    00372         /*@globals fileSystem, internalState @*/
    00373         /*@modifies fileSystem, internalState @*/
    00374 {
    00375     int rc;
    00376 #if defined(HAVE_GZSEEK)
    00377 #ifdef USE_COOKIE_SEEK_POINTER
    00378     _IO_off64_t p = *pos;
    00379 #else
    00380     off_t p = pos;
    00381 #endif
    00382     FD_t fd = c2f(cookie);
    00383     rpmGZFILE rpmgz;
    00384
    00385     if (fd == NULL) return -2;
    00386     assert(fd->bytesRemain == -1);      /* XXX FIXME */
    00387
    00388     rpmgz = gzdFileno(fd);
    00389     if (rpmgz == NULL) return -2;       /* XXX can't happen */
    00390
    00391     fdstat_enter(fd, FDSTAT_SEEK);
    00392     rc = gzseek(rpmgz->gz, (long)p, whence);
    00393 DBGIO(fd, (stderr, "==>\tgzdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd)));
    00394     if (rc < 0) {
    00395         int zerror = 0;
    00396         fd->errcookie = gzerror(rpmgz->gz, &zerror);
    00397         if (zerror == Z_ERRNO) {
    00398             fd->syserrno = errno;
    00399             fd->errcookie = strerror(fd->syserrno);
    00400         }
    00401     }
    00402     if (rc > 0)
    00403         fdstat_exit(fd, FDSTAT_SEEK, rc);
    00404 #else
    00405     rc = -2;
    00406 #endif
    00407     return rc;
    00408 }
    00409
    00410 static int gzdClose( /*@only@*/ void * cookie)
    00411         /*@globals fileSystem, internalState @*/
    00412         /*@modifies fileSystem, internalState @*/
    00413 {
    00414     FD_t fd = c2f(cookie);
    00415     rpmGZFILE rpmgz;
    00416     int rc;
    00417
    00418     rpmgz = gzdFileno(fd);
    00419     if (rpmgz == NULL) return -2;       /* XXX can't happen */
    00420
    00421     fdstat_enter(fd, FDSTAT_CLOSE);
    00422     /*@-dependenttrans@*/
    00423     rc = gzclose(rpmgz->gz);
    00424     /*@=dependenttrans@*/
    00425     rpmgz->gz = NULL;
    00426 /*@-dependenttrans@*/
    00427     rpmgz = _free(rpmgz);
    00428 /*@=dependenttrans@*/
    00429
    00430     /* XXX TODO: preserve fd if errors */
    00431
    00432     if (fd) {
    00433 DBGIO(fd, (stderr, "==>\tgzdClose(%p) zerror %d %s\n", cookie, rc, fdbg(fd)));
    00434         if (rc < 0) {
    00435             fd->errcookie = "gzclose error";
    00436             if (rc == Z_ERRNO) {
    00437                 fd->syserrno = errno;
    00438                 fd->errcookie = strerror(fd->syserrno);
    00439             }
    00440         } else if (rc >= 0) {
    00441             fdstat_exit(fd, FDSTAT_CLOSE, rc);
    00442         }
    00443     }
    00444
    00445 DBGIO(fd, (stderr, "==>\tgzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
    00446
    00447     if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "GZDIO", stderr);
    00448     if (rc == 0)
    00449         fd = fdFree(fd, "open (gzdClose)");
    00450     return rc;
    00451 }
    00452
    00453 /*@-type@*/ /* LCL: function typedefs */
    00454 static struct FDIO_s gzdio_s = {
    00455   gzdRead, gzdWrite, gzdSeek, gzdClose, gzdOpen, gzdFdopen, gzdFlush,
    00456 };
    00457 /*@=type@*/
    00458
    00459 FDIO_t gzdio = /*@-compmempass@*/ &gzdio_s /*@=compmempass@*/ ;
    00460
    00461 /*@=moduncon@*/
    00462 #endif  /* WITH_ZLIB */