rpm 5.3.12
|
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