10 #include <sys/personality.h>
12 #include <sys/utsname.h>
14 #include <rpm/rpmlog.h>
15 #include <rpm/rpmmacro.h>
16 #include <rpm/rpmfileutil.h>
17 #include <rpm/rpmsw.h>
18 #include <rpm/rpmurl.h>
20 #include "rpmio/rpmio_internal.h"
24 typedef struct _FDSTACK_s {
31 * Cumulative statistics for a descriptor.
34 struct rpmop_s ops[FDSTAT_MAX]; /*!< Cumulative statistics. */
38 * The FD_t File Handle data structure.
43 #define RPMIO_DEBUG_IO 0x40000000
45 #define FDMAGIC 0x04463138
48 int urlType; /* ufdio: */
50 int syserrno; /* last system errno encountered */
51 const char *errcookie; /* gzdio/bzdio/ufdio/xzdio: */
53 char *descr; /* file name (or other description) */
54 FDSTAT_t stats; /* I/O statistics */
56 rpmDigestBundle digests;
59 #define DBG(_f, _m, _x) \
61 if ((_rpmio_debug | ((_f) ? ((FD_t)(_f))->flags : 0)) & (_m)) fprintf _x \
63 #define DBGIO(_f, _x) DBG((_f), RPMIO_DEBUG_IO, _x)
65 static FDIO_t fdGetIo(FD_t fd)
67 return (fd != NULL) ? fd->fps[fd->nfps].io : NULL;
70 static void fdSetIo(FD_t fd, FDIO_t io)
73 fd->fps[fd->nfps].io = io;
76 static void * fdGetFp(FD_t fd)
78 return (fd != NULL) ? fd->fps[fd->nfps].fp : NULL;
81 static void fdSetFp(FD_t fd, void * fp)
84 fd->fps[fd->nfps].fp = fp;
87 static void fdSetFdno(FD_t fd, int fdno)
90 fd->fps[fd->nfps].fdno = fdno;
93 static void fdPush(FD_t fd, FDIO_t io, void * fp, int fdno)
95 if (fd == NULL || fd->nfps >= (sizeof(fd->fps)/sizeof(fd->fps[0]) - 1))
103 static void fdPop(FD_t fd)
105 if (fd == NULL || fd->nfps < 0) return;
112 void fdSetBundle(FD_t fd, rpmDigestBundle bundle)
115 fd->digests = bundle;
118 rpmDigestBundle fdGetBundle(FD_t fd)
120 return (fd != NULL) ? fd->digests : NULL;
123 static void * iotFileno(FD_t fd, FDIO_t iot)
130 for (int i = fd->nfps; i >= 0; i--) {
131 FDSTACK_t * fps = &fd->fps[i];
142 * \name RPMIO Vectors.
144 typedef ssize_t (*fdio_read_function_t) (FD_t fd, void *buf, size_t nbytes);
145 typedef ssize_t (*fdio_write_function_t) (FD_t fd, const void *buf, size_t nbytes);
146 typedef int (*fdio_seek_function_t) (FD_t fd, off_t pos, int whence);
147 typedef int (*fdio_close_function_t) (FD_t fd);
148 typedef FD_t (*fdio_ref_function_t) (FD_t fd);
149 typedef FD_t (*fdio_deref_function_t) (FD_t fd);
150 typedef FD_t (*fdio_new_function_t) (const char *descr);
151 typedef int (*fdio_fileno_function_t) (FD_t fd);
152 typedef FD_t (*fdio_open_function_t) (const char * path, int flags, mode_t mode);
153 typedef FD_t (*fdio_fopen_function_t) (const char * path, const char * fmode);
154 typedef void * (*fdio_ffileno_function_t) (FD_t fd);
155 typedef int (*fdio_fflush_function_t) (FD_t fd);
156 typedef long (*fdio_ftell_function_t) (FD_t);
159 fdio_read_function_t read;
160 fdio_write_function_t write;
161 fdio_seek_function_t seek;
162 fdio_close_function_t close;
164 fdio_ref_function_t _fdref;
165 fdio_deref_function_t _fdderef;
166 fdio_new_function_t _fdnew;
167 fdio_fileno_function_t _fileno;
169 fdio_open_function_t _open;
170 fdio_fopen_function_t _fopen;
171 fdio_ffileno_function_t _ffileno;
172 fdio_fflush_function_t _fflush;
173 fdio_ftell_function_t _ftell;
177 static const FDIO_t fdio;
178 static const FDIO_t ufdio;
179 static const FDIO_t gzdio;
180 static const FDIO_t bzdio;
181 static const FDIO_t xzdio;
182 static const FDIO_t lzdio;
185 * Update digest(s) attached to fd.
187 static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen);
188 static FD_t fdNew(const char *descr);
191 int _rpmio_debug = 0;
193 /* =============================================================== */
195 static const char * fdbg(FD_t fd)
197 static char buf[BUFSIZ];
206 for (i = fd->nfps; i >= 0; i--) {
207 FDSTACK_t * fps = &fd->fps[i];
212 if (fps->io == fdio) {
213 sprintf(be, "FD %d fp %p", fps->fdno, fps->fp);
214 } else if (fps->io == ufdio) {
215 sprintf(be, "UFD %d fp %p", fps->fdno, fps->fp);
216 } else if (fps->io == gzdio) {
217 sprintf(be, "GZD %p fdno %d", fps->fp, fps->fdno);
219 } else if (fps->io == bzdio) {
220 sprintf(be, "BZD %p fdno %d", fps->fp, fps->fdno);
223 } else if (fps->io == xzdio) {
224 sprintf(be, "XZD %p fdno %d", fps->fp, fps->fdno);
225 } else if (fps->io == lzdio) {
226 sprintf(be, "LZD %p fdno %d", fps->fp, fps->fdno);
229 sprintf(be, "??? io %p fp %p fdno %d ???",
230 fps->io, fps->fp, fps->fdno);
238 static void fdstat_enter(FD_t fd, fdOpX opx)
240 if (fd->stats != NULL)
241 (void) rpmswEnter(fdOp(fd, opx), (ssize_t) 0);
244 static void fdstat_exit(FD_t fd, fdOpX opx, ssize_t rc)
247 fd->syserrno = errno;
248 if (fd->stats != NULL)
249 (void) rpmswExit(fdOp(fd, opx), rc);
252 static void fdstat_print(FD_t fd, const char * msg, FILE * fp)
254 static const int usec_scale = (1000*1000);
257 if (fd == NULL || fd->stats == NULL) return;
258 for (opx = 0; opx < 4; opx++) {
259 rpmop op = &fd->stats->ops[opx];
260 if (op->count <= 0) continue;
263 if (msg) fprintf(fp, "%s:", msg);
264 fprintf(fp, "%8d reads, %8ld total bytes in %d.%06d secs\n",
265 op->count, (long)op->bytes,
266 (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
269 if (msg) fprintf(fp, "%s:", msg);
270 fprintf(fp, "%8d writes, %8ld total bytes in %d.%06d secs\n",
271 op->count, (long)op->bytes,
272 (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
282 off_t fdSize(FD_t fd)
287 if (fd != NULL && fstat(Fileno(fd), &sb) == 0)
297 if ((nfdno = dup(fdno)) < 0)
300 fdSetFdno(fd, nfdno);
301 DBGIO(fd, (stderr, "==> fdDup(%d) fd %p %s\n", fdno, (fd ? fd : NULL), fdbg(fd)));
305 /* Regular fd doesn't have fflush() equivalent but its not an error either */
306 static int fdFlush(FD_t fd)
311 static int fdFileno(FD_t fd)
313 return (fd != NULL) ? fd->fps[0].fdno : -2;
316 const char * Fdescr(FD_t fd)
321 /* Lazy lookup if description is not set (eg dupped fd) */
322 if (fd->descr == NULL) {
323 int fdno = fd->fps[fd->nfps].fdno;
324 #if defined(__linux__)
325 /* Grab the path from /proc if we can */
326 char *procpath = NULL;
330 rasprintf(&procpath, "/proc/self/fd/%d", fdno);
331 llen = readlink(procpath, buf, sizeof(buf)-1);
336 /* Real paths in /proc are always absolute */
338 fd->descr = xstrdup(buf);
340 fd->descr = rstrscat(NULL, "[", buf, "]", NULL);
343 /* Still no description, base it on fdno which is always there */
344 if (fd->descr == NULL)
345 rasprintf(&(fd->descr), "[fd %d]", fdno);
357 FD_t fdFree( FD_t fd)
362 fd->stats = _free(fd->stats);
364 fd->digests = rpmDigestBundleFree(fd->digests);
372 FD_t fdNew(const char *descr)
374 FD_t fd = xcalloc(1, sizeof(*fd));
375 if (fd == NULL) /* XXX xmalloc never returns NULL */
380 fd->urlType = URL_IS_UNKNOWN;
383 memset(fd->fps, 0, sizeof(fd->fps));
385 fd->fps[0].io = fdio;
386 fd->fps[0].fp = NULL;
387 fd->fps[0].fdno = -1;
390 fd->errcookie = NULL;
391 fd->stats = xcalloc(1, sizeof(*fd->stats));
393 fd->descr = descr ? xstrdup(descr) : NULL;
398 static ssize_t fdRead(FD_t fd, void * buf, size_t count)
400 return read(fdFileno(fd), buf, count);
403 static ssize_t fdWrite(FD_t fd, const void * buf, size_t count)
408 return write(fdFileno(fd), buf, count);
411 static int fdSeek(FD_t fd, off_t pos, int whence)
413 return lseek(fdFileno(fd), pos, whence);
416 static int fdClose(FD_t fd)
421 if (fd == NULL) return -2;
426 rc = ((fdno >= 0) ? close(fdno) : -2);
432 static FD_t fdOpen(const char *path, int flags, mode_t mode)
437 fdno = open(path, flags, mode);
438 if (fdno < 0) return NULL;
439 if (fcntl(fdno, F_SETFD, FD_CLOEXEC)) {
449 static long fdTell(FD_t fd)
451 return lseek(Fileno(fd), 0, SEEK_CUR);
454 static const struct FDIO_s fdio_s = {
455 fdRead, fdWrite, fdSeek, fdClose, fdLink, fdFree, fdNew, fdFileno,
456 fdOpen, NULL, fdGetFp, fdFlush, fdTell
458 static const FDIO_t fdio = &fdio_s ;
460 off_t ufdCopy(FD_t sfd, FD_t tfd)
463 ssize_t rdbytes, wrbytes;
467 rdbytes = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd);
470 wrbytes = Fwrite(buf, sizeof(buf[0]), rdbytes, tfd);
471 if (wrbytes != rdbytes) {
487 * Deal with remote url's by fetching them with a helper application
488 * and treat as local file afterwards.
490 * - better error checking + reporting
491 * - curl & friends don't know about hkp://, transform to http?
494 static FD_t urlOpen(const char * url, int flags, mode_t mode)
498 int rc = 1; /* assume failure */
500 fd = rpmMkTempFile(NULL, &dest);
506 rc = urlGetFile(url, dest);
508 fd = fdOpen(dest, flags, mode);
518 static FD_t ufdOpen(const char * url, int flags, mode_t mode)
522 urltype urlType = urlPath(url, &path);
525 fprintf(stderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mode);
532 fd = urlOpen(url, flags, mode);
533 /* we're dealing with local file when urlOpen() returns */
534 urlType = URL_IS_UNKNOWN;
537 if ((flags & O_ACCMODE) == O_RDWR) {
540 fd = fdDup((flags & O_ACCMODE) == O_WRONLY ?
541 STDOUT_FILENO : STDIN_FILENO);
547 fd = fdOpen(path, flags, mode);
551 if (fd == NULL) return NULL;
554 fd->urlType = urlType;
556 if (Fileno(fd) < 0) {
563 static const struct FDIO_s ufdio_s = {
564 fdRead, fdWrite, fdSeek, fdClose, fdLink, fdFree, fdNew, fdFileno,
565 ufdOpen, NULL, fdGetFp, fdFlush, fdTell
567 static const FDIO_t ufdio = &ufdio_s ;
569 /* =============================================================== */
570 /* Support for GZIP library. */
573 static void * gzdFileno(FD_t fd)
575 return iotFileno(fd, gzdio);
579 FD_t gzdOpen(const char * path, const char * fmode)
583 if ((gzfile = gzopen(path, fmode)) == NULL)
586 fdPop(fd); fdPush(fd, gzdio, gzfile, -1);
591 static FD_t gzdFdopen(FD_t fd, const char *fmode)
596 if (fd == NULL || fmode == NULL) return NULL;
598 fdSetFdno(fd, -1); /* XXX skip the fdio close */
599 if (fdno < 0) return NULL;
600 gzfile = gzdopen(fdno, fmode);
601 if (gzfile == NULL) return NULL;
603 fdPush(fd, gzdio, gzfile, fdno); /* Push gzdio onto stack */
608 static int gzdFlush(FD_t fd)
611 gzfile = gzdFileno(fd);
612 if (gzfile == NULL) return -2;
613 return gzflush(gzfile, Z_SYNC_FLUSH); /* XXX W2DO? */
616 static ssize_t gzdRead(FD_t fd, void * buf, size_t count)
621 gzfile = gzdFileno(fd);
622 if (gzfile == NULL) return -2; /* XXX can't happen */
624 rc = gzread(gzfile, buf, count);
627 fd->errcookie = gzerror(gzfile, &zerror);
628 if (zerror == Z_ERRNO) {
629 fd->syserrno = errno;
630 fd->errcookie = strerror(fd->syserrno);
636 static ssize_t gzdWrite(FD_t fd, const void * buf, size_t count)
641 gzfile = gzdFileno(fd);
642 if (gzfile == NULL) return -2; /* XXX can't happen */
644 rc = gzwrite(gzfile, (void *)buf, count);
647 fd->errcookie = gzerror(gzfile, &zerror);
648 if (zerror == Z_ERRNO) {
649 fd->syserrno = errno;
650 fd->errcookie = strerror(fd->syserrno);
656 /* XXX zlib-1.0.4 has not */
657 static int gzdSeek(FD_t fd, off_t pos, int whence)
664 if (fd == NULL) return -2;
666 gzfile = gzdFileno(fd);
667 if (gzfile == NULL) return -2; /* XXX can't happen */
669 rc = gzseek(gzfile, p, whence);
672 fd->errcookie = gzerror(gzfile, &zerror);
673 if (zerror == Z_ERRNO) {
674 fd->syserrno = errno;
675 fd->errcookie = strerror(fd->syserrno);
684 static int gzdClose(FD_t fd)
689 gzfile = gzdFileno(fd);
690 if (gzfile == NULL) return -2; /* XXX can't happen */
692 rc = gzclose(gzfile);
694 /* XXX TODO: preserve fd if errors */
698 fd->errcookie = "gzclose error";
700 fd->syserrno = errno;
701 fd->errcookie = strerror(fd->syserrno);
706 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "GZDIO", stderr);
712 static long gzdTell(FD_t fd)
715 gzFile gzfile = gzdFileno(fd);
717 if (gzfile != NULL) {
719 pos = gztell(gzfile);
722 fd->errcookie = gzerror(gzfile, &zerror);
723 if (zerror == Z_ERRNO) {
724 fd->syserrno = errno;
725 fd->errcookie = strerror(fd->syserrno);
734 static const struct FDIO_s gzdio_s = {
735 gzdRead, gzdWrite, gzdSeek, gzdClose, fdLink, fdFree, fdNew, fdFileno,
736 NULL, gzdOpen, gzdFileno, gzdFlush, gzdTell
738 static const FDIO_t gzdio = &gzdio_s ;
740 /* =============================================================== */
741 /* Support for BZIP2 library. */
746 static void * bzdFileno(FD_t fd)
748 return iotFileno(fd, bzdio);
751 static FD_t bzdOpen(const char * path, const char * mode)
755 if ((bzfile = BZ2_bzopen(path, mode)) == NULL)
758 fdPop(fd); fdPush(fd, bzdio, bzfile, -1);
762 static FD_t bzdFdopen(FD_t fd, const char * fmode)
767 if (fd == NULL || fmode == NULL) return NULL;
769 fdSetFdno(fd, -1); /* XXX skip the fdio close */
770 if (fdno < 0) return NULL;
771 bzfile = BZ2_bzdopen(fdno, fmode);
772 if (bzfile == NULL) return NULL;
774 fdPush(fd, bzdio, bzfile, fdno); /* Push bzdio onto stack */
779 static int bzdFlush(FD_t fd)
781 return BZ2_bzflush(bzdFileno(fd));
784 static ssize_t bzdRead(FD_t fd, void * buf, size_t count)
789 bzfile = bzdFileno(fd);
791 rc = BZ2_bzread(bzfile, buf, count);
795 fd->errcookie = BZ2_bzerror(bzfile, &zerror);
800 static ssize_t bzdWrite(FD_t fd, const void * buf, size_t count)
805 bzfile = bzdFileno(fd);
806 rc = BZ2_bzwrite(bzfile, (void *)buf, count);
809 fd->errcookie = BZ2_bzerror(bzfile, &zerror);
814 static int bzdClose(FD_t fd)
819 bzfile = bzdFileno(fd);
821 if (bzfile == NULL) return -2;
824 rc = 0; /* XXX FIXME */
826 /* XXX TODO: preserve fd if errors */
831 fd->errcookie = BZ2_bzerror(bzfile, &zerror);
835 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "BZDIO", stderr);
841 static const struct FDIO_s bzdio_s = {
842 bzdRead, bzdWrite, NULL, bzdClose, fdLink, fdFree, fdNew, fdFileno,
843 NULL, bzdOpen, bzdFileno, bzdFlush, NULL
845 static const FDIO_t bzdio = &bzdio_s ;
847 #endif /* HAVE_BZLIB_H */
849 static const char * getFdErrstr (FD_t fd)
851 const char *errstr = NULL;
853 if (fdGetIo(fd) == gzdio) {
854 errstr = fd->errcookie;
857 if (fdGetIo(fd) == bzdio) {
858 errstr = fd->errcookie;
860 #endif /* HAVE_BZLIB_H */
862 if (fdGetIo(fd) == xzdio || fdGetIo(fd) == lzdio) {
863 errstr = fd->errcookie;
865 #endif /* HAVE_LZMA_H */
867 errstr = (fd->syserrno ? strerror(fd->syserrno) : "");
873 /* =============================================================== */
874 /* Support for LZMA library. */
878 #include <sys/types.h>
879 #include <inttypes.h>
882 #define kBufferSize (1 << 15)
884 typedef struct lzfile {
886 uint8_t buf[kBufferSize];
897 static LZFILE *lzopen_internal(const char *path, const char *mode, int fd, int xz)
899 int level = LZMA_PRESET_DEFAULT;
904 lzma_stream init_strm = LZMA_STREAM_INIT;
905 uint64_t mem_limit = rpmExpandNumeric("%{_xz_memlimit}");
908 for (; *mode; mode++) {
911 else if (*mode == 'r')
913 else if (*mode >= '0' && *mode <= '9')
915 else if (*mode == 'T') {
916 if (isdigit(*(mode+1))) {
917 threads = atoi(++mode);
918 /* skip past rest of digits in string that atoi()
919 * should've processed
921 while(isdigit(*++mode));
928 fp = fdopen(fd, encoding ? "w" : "r");
930 fp = fopen(path, encoding ? "w" : "r");
933 lzfile = calloc(1, sizeof(*lzfile));
940 lzfile->encoding = encoding;
942 lzfile->strm = init_strm;
946 ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
949 threads = sysconf(_SC_NPROCESSORS_ONLN);
950 lzma_mt mt_options = {
957 .check = LZMA_CHECK_SHA256 };
960 /* In 32 bit environment, required memory easily exceeds memory address
961 * space limit if compressing using multiple threads.
962 * By setting a memory limit, liblzma will automatically adjust number
963 * of threads to avoid exceeding memory.
967 uint32_t memlimit = (SIZE_MAX>>1) + (SIZE_MAX>>3);
968 uint64_t memory_usage;
969 /* While a 32 bit linux kernel will have an address limit of 3GiB
970 * for processes (which is why set the memory limit to 2.5GiB as a safety
971 * margin), 64 bit kernels will have a limit of 4GiB for 32 bit binaries.
972 * Therefore the memory limit should be higher if running on a 64 bit
973 * kernel, so we increase it to 3,5GiB.
976 if (strstr(u.machine, "64") || strstr(u.machine, "s390x")
977 #if defined(__linux__)
978 || ((personality(0xffffffff) & PER_MASK) == PER_LINUX32)
981 memlimit += (SIZE_MAX>>2);
983 /* keep reducing the number of threads untill memory usage gets below limit */
984 while ((memory_usage = lzma_stream_encoder_mt_memusage(&mt_options)) > memlimit) {
985 /* number of threads shouldn't be able to hit zero with compression
986 * settings aailable to set through rpm... */
987 assert(--mt_options.threads != 0);
989 lzma_memlimit_set(&lzfile->strm, memlimit);
991 if (threads != (int)mt_options.threads)
992 rpmlog(RPMLOG_NOTICE,
993 "XZ: Adjusted the number of threads from %d to %d to not exceed the memory usage limit of %lu bytes",
994 threads, mt_options.threads, memlimit);
998 ret = lzma_stream_encoder_mt(&lzfile->strm, &mt_options);
1001 lzma_options_lzma options;
1002 lzma_lzma_preset(&options, level);
1003 ret = lzma_alone_encoder(&lzfile->strm, &options);
1005 } else { /* lzma_easy_decoder_memusage(level) is not ready yet, use hardcoded limit for now */
1006 ret = lzma_auto_decoder(&lzfile->strm, mem_limit ? mem_limit : 100<<20, 0);
1008 if (ret != LZMA_OK) {
1010 case LZMA_MEM_ERROR:
1011 rpmlog(RPMLOG_ERR, "liblzma: Memory allocation failed");
1014 case LZMA_DATA_ERROR:
1015 rpmlog(RPMLOG_ERR, "liblzma: File size limits exceeded");
1019 rpmlog(RPMLOG_ERR, "liblzma: <Unknown error (%d), possibly a bug", ret);
1029 static LZFILE *xzopen(const char *path, const char *mode)
1031 return lzopen_internal(path, mode, -1, 1);
1034 static LZFILE *xzdopen(int fd, const char *mode)
1038 return lzopen_internal(0, mode, fd, 1);
1041 static LZFILE *lzopen(const char *path, const char *mode)
1043 return lzopen_internal(path, mode, -1, 0);
1046 static LZFILE *lzdopen(int fd, const char *mode)
1050 return lzopen_internal(0, mode, fd, 0);
1053 static int lzflush(LZFILE *lzfile)
1055 return fflush(lzfile->file);
1058 static int lzclose(LZFILE *lzfile)
1066 if (lzfile->encoding) {
1068 lzfile->strm.avail_out = kBufferSize;
1069 lzfile->strm.next_out = lzfile->buf;
1070 ret = lzma_code(&lzfile->strm, LZMA_FINISH);
1071 if (ret != LZMA_OK && ret != LZMA_STREAM_END)
1073 n = kBufferSize - lzfile->strm.avail_out;
1074 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
1076 if (ret == LZMA_STREAM_END)
1080 lzma_end(&lzfile->strm);
1081 rc = fclose(lzfile->file);
1086 static ssize_t lzread(LZFILE *lzfile, void *buf, size_t len)
1091 if (!lzfile || lzfile->encoding)
1095 lzfile->strm.next_out = buf;
1096 lzfile->strm.avail_out = len;
1098 if (!lzfile->strm.avail_in) {
1099 lzfile->strm.next_in = lzfile->buf;
1100 lzfile->strm.avail_in = fread(lzfile->buf, 1, kBufferSize, lzfile->file);
1101 if (!lzfile->strm.avail_in)
1104 ret = lzma_code(&lzfile->strm, LZMA_RUN);
1105 if (ret == LZMA_STREAM_END) {
1107 return len - lzfile->strm.avail_out;
1111 if (!lzfile->strm.avail_out)
1118 static ssize_t lzwrite(LZFILE *lzfile, void *buf, size_t len)
1122 if (!lzfile || !lzfile->encoding)
1126 lzfile->strm.next_in = buf;
1127 lzfile->strm.avail_in = len;
1129 lzfile->strm.next_out = lzfile->buf;
1130 lzfile->strm.avail_out = kBufferSize;
1131 ret = lzma_code(&lzfile->strm, LZMA_RUN);
1134 n = kBufferSize - lzfile->strm.avail_out;
1135 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
1137 if (!lzfile->strm.avail_in)
1142 static void * lzdFileno(FD_t fd)
1149 for (int i = fd->nfps; i >= 0; i--) {
1150 FDSTACK_t * fps = &fd->fps[i];
1151 if (fps->io != xzdio && fps->io != lzdio)
1159 static FD_t xzdOpen(const char * path, const char * mode)
1163 if ((lzfile = xzopen(path, mode)) == NULL)
1166 fdPop(fd); fdPush(fd, xzdio, lzfile, -1);
1170 static FD_t xzdFdopen(FD_t fd, const char * fmode)
1175 if (fd == NULL || fmode == NULL) return NULL;
1176 fdno = fdFileno(fd);
1177 fdSetFdno(fd, -1); /* XXX skip the fdio close */
1178 if (fdno < 0) return NULL;
1179 lzfile = xzdopen(fdno, fmode);
1180 if (lzfile == NULL) return NULL;
1181 fdPush(fd, xzdio, lzfile, fdno);
1185 static FD_t lzdOpen(const char * path, const char * mode)
1189 if ((lzfile = lzopen(path, mode)) == NULL)
1192 fdPop(fd); fdPush(fd, xzdio, lzfile, -1);
1196 static FD_t lzdFdopen(FD_t fd, const char * fmode)
1201 if (fd == NULL || fmode == NULL) return NULL;
1202 fdno = fdFileno(fd);
1203 fdSetFdno(fd, -1); /* XXX skip the fdio close */
1204 if (fdno < 0) return NULL;
1205 lzfile = lzdopen(fdno, fmode);
1206 if (lzfile == NULL) return NULL;
1207 fdPush(fd, xzdio, lzfile, fdno);
1211 static int lzdFlush(FD_t fd)
1213 return lzflush(lzdFileno(fd));
1216 static ssize_t lzdRead(FD_t fd, void * buf, size_t count)
1221 lzfile = lzdFileno(fd);
1223 rc = lzread(lzfile, buf, count);
1225 fd->errcookie = "Lzma: decoding error";
1230 static ssize_t lzdWrite(FD_t fd, const void * buf, size_t count)
1235 lzfile = lzdFileno(fd);
1237 rc = lzwrite(lzfile, (void *)buf, count);
1239 fd->errcookie = "Lzma: encoding error";
1244 static int lzdClose(FD_t fd)
1249 lzfile = lzdFileno(fd);
1251 if (lzfile == NULL) return -2;
1252 rc = lzclose(lzfile);
1254 /* XXX TODO: preserve fd if errors */
1258 fd->errcookie = "lzclose error";
1259 fd->syserrno = errno;
1260 fd->errcookie = strerror(fd->syserrno);
1264 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "XZDIO", stderr);
1270 static struct FDIO_s xzdio_s = {
1271 lzdRead, lzdWrite, NULL, lzdClose, NULL, NULL, NULL, fdFileno,
1272 NULL, xzdOpen, lzdFileno, lzdFlush, NULL
1274 static const FDIO_t xzdio = &xzdio_s;
1276 static struct FDIO_s lzdio_s = {
1277 lzdRead, lzdWrite, NULL, lzdClose, NULL, NULL, NULL, fdFileno,
1278 NULL, lzdOpen, lzdFileno, lzdFlush, NULL
1280 static const FDIO_t lzdio = &lzdio_s;
1282 #endif /* HAVE_LZMA_H */
1284 /* =============================================================== */
1286 const char *Fstrerror(FD_t fd)
1289 return (errno ? strerror(errno) : "");
1290 return getFdErrstr(fd);
1293 #define FDIOVEC(_fd, _vec) \
1294 ((fdGetIo(_fd) && fdGetIo(_fd)->_vec) ? fdGetIo(_fd)->_vec : NULL)
1296 ssize_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
1301 fdio_read_function_t _read = FDIOVEC(fd, read);
1303 fdstat_enter(fd, FDSTAT_READ);
1305 rc = (_read ? (*_read) (fd, buf, size * nmemb) : -2);
1306 } while (rc == -1 && errno == EINTR);
1307 fdstat_exit(fd, FDSTAT_READ, rc);
1309 if (fd->digests && rc > 0)
1310 fdUpdateDigests(fd, buf, rc);
1313 DBGIO(fd, (stderr, "==>\tFread(%p,%p,%ld) rc %ld %s\n",
1314 fd, buf, (long)size * nmemb, (long)rc, fdbg(fd)));
1319 ssize_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
1324 fdio_write_function_t _write = FDIOVEC(fd, write);
1326 fdstat_enter(fd, FDSTAT_WRITE);
1328 rc = (_write ? _write(fd, buf, size * nmemb) : -2);
1329 } while (rc == -1 && errno == EINTR);
1330 fdstat_exit(fd, FDSTAT_WRITE, rc);
1332 if (fd->digests && rc > 0)
1333 fdUpdateDigests(fd, buf, rc);
1336 DBGIO(fd, (stderr, "==>\tFwrite(%p,%p,%ld) rc %ld %s\n",
1337 fd, buf, (long)size * nmemb, (long)rc, fdbg(fd)));
1342 int Fseek(FD_t fd, off_t offset, int whence)
1347 fdio_seek_function_t _seek = FDIOVEC(fd, seek);
1349 fdstat_enter(fd, FDSTAT_SEEK);
1350 rc = (_seek ? _seek(fd, offset, whence) : -2);
1351 fdstat_exit(fd, FDSTAT_SEEK, rc);
1354 DBGIO(fd, (stderr, "==>\tFseek(%p,%ld,%d) rc %lx %s\n",
1355 fd, (long)offset, whence, (unsigned long)rc, fdbg(fd)));
1368 fdstat_enter(fd, FDSTAT_CLOSE);
1369 while (fd->nfps >= 0) {
1370 fdio_close_function_t _close = FDIOVEC(fd, close);
1371 rc = _close ? _close(fd) : -2;
1379 fdstat_exit(fd, FDSTAT_CLOSE, rc);
1380 DBGIO(fd, (stderr, "==>\tFclose(%p) rc %lx %s\n",
1381 (fd ? fd : NULL), (unsigned long)rc, fdbg(fd)));
1388 * Convert stdio fmode to open(2) mode, filtering out zlib/bzlib flags.
1389 * returns stdio[0] = NUL on error.
1391 * - gzopen: [0-9] is compression level
1392 * - gzopen: 'f' is filtered (Z_FILTERED)
1393 * - gzopen: 'h' is Huffman encoding (Z_HUFFMAN_ONLY)
1394 * - bzopen: [1-9] is block size (modulo 100K)
1395 * - bzopen: 's' is smallmode
1396 * - HACK: '.' terminates, rest is type of I/O
1398 static void cvtfmode (const char *m,
1399 char *stdio, size_t nstdio,
1400 char *other, size_t nother,
1401 const char **end, int * f)
1408 flags |= O_WRONLY | O_CREAT | O_APPEND;
1409 if (--nstdio > 0) *stdio++ = *m;
1412 flags |= O_WRONLY | O_CREAT | O_TRUNC;
1413 if (--nstdio > 0) *stdio++ = *m;
1417 if (--nstdio > 0) *stdio++ = *m;
1426 while ((c = *m++) != '\0') {
1431 flags &= ~(O_RDONLY|O_WRONLY);
1433 if (--nstdio > 0) *stdio++ = c;
1437 if (--nstdio > 0) *stdio++ = c;
1442 if (--nstdio > 0) *stdio++ = c;
1446 if (--nother > 0) *other++ = c;
1453 *stdio = *other = '\0';
1455 *end = (*m != '\0' ? m : NULL);
1460 FD_t Fdopen(FD_t ofd, const char *fmode)
1462 char stdio[20], other[20], zstdio[40];
1463 const char *end = NULL;
1468 fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
1470 if (fd == NULL || fmode == NULL)
1473 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL);
1474 if (stdio[0] == '\0')
1477 strncat(zstdio, stdio, sizeof(zstdio) - strlen(zstdio) - 1);
1478 strncat(zstdio, other, sizeof(zstdio) - strlen(zstdio) - 1);
1480 if (end == NULL && other[0] == '\0')
1484 if (rstreq(end, "fdio")) {
1486 } else if (rstreq(end, "gzdio") || rstreq(end, "gzip")) {
1488 fd = gzdFdopen(fd, zstdio);
1490 } else if (rstreq(end, "bzdio") || rstreq(end, "bzip2")) {
1492 fd = bzdFdopen(fd, zstdio);
1495 } else if (rstreq(end, "xzdio") || rstreq(end, "xz")) {
1497 fd = xzdFdopen(fd, zstdio);
1498 } else if (rstreq(end, "lzdio") || rstreq(end, "lzma")) {
1500 fd = lzdFdopen(fd, zstdio);
1502 } else if (rstreq(end, "ufdio")) {
1505 } else if (other[0] != '\0') {
1506 for (end = other; *end && strchr("0123456789fh", *end); end++)
1510 fd = gzdFdopen(fd, zstdio);
1516 DBGIO(fd, (stderr, "==> Fdopen(%p,\"%s\") returns fd %p %s\n", ofd, fmode, (fd ? fd : NULL), fdbg(fd)));
1520 FD_t Fopen(const char *path, const char *fmode)
1522 char stdio[20], other[20];
1523 const char *end = NULL;
1524 mode_t perms = 0666;
1528 if (path == NULL || fmode == NULL)
1532 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, &flags);
1533 if (stdio[0] == '\0')
1536 if (end == NULL || rstreq(end, "fdio")) {
1538 fprintf(stderr, "*** Fopen fdio path %s fmode %s\n", path, fmode);
1539 fd = fdOpen(path, flags, perms);
1540 if (fdFileno(fd) < 0) {
1541 if (fd) (void) fdClose(fd);
1545 /* XXX gzdio and bzdio here too */
1547 switch (urlIsURL(path)) {
1554 case URL_IS_UNKNOWN:
1556 fprintf(stderr, "*** Fopen ufdio path %s fmode %s\n", path, fmode);
1557 fd = ufdOpen(path, flags, perms);
1558 if (fd == NULL || !(fdFileno(fd) >= 0))
1563 fprintf(stderr, "*** Fopen WTFO path %s fmode %s\n", path, fmode);
1571 fd = Fdopen(fd, fmode);
1573 DBGIO(fd, (stderr, "==>\tFopen(\"%s\",%x,0%o) %s\n",
1574 path, (unsigned)flags, (unsigned)perms, fdbg(fd)));
1583 fdio_fflush_function_t _fflush = FDIOVEC(fd, _fflush);
1585 rc = (_fflush ? _fflush(fd) : -2);
1590 off_t Ftell(FD_t fd)
1594 fdio_ftell_function_t _ftell = FDIOVEC(fd, _ftell);
1596 pos = (_ftell ? _ftell(fd) : -2);
1605 if (fd == NULL) return -1;
1606 for (i = fd->nfps; rc == 0 && i >= 0; i--) {
1607 FDSTACK_t * fps = &fd->fps[i];
1610 if (fps->io == gzdio) {
1611 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
1612 i--; /* XXX fdio under gzdio always has fdno == -1 */
1614 } else if (fps->io == bzdio) {
1615 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
1616 i--; /* XXX fdio under bzdio always has fdno == -1 */
1619 } else if (fps->io == xzdio || fps->io == lzdio) {
1620 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
1621 i--; /* XXX fdio under xzdio/lzdio always has fdno == -1 */
1624 /* XXX need to check ufdio/gzdio/bzdio/fdio errors correctly. */
1625 ec = (fdFileno(fd) < 0 ? -1 : 0);
1631 DBGIO(fd, (stderr, "==> Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd)));
1639 if (fd == NULL) return -1;
1640 for (i = fd->nfps ; rc == -1 && i >= 0; i--) {
1641 rc = fd->fps[i].fdno;
1644 DBGIO(fd, (stderr, "==> Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, fdbg(fd)));
1648 /* XXX this is naive */
1649 int Fcntl(FD_t fd, int op, void *lip)
1651 return fcntl(Fileno(fd), op, lip);
1654 rpmop fdOp(FD_t fd, fdOpX opx)
1658 if (fd != NULL && fd->stats != NULL && opx >= 0 && opx < FDSTAT_MAX)
1659 op = fd->stats->ops + opx;
1663 int rpmioSlurp(const char * fn, uint8_t ** bp, ssize_t * blenp)
1665 static const ssize_t blenmax = (32 * BUFSIZ);
1672 fd = Fopen(fn, "r.ufdio");
1673 if (fd == NULL || Ferror(fd)) {
1679 blen = (size >= 0 ? size : blenmax);
1682 b = xmalloc(blen+1);
1684 nb = Fread(b, sizeof(*b), blen, fd);
1685 if (Ferror(fd) || (size > 0 && nb != blen)) {
1689 if (blen == blenmax && nb < blen) {
1691 b = xrealloc(b, blen+1);
1697 if (fd) (void) Fclose(fd);
1706 else if (b) free(b);
1708 if (blenp) *blenp = blen;
1713 void fdInitDigest(FD_t fd, int hashalgo, rpmDigestFlags flags)
1715 if (fd->digests == NULL) {
1716 fd->digests = rpmDigestBundleNew();
1718 fdstat_enter(fd, FDSTAT_DIGEST);
1719 rpmDigestBundleAdd(fd->digests, hashalgo, flags);
1720 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);
1723 static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen)
1725 if (fd && fd->digests) {
1726 fdstat_enter(fd, FDSTAT_DIGEST);
1727 rpmDigestBundleUpdate(fd->digests, buf, buflen);
1728 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) buflen);
1732 void fdFiniDigest(FD_t fd, int hashalgo,
1733 void ** datap, size_t * lenp, int asAscii)
1735 if (fd && fd->digests) {
1736 fdstat_enter(fd, FDSTAT_DIGEST);
1737 rpmDigestBundleFinal(fd->digests, hashalgo, datap, lenp, asAscii);
1738 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);