rpm 5.3.12
rpmio/xzdio.c
Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 #include "rpmio_internal.h"
00008 #include <rpmmacro.h>
00009 #include <rpmcb.h>
00010 
00011 #if defined(WITH_XZ)
00012 
00013 /* provide necessary defines for inclusion of <lzma.h>
00014    similar to LZMAUtils's internal <common.h> and as
00015    explicitly stated in the top-level comment of <lzma.h> */
00016 #ifndef UINT32_C
00017 #       define UINT32_C(n) n ## U
00018 #endif
00019 #ifndef UINT32_MAX
00020 #       define UINT32_MAX UINT32_C(4294967295)
00021 #endif
00022 #if SIZEOF_UNSIGNED_LONG == 4
00023 #       ifndef UINT64_C
00024 #               define UINT64_C(n) n ## ULL
00025 #       endif
00026 #else
00027 #       ifndef UINT64_C
00028 #               define UINT64_C(n) n ## UL
00029 #       endif
00030 #endif
00031 #ifndef UINT64_MAX
00032 #       define UINT64_MAX UINT64_C(18446744073709551615)
00033 #endif
00034 
00035 #include "lzma.h"
00036 
00037 #ifndef LZMA_PRESET_DEFAULT
00038 #define LZMA_PRESET_DEFAULT     UINT32_C(6)
00039 #endif
00040 
00041 #include "debug.h"
00042 
00043 /*@access FD_t @*/
00044 
00045 #define XZDONLY(fd)     assert(fdGetIo(fd) == xzdio)
00046 
00047 #define kBufferSize (1 << 15)
00048 
00049 typedef struct xzfile {
00050 /*@only@*/
00051     rpmuint8_t buf[kBufferSize];        
00052     lzma_stream strm;           
00053 /*@dependent@*/
00054     FILE * fp;
00055     int encoding;
00056     int eof;
00057 } XZFILE;
00058 
00059 /*@-globstate@*/
00060 /*@null@*/
00061 static XZFILE *xzopen_internal(const char *path, const char *mode, int fdno, int xz)
00062         /*@globals fileSystem @*/
00063         /*@modifies fileSystem @*/
00064 {
00065     int level = LZMA_PRESET_DEFAULT;
00066     int encoding = 0;
00067     FILE *fp;
00068     XZFILE *xzfile;
00069     lzma_stream tmp;
00070     lzma_ret ret;
00071 
00072     for (; *mode != '\0'; mode++) {
00073         if (*mode == 'w')
00074             encoding = 1;
00075         else if (*mode == 'r')
00076             encoding = 0;
00077         else if (*mode >= '0' && *mode <= '9')
00078             level = (int)(*mode - '0');
00079     }
00080     if (fdno != -1)
00081         fp = fdopen(fdno, encoding ? "w" : "r");
00082     else
00083         fp = fopen(path, encoding ? "w" : "r");
00084     if (!fp)
00085         return NULL;
00086     xzfile = calloc(1, sizeof(*xzfile));
00087     if (!xzfile) {
00088         (void) fclose(fp);
00089         return NULL;
00090     }
00091     xzfile->fp = fp;
00092     xzfile->encoding = encoding;
00093     xzfile->eof = 0;
00094     tmp = (lzma_stream)LZMA_STREAM_INIT;
00095     xzfile->strm = tmp;
00096     if (encoding) {
00097         if (xz) {
00098             ret = lzma_easy_encoder(&xzfile->strm, level, LZMA_CHECK_CRC32);
00099         } else {
00100             lzma_options_lzma options;
00101             (void) lzma_lzma_preset(&options, level);
00102             ret = lzma_alone_encoder(&xzfile->strm, &options);
00103         }
00104     } else {
00105         /* We set the memlimit for decompression to 100MiB which should be
00106          * more than enough to be sufficient for level 9 which requires 65 MiB.
00107          */
00108         ret = lzma_auto_decoder(&xzfile->strm, 100<<20, 0);
00109     }
00110     if (ret != LZMA_OK) {
00111         (void) fclose(fp);
00112         memset(xzfile, 0, sizeof(*xzfile));
00113         free(xzfile);
00114         return NULL;
00115     }
00116     return xzfile;
00117 }
00118 /*@=globstate@*/
00119 
00120 /*@null@*/
00121 static XZFILE *lzopen(const char *path, const char *mode)
00122         /*@globals fileSystem @*/
00123         /*@modifies fileSystem @*/
00124 {
00125     return xzopen_internal(path, mode, -1, 0);
00126 }
00127 
00128 /*@null@*/
00129 static XZFILE *lzdopen(int fdno, const char *mode)
00130         /*@globals fileSystem @*/
00131         /*@modifies fileSystem @*/
00132 {
00133     if (fdno < 0)
00134         return NULL;
00135     return xzopen_internal(0, mode, fdno, 0);
00136 }
00137 
00138 /*@null@*/
00139 static XZFILE *xzopen(const char *path, const char *mode)
00140         /*@globals fileSystem @*/
00141         /*@modifies fileSystem @*/
00142 {
00143     return xzopen_internal(path, mode, -1, 1);
00144 }
00145 
00146 /*@null@*/
00147 static XZFILE *xzdopen(int fdno, const char *mode)
00148         /*@globals fileSystem @*/
00149         /*@modifies fileSystem @*/
00150 {
00151     if (fdno < 0)
00152         return NULL;
00153     return xzopen_internal(0, mode, fdno, 1);
00154 }
00155 
00156 static int xzflush(XZFILE *xzfile)
00157         /*@globals fileSystem @*/
00158         /*@modifies xzfile, fileSystem @*/
00159 {
00160     return fflush(xzfile->fp);
00161 }
00162 
00163 static int xzclose(/*@only@*/ XZFILE *xzfile)
00164         /*@globals fileSystem @*/
00165         /*@modifies *xzfile, fileSystem @*/
00166 {
00167     lzma_ret ret;
00168     size_t n;
00169     int rc;
00170 
00171     if (!xzfile)
00172         return -1;
00173     if (xzfile->encoding) {
00174         for (;;) {
00175             xzfile->strm.avail_out = kBufferSize;
00176             xzfile->strm.next_out = (uint8_t *)xzfile->buf;
00177             ret = lzma_code(&xzfile->strm, LZMA_FINISH);
00178             if (ret != LZMA_OK && ret != LZMA_STREAM_END)
00179                 return -1;
00180             n = kBufferSize - xzfile->strm.avail_out;
00181             if (n && fwrite(xzfile->buf, 1, n, xzfile->fp) != n)
00182                 return -1;
00183             if (ret == LZMA_STREAM_END)
00184                 break;
00185         }
00186     }
00187     lzma_end(&xzfile->strm);
00188     rc = fclose(xzfile->fp);
00189     memset(xzfile, 0, sizeof(*xzfile));
00190     free(xzfile);
00191     return rc;
00192 }
00193 
00194 /*@-mustmod@*/
00195 static ssize_t xzread(XZFILE *xzfile, void *buf, size_t len)
00196         /*@globals fileSystem @*/
00197         /*@modifies xzfile, *buf, fileSystem @*/
00198 {
00199     lzma_ret ret;
00200     int eof = 0;
00201 
00202     if (!xzfile || xzfile->encoding)
00203       return -1;
00204     if (xzfile->eof)
00205       return 0;
00206 /*@-temptrans@*/
00207     xzfile->strm.next_out = buf;
00208 /*@=temptrans@*/
00209     xzfile->strm.avail_out = len;
00210     for (;;) {
00211         if (!xzfile->strm.avail_in) {
00212             xzfile->strm.next_in = (uint8_t *)xzfile->buf;
00213             xzfile->strm.avail_in = fread(xzfile->buf, 1, kBufferSize, xzfile->fp);
00214             if (!xzfile->strm.avail_in)
00215                 eof = 1;
00216         }
00217         ret = lzma_code(&xzfile->strm, LZMA_RUN);
00218         if (ret == LZMA_STREAM_END) {
00219             xzfile->eof = 1;
00220             return len - xzfile->strm.avail_out;
00221         }
00222         if (ret != LZMA_OK)
00223             return -1;
00224         if (!xzfile->strm.avail_out)
00225             return len;
00226         if (eof)
00227             return -1;
00228       }
00229     /*@notreached@*/
00230 }
00231 /*@=mustmod@*/
00232 
00233 static ssize_t xzwrite(XZFILE *xzfile, void *buf, size_t len)
00234         /*@globals fileSystem @*/
00235         /*@modifies xzfile, fileSystem @*/
00236 {
00237     lzma_ret ret;
00238     size_t n;
00239 
00240     if (!xzfile || !xzfile->encoding)
00241         return -1;
00242     if (!len)
00243         return 0;
00244 /*@-temptrans@*/
00245     xzfile->strm.next_in = buf;
00246 /*@=temptrans@*/
00247     xzfile->strm.avail_in = len;
00248     for (;;) {
00249         xzfile->strm.next_out = (uint8_t *)xzfile->buf;
00250         xzfile->strm.avail_out = kBufferSize;
00251         ret = lzma_code(&xzfile->strm, LZMA_RUN);
00252         if (ret != LZMA_OK)
00253             return -1;
00254         n = kBufferSize - xzfile->strm.avail_out;
00255         if (n && fwrite(xzfile->buf, 1, n, xzfile->fp) != n)
00256             return -1;
00257         if (!xzfile->strm.avail_in)
00258             return len;
00259     }
00260     /*@notreached@*/
00261 }
00262 
00263 /* =============================================================== */
00264 
00265 static inline /*@dependent@*/ /*@null@*/ void * xzdFileno(FD_t fd)
00266         /*@*/
00267 {
00268     void * rc = NULL;
00269     int i;
00270 
00271     FDSANE(fd);
00272     for (i = fd->nfps; i >= 0; i--) {
00273 /*@-boundsread@*/
00274             FDSTACK_t * fps = &fd->fps[i];
00275 /*@=boundsread@*/
00276             if (fps->io != xzdio && fps->io != lzdio)
00277                 continue;
00278             rc = fps->fp;
00279         break;
00280     }
00281     
00282     return rc;
00283 }
00284 
00285 /*@-globuse@*/
00286 static /*@null@*/ FD_t lzdOpen(const char * path, const char * fmode)
00287         /*@globals fileSystem @*/
00288         /*@modifies fileSystem @*/
00289 {
00290     FD_t fd;
00291     mode_t mode = (fmode && fmode[0] == 'w' ? O_WRONLY : O_RDONLY);
00292     XZFILE * xzfile = lzopen(path, fmode);
00293 
00294     if (xzfile == NULL)
00295         return NULL;
00296     fd = fdNew("open (lzdOpen)");
00297     fdPop(fd); fdPush(fd, lzdio, xzfile, -1);
00298     fdSetOpen(fd, path, fileno(xzfile->fp), mode);
00299     return fdLink(fd, "lzdOpen");
00300 }
00301 /*@=globuse@*/
00302 
00303 /*@-globuse@*/
00304 static /*@null@*/ FD_t lzdFdopen(void * cookie, const char * fmode)
00305         /*@globals fileSystem, internalState @*/
00306         /*@modifies fileSystem, internalState @*/
00307 {
00308     FD_t fd = c2f(cookie);
00309     int fdno = fdFileno(fd);
00310     XZFILE *xzfile;
00311 
00312 assert(fmode != NULL);
00313     fdSetFdno(fd, -1);          /* XXX skip the fdio close */
00314     if (fdno < 0) return NULL;
00315     xzfile = lzdopen(fdno, fmode);
00316     if (xzfile == NULL) return NULL;
00317     fdPush(fd, lzdio, xzfile, fdno);
00318     return fdLink(fd, "lzdFdopen");
00319 }
00320 /*@=globuse@*/
00321 
00322 /*@-globuse@*/
00323 static /*@null@*/ FD_t xzdOpen(const char * path, const char * fmode)
00324         /*@globals fileSystem @*/
00325         /*@modifies fileSystem @*/
00326 {
00327     FD_t fd;
00328     mode_t mode = (fmode && fmode[0] == 'w' ? O_WRONLY : O_RDONLY);
00329     XZFILE * xzfile = xzopen(path, fmode);
00330 
00331     if (xzfile == NULL)
00332         return NULL;
00333     fd = fdNew("open (xzdOpen)");
00334     fdPop(fd); fdPush(fd, xzdio, xzfile, -1);
00335     fdSetOpen(fd, path, fileno(xzfile->fp), mode);
00336     return fdLink(fd, "xzdOpen");
00337 }
00338 /*@=globuse@*/
00339 
00340 /*@-globuse@*/
00341 static /*@null@*/ FD_t xzdFdopen(void * cookie, const char * fmode)
00342         /*@globals fileSystem, internalState @*/
00343         /*@modifies fileSystem, internalState @*/
00344 {
00345     FD_t fd = c2f(cookie);
00346     int fdno = fdFileno(fd);
00347     XZFILE *xzfile;
00348 
00349 assert(fmode != NULL);
00350     fdSetFdno(fd, -1);          /* XXX skip the fdio close */
00351     if (fdno < 0) return NULL;
00352     xzfile = xzdopen(fdno, fmode);
00353     if (xzfile == NULL) return NULL;
00354     fdPush(fd, xzdio, xzfile, fdno);
00355     return fdLink(fd, "xzdFdopen");
00356 }
00357 /*@=globuse@*/
00358 
00359 /*@-globuse@*/
00360 static int xzdFlush(void * cookie)
00361         /*@globals fileSystem @*/
00362         /*@modifies fileSystem @*/
00363 {
00364     FD_t fd = c2f(cookie);
00365     return xzflush(xzdFileno(fd));
00366 }
00367 /*@=globuse@*/
00368 
00369 /* =============================================================== */
00370 /*@-globuse@*/
00371 /*@-mustmod@*/          /* LCL: *buf is modified */
00372 static ssize_t xzdRead(void * cookie, /*@out@*/ char * buf, size_t count)
00373         /*@globals fileSystem, internalState @*/
00374         /*@modifies *buf, fileSystem, internalState @*/
00375 {
00376     FD_t fd = c2f(cookie);
00377     XZFILE *xzfile;
00378     ssize_t rc = -1;
00379 
00380 assert(fd != NULL);
00381     if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
00382     xzfile = xzdFileno(fd);
00383 assert(xzfile != NULL);
00384     fdstat_enter(fd, FDSTAT_READ);
00385 /*@-compdef@*/
00386     rc = xzread(xzfile, buf, count);
00387 /*@=compdef@*/
00388 DBGIO(fd, (stderr, "==>\txzdRead(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
00389     if (rc == -1) {
00390         fd->errcookie = "Lzma: decoding error";
00391     } else if (rc >= 0) {
00392         fdstat_exit(fd, FDSTAT_READ, rc);
00393         /*@-compdef@*/
00394         if (fd->ndigests > 0 && rc > 0) fdUpdateDigests(fd, (void *)buf, rc);
00395         /*@=compdef@*/
00396     }
00397     return rc;
00398 }
00399 /*@=mustmod@*/
00400 /*@=globuse@*/
00401 
00402 /*@-globuse@*/
00403 static ssize_t xzdWrite(void * cookie, const char * buf, size_t count)
00404         /*@globals fileSystem, internalState @*/
00405         /*@modifies fileSystem, internalState @*/
00406 {
00407     FD_t fd = c2f(cookie);
00408     XZFILE *xzfile;
00409     ssize_t rc = 0;
00410 
00411     if (fd == NULL || fd->bytesRemain == 0) return 0;   /* XXX simulate EOF */
00412 
00413     if (fd->ndigests > 0 && count > 0) fdUpdateDigests(fd, (void *)buf, count);
00414 
00415     xzfile = xzdFileno(fd);
00416 
00417     fdstat_enter(fd, FDSTAT_WRITE);
00418     rc = xzwrite(xzfile, (void *)buf, count);
00419 DBGIO(fd, (stderr, "==>\txzdWrite(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
00420     if (rc < 0) {
00421         fd->errcookie = "Lzma: encoding error";
00422     } else if (rc > 0) {
00423         fdstat_exit(fd, FDSTAT_WRITE, rc);
00424     }
00425     return rc;
00426 }
00427 
00428 static int xzdSeek(void * cookie, /*@unused@*/ _libio_pos_t pos,
00429                         /*@unused@*/ int whence)
00430         /*@*/
00431 {
00432     FD_t fd = c2f(cookie);
00433 
00434     XZDONLY(fd);
00435     return -2;
00436 }
00437 
00438 static int xzdClose( /*@only@*/ void * cookie)
00439         /*@globals fileSystem, internalState @*/
00440         /*@modifies fileSystem, internalState @*/
00441 {
00442     FD_t fd = c2f(cookie);
00443     XZFILE *xzfile;
00444     const char * errcookie;
00445     int rc;
00446 
00447     xzfile = xzdFileno(fd);
00448 
00449     if (xzfile == NULL) return -2;
00450     errcookie = strerror(ferror(xzfile->fp));
00451 
00452     fdstat_enter(fd, FDSTAT_CLOSE);
00453     /*@-dependenttrans@*/
00454     rc = xzclose(xzfile);
00455     /*@=dependenttrans@*/
00456     fdstat_exit(fd, FDSTAT_CLOSE, rc);
00457 
00458     if (fd && rc == -1)
00459         fd->errcookie = errcookie;
00460 
00461 DBGIO(fd, (stderr, "==>\txzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
00462 
00463     if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "XZDIO", stderr);
00464     /*@-branchstate@*/
00465     if (rc == 0)
00466         fd = fdFree(fd, "open (xzdClose)");
00467     /*@=branchstate@*/
00468     return rc;
00469 }
00470 
00471 /*@-type@*/ /* LCL: function typedefs */
00472 static struct FDIO_s lzdio_s = {
00473   xzdRead, xzdWrite, xzdSeek, xzdClose, lzdOpen, lzdFdopen, xzdFlush,
00474 };
00475 /*@=type@*/
00476 
00477 FDIO_t lzdio = /*@-compmempass@*/ &lzdio_s /*@=compmempass@*/ ;
00478 
00479 /*@-type@*/ /* LCL: function typedefs */
00480 static struct FDIO_s xzdio_s = {
00481   xzdRead, xzdWrite, xzdSeek, xzdClose, xzdOpen, xzdFdopen, xzdFlush,
00482 };
00483 /*@=type@*/
00484 
00485 FDIO_t xzdio = /*@-compmempass@*/ &xzdio_s /*@=compmempass@*/ ;
00486 
00487 #endif
00488