10 #include <rpm/rpmlog.h>
11 #include <rpm/rpmmacro.h>
12 #include <rpm/rpmfileutil.h>
13 #include <rpm/rpmsw.h>
14 #include <rpm/rpmurl.h>
16 #include "rpmio/rpmio_internal.h"
20 typedef struct _FDSTACK_s {
27 * Cumulative statistics for a descriptor.
30 struct rpmop_s ops[FDSTAT_MAX]; /*!< Cumulative statistics. */
34 * The FD_t File Handle data structure.
39 #define RPMIO_DEBUG_IO 0x40000000
41 #define FDMAGIC 0x04463138
44 int urlType; /* ufdio: */
46 int syserrno; /* last system errno encountered */
47 const char *errcookie; /* gzdio/bzdio/ufdio/xzdio: */
49 char *descr; /* file name (or other description) */
50 FDSTAT_t stats; /* I/O statistics */
52 rpmDigestBundle digests;
55 #define DBG(_f, _m, _x) \
57 if ((_rpmio_debug | ((_f) ? ((FD_t)(_f))->flags : 0)) & (_m)) fprintf _x \
59 #define DBGIO(_f, _x) DBG((_f), RPMIO_DEBUG_IO, _x)
61 static FDIO_t fdGetIo(FD_t fd)
63 return (fd != NULL) ? fd->fps[fd->nfps].io : NULL;
66 static void fdSetIo(FD_t fd, FDIO_t io)
69 fd->fps[fd->nfps].io = io;
72 static void * fdGetFp(FD_t fd)
74 return (fd != NULL) ? fd->fps[fd->nfps].fp : NULL;
77 static void fdSetFp(FD_t fd, void * fp)
80 fd->fps[fd->nfps].fp = fp;
83 static void fdSetFdno(FD_t fd, int fdno)
86 fd->fps[fd->nfps].fdno = fdno;
89 static void fdPush(FD_t fd, FDIO_t io, void * fp, int fdno)
91 if (fd == NULL || fd->nfps >= (sizeof(fd->fps)/sizeof(fd->fps[0]) - 1))
99 static void fdPop(FD_t fd)
101 if (fd == NULL || fd->nfps < 0) return;
108 void fdSetBundle(FD_t fd, rpmDigestBundle bundle)
111 fd->digests = bundle;
114 rpmDigestBundle fdGetBundle(FD_t fd)
116 return (fd != NULL) ? fd->digests : NULL;
119 static void * iotFileno(FD_t fd, FDIO_t iot)
126 for (int i = fd->nfps; i >= 0; i--) {
127 FDSTACK_t * fps = &fd->fps[i];
138 * \name RPMIO Vectors.
140 typedef ssize_t (*fdio_read_function_t) (FD_t fd, void *buf, size_t nbytes);
141 typedef ssize_t (*fdio_write_function_t) (FD_t fd, const void *buf, size_t nbytes);
142 typedef int (*fdio_seek_function_t) (FD_t fd, off_t pos, int whence);
143 typedef int (*fdio_close_function_t) (FD_t fd);
144 typedef FD_t (*fdio_ref_function_t) (FD_t fd);
145 typedef FD_t (*fdio_deref_function_t) (FD_t fd);
146 typedef FD_t (*fdio_new_function_t) (const char *descr);
147 typedef int (*fdio_fileno_function_t) (FD_t fd);
148 typedef FD_t (*fdio_open_function_t) (const char * path, int flags, mode_t mode);
149 typedef FD_t (*fdio_fopen_function_t) (const char * path, const char * fmode);
150 typedef void * (*fdio_ffileno_function_t) (FD_t fd);
151 typedef int (*fdio_fflush_function_t) (FD_t fd);
152 typedef long (*fdio_ftell_function_t) (FD_t);
155 fdio_read_function_t read;
156 fdio_write_function_t write;
157 fdio_seek_function_t seek;
158 fdio_close_function_t close;
160 fdio_ref_function_t _fdref;
161 fdio_deref_function_t _fdderef;
162 fdio_new_function_t _fdnew;
163 fdio_fileno_function_t _fileno;
165 fdio_open_function_t _open;
166 fdio_fopen_function_t _fopen;
167 fdio_ffileno_function_t _ffileno;
168 fdio_fflush_function_t _fflush;
169 fdio_ftell_function_t _ftell;
173 static const FDIO_t fdio;
174 static const FDIO_t ufdio;
175 static const FDIO_t gzdio;
176 static const FDIO_t bzdio;
177 static const FDIO_t xzdio;
178 static const FDIO_t lzdio;
181 * Update digest(s) attached to fd.
183 static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen);
184 static FD_t fdNew(const char *descr);
187 int _rpmio_debug = 0;
189 /* =============================================================== */
191 static const char * fdbg(FD_t fd)
193 static char buf[BUFSIZ];
202 for (i = fd->nfps; i >= 0; i--) {
203 FDSTACK_t * fps = &fd->fps[i];
208 if (fps->io == fdio) {
209 sprintf(be, "FD %d fp %p", fps->fdno, fps->fp);
210 } else if (fps->io == ufdio) {
211 sprintf(be, "UFD %d fp %p", fps->fdno, fps->fp);
212 } else if (fps->io == gzdio) {
213 sprintf(be, "GZD %p fdno %d", fps->fp, fps->fdno);
215 } else if (fps->io == bzdio) {
216 sprintf(be, "BZD %p fdno %d", fps->fp, fps->fdno);
219 } else if (fps->io == xzdio) {
220 sprintf(be, "XZD %p fdno %d", fps->fp, fps->fdno);
221 } else if (fps->io == lzdio) {
222 sprintf(be, "LZD %p fdno %d", fps->fp, fps->fdno);
225 sprintf(be, "??? io %p fp %p fdno %d ???",
226 fps->io, fps->fp, fps->fdno);
234 static void fdstat_enter(FD_t fd, fdOpX opx)
236 if (fd->stats != NULL)
237 (void) rpmswEnter(fdOp(fd, opx), (ssize_t) 0);
240 static void fdstat_exit(FD_t fd, fdOpX opx, ssize_t rc)
243 fd->syserrno = errno;
244 if (fd->stats != NULL)
245 (void) rpmswExit(fdOp(fd, opx), rc);
248 static void fdstat_print(FD_t fd, const char * msg, FILE * fp)
250 static const int usec_scale = (1000*1000);
253 if (fd == NULL || fd->stats == NULL) return;
254 for (opx = 0; opx < 4; opx++) {
255 rpmop op = &fd->stats->ops[opx];
256 if (op->count <= 0) continue;
259 if (msg) fprintf(fp, "%s:", msg);
260 fprintf(fp, "%8d reads, %8ld total bytes in %d.%06d secs\n",
261 op->count, (long)op->bytes,
262 (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
265 if (msg) fprintf(fp, "%s:", msg);
266 fprintf(fp, "%8d writes, %8ld total bytes in %d.%06d secs\n",
267 op->count, (long)op->bytes,
268 (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
278 off_t fdSize(FD_t fd)
283 if (fd != NULL && fstat(Fileno(fd), &sb) == 0)
293 if ((nfdno = dup(fdno)) < 0)
296 fdSetFdno(fd, nfdno);
297 DBGIO(fd, (stderr, "==> fdDup(%d) fd %p %s\n", fdno, (fd ? fd : NULL), fdbg(fd)));
301 /* Regular fd doesn't have fflush() equivalent but its not an error either */
302 static int fdFlush(FD_t fd)
307 static int fdFileno(FD_t fd)
309 return (fd != NULL) ? fd->fps[0].fdno : -2;
312 const char * Fdescr(FD_t fd)
317 /* Lazy lookup if description is not set (eg dupped fd) */
318 if (fd->descr == NULL) {
319 int fdno = fd->fps[fd->nfps].fdno;
320 #if defined(__linux__)
321 /* Grab the path from /proc if we can */
322 char *procpath = NULL;
326 rasprintf(&procpath, "/proc/self/fd/%d", fdno);
327 llen = readlink(procpath, buf, sizeof(buf)-1);
332 /* Real paths in /proc are always absolute */
334 fd->descr = xstrdup(buf);
336 fd->descr = rstrscat(NULL, "[", buf, "]", NULL);
339 /* Still no description, base it on fdno which is always there */
340 if (fd->descr == NULL)
341 rasprintf(&(fd->descr), "[fd %d]", fdno);
353 FD_t fdFree( FD_t fd)
358 fd->stats = _free(fd->stats);
360 fd->digests = rpmDigestBundleFree(fd->digests);
368 FD_t fdNew(const char *descr)
370 FD_t fd = xcalloc(1, sizeof(*fd));
371 if (fd == NULL) /* XXX xmalloc never returns NULL */
376 fd->urlType = URL_IS_UNKNOWN;
379 memset(fd->fps, 0, sizeof(fd->fps));
381 fd->fps[0].io = fdio;
382 fd->fps[0].fp = NULL;
383 fd->fps[0].fdno = -1;
386 fd->errcookie = NULL;
387 fd->stats = xcalloc(1, sizeof(*fd->stats));
389 fd->descr = descr ? xstrdup(descr) : NULL;
394 static ssize_t fdRead(FD_t fd, void * buf, size_t count)
396 return read(fdFileno(fd), buf, count);
399 static ssize_t fdWrite(FD_t fd, const void * buf, size_t count)
404 return write(fdFileno(fd), buf, count);
407 static int fdSeek(FD_t fd, off_t pos, int whence)
409 return lseek(fdFileno(fd), pos, whence);
412 static int fdClose(FD_t fd)
417 if (fd == NULL) return -2;
422 rc = ((fdno >= 0) ? close(fdno) : -2);
428 static FD_t fdOpen(const char *path, int flags, mode_t mode)
433 fdno = open(path, flags, mode);
434 if (fdno < 0) return NULL;
435 if (fcntl(fdno, F_SETFD, FD_CLOEXEC)) {
445 static long fdTell(FD_t fd)
447 return lseek(Fileno(fd), 0, SEEK_CUR);
450 static const struct FDIO_s fdio_s = {
451 fdRead, fdWrite, fdSeek, fdClose, fdLink, fdFree, fdNew, fdFileno,
452 fdOpen, NULL, fdGetFp, fdFlush, fdTell
454 static const FDIO_t fdio = &fdio_s ;
456 off_t ufdCopy(FD_t sfd, FD_t tfd)
459 ssize_t rdbytes, wrbytes;
463 rdbytes = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd);
466 wrbytes = Fwrite(buf, sizeof(buf[0]), rdbytes, tfd);
467 if (wrbytes != rdbytes) {
483 * Deal with remote url's by fetching them with a helper application
484 * and treat as local file afterwards.
486 * - better error checking + reporting
487 * - curl & friends don't know about hkp://, transform to http?
490 static FD_t urlOpen(const char * url, int flags, mode_t mode)
494 int rc = 1; /* assume failure */
496 fd = rpmMkTempFile(NULL, &dest);
502 rc = urlGetFile(url, dest);
504 fd = fdOpen(dest, flags, mode);
514 static FD_t ufdOpen(const char * url, int flags, mode_t mode)
518 urltype urlType = urlPath(url, &path);
521 fprintf(stderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mode);
528 fd = urlOpen(url, flags, mode);
529 /* we're dealing with local file when urlOpen() returns */
530 urlType = URL_IS_UNKNOWN;
533 if ((flags & O_ACCMODE) == O_RDWR) {
536 fd = fdDup((flags & O_ACCMODE) == O_WRONLY ?
537 STDOUT_FILENO : STDIN_FILENO);
543 fd = fdOpen(path, flags, mode);
547 if (fd == NULL) return NULL;
550 fd->urlType = urlType;
552 if (Fileno(fd) < 0) {
559 static const struct FDIO_s ufdio_s = {
560 fdRead, fdWrite, fdSeek, fdClose, fdLink, fdFree, fdNew, fdFileno,
561 ufdOpen, NULL, fdGetFp, fdFlush, fdTell
563 static const FDIO_t ufdio = &ufdio_s ;
565 /* =============================================================== */
566 /* Support for GZIP library. */
569 static void * gzdFileno(FD_t fd)
571 return iotFileno(fd, gzdio);
575 FD_t gzdOpen(const char * path, const char * fmode)
579 if ((gzfile = gzopen(path, fmode)) == NULL)
582 fdPop(fd); fdPush(fd, gzdio, gzfile, -1);
587 static FD_t gzdFdopen(FD_t fd, const char *fmode)
592 if (fd == NULL || fmode == NULL) return NULL;
594 fdSetFdno(fd, -1); /* XXX skip the fdio close */
595 if (fdno < 0) return NULL;
596 gzfile = gzdopen(fdno, fmode);
597 if (gzfile == NULL) return NULL;
599 fdPush(fd, gzdio, gzfile, fdno); /* Push gzdio onto stack */
604 static int gzdFlush(FD_t fd)
607 gzfile = gzdFileno(fd);
608 if (gzfile == NULL) return -2;
609 return gzflush(gzfile, Z_SYNC_FLUSH); /* XXX W2DO? */
612 static ssize_t gzdRead(FD_t fd, void * buf, size_t count)
617 gzfile = gzdFileno(fd);
618 if (gzfile == NULL) return -2; /* XXX can't happen */
620 rc = gzread(gzfile, buf, count);
623 fd->errcookie = gzerror(gzfile, &zerror);
624 if (zerror == Z_ERRNO) {
625 fd->syserrno = errno;
626 fd->errcookie = strerror(fd->syserrno);
632 static ssize_t gzdWrite(FD_t fd, const void * buf, size_t count)
637 gzfile = gzdFileno(fd);
638 if (gzfile == NULL) return -2; /* XXX can't happen */
640 rc = gzwrite(gzfile, (void *)buf, count);
643 fd->errcookie = gzerror(gzfile, &zerror);
644 if (zerror == Z_ERRNO) {
645 fd->syserrno = errno;
646 fd->errcookie = strerror(fd->syserrno);
652 /* XXX zlib-1.0.4 has not */
653 static int gzdSeek(FD_t fd, off_t pos, int whence)
660 if (fd == NULL) return -2;
662 gzfile = gzdFileno(fd);
663 if (gzfile == NULL) return -2; /* XXX can't happen */
665 rc = gzseek(gzfile, p, whence);
668 fd->errcookie = gzerror(gzfile, &zerror);
669 if (zerror == Z_ERRNO) {
670 fd->syserrno = errno;
671 fd->errcookie = strerror(fd->syserrno);
680 static int gzdClose(FD_t fd)
685 gzfile = gzdFileno(fd);
686 if (gzfile == NULL) return -2; /* XXX can't happen */
688 rc = gzclose(gzfile);
690 /* XXX TODO: preserve fd if errors */
694 fd->errcookie = "gzclose error";
696 fd->syserrno = errno;
697 fd->errcookie = strerror(fd->syserrno);
702 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "GZDIO", stderr);
708 static long gzdTell(FD_t fd)
711 gzFile gzfile = gzdFileno(fd);
713 if (gzfile != NULL) {
715 pos = gztell(gzfile);
718 fd->errcookie = gzerror(gzfile, &zerror);
719 if (zerror == Z_ERRNO) {
720 fd->syserrno = errno;
721 fd->errcookie = strerror(fd->syserrno);
730 static const struct FDIO_s gzdio_s = {
731 gzdRead, gzdWrite, gzdSeek, gzdClose, fdLink, fdFree, fdNew, fdFileno,
732 NULL, gzdOpen, gzdFileno, gzdFlush, gzdTell
734 static const FDIO_t gzdio = &gzdio_s ;
736 /* =============================================================== */
737 /* Support for BZIP2 library. */
742 static void * bzdFileno(FD_t fd)
744 return iotFileno(fd, bzdio);
747 static FD_t bzdOpen(const char * path, const char * mode)
751 if ((bzfile = BZ2_bzopen(path, mode)) == NULL)
754 fdPop(fd); fdPush(fd, bzdio, bzfile, -1);
758 static FD_t bzdFdopen(FD_t fd, const char * fmode)
763 if (fd == NULL || fmode == NULL) return NULL;
765 fdSetFdno(fd, -1); /* XXX skip the fdio close */
766 if (fdno < 0) return NULL;
767 bzfile = BZ2_bzdopen(fdno, fmode);
768 if (bzfile == NULL) return NULL;
770 fdPush(fd, bzdio, bzfile, fdno); /* Push bzdio onto stack */
775 static int bzdFlush(FD_t fd)
777 return BZ2_bzflush(bzdFileno(fd));
780 static ssize_t bzdRead(FD_t fd, void * buf, size_t count)
785 bzfile = bzdFileno(fd);
787 rc = BZ2_bzread(bzfile, buf, count);
791 fd->errcookie = BZ2_bzerror(bzfile, &zerror);
796 static ssize_t bzdWrite(FD_t fd, const void * buf, size_t count)
801 bzfile = bzdFileno(fd);
802 rc = BZ2_bzwrite(bzfile, (void *)buf, count);
805 fd->errcookie = BZ2_bzerror(bzfile, &zerror);
810 static int bzdClose(FD_t fd)
815 bzfile = bzdFileno(fd);
817 if (bzfile == NULL) return -2;
820 rc = 0; /* XXX FIXME */
822 /* XXX TODO: preserve fd if errors */
827 fd->errcookie = BZ2_bzerror(bzfile, &zerror);
831 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "BZDIO", stderr);
837 static const struct FDIO_s bzdio_s = {
838 bzdRead, bzdWrite, NULL, bzdClose, fdLink, fdFree, fdNew, fdFileno,
839 NULL, bzdOpen, bzdFileno, bzdFlush, NULL
841 static const FDIO_t bzdio = &bzdio_s ;
843 #endif /* HAVE_BZLIB_H */
845 static const char * getFdErrstr (FD_t fd)
847 const char *errstr = NULL;
849 if (fdGetIo(fd) == gzdio) {
850 errstr = fd->errcookie;
853 if (fdGetIo(fd) == bzdio) {
854 errstr = fd->errcookie;
856 #endif /* HAVE_BZLIB_H */
858 if (fdGetIo(fd) == xzdio || fdGetIo(fd) == lzdio) {
859 errstr = fd->errcookie;
861 #endif /* HAVE_LZMA_H */
863 errstr = (fd->syserrno ? strerror(fd->syserrno) : "");
869 /* =============================================================== */
870 /* Support for LZMA library. */
874 #include <sys/types.h>
875 #include <inttypes.h>
878 #define kBufferSize (1 << 15)
880 typedef struct lzfile {
882 uint8_t buf[kBufferSize];
893 static LZFILE *lzopen_internal(const char *path, const char *mode, int fd, int xz)
895 int level = LZMA_PRESET_DEFAULT;
900 lzma_stream init_strm = LZMA_STREAM_INIT;
901 uint64_t mem_limit = rpmExpandNumeric("%{_xz_memlimit}");
904 for (; *mode; mode++) {
907 else if (*mode == 'r')
909 else if (*mode >= '0' && *mode <= '9')
911 else if (*mode == 'T') {
912 if (isdigit(*(mode+1))) {
913 threads = atoi(++mode);
914 /* skip past rest of digits in string that atoi()
915 * should've processed
917 while(isdigit(*++mode));
924 fp = fdopen(fd, encoding ? "w" : "r");
926 fp = fopen(path, encoding ? "w" : "r");
929 lzfile = calloc(1, sizeof(*lzfile));
936 lzfile->encoding = encoding;
938 lzfile->strm = init_strm;
942 ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
945 threads = sysconf(_SC_NPROCESSORS_ONLN);
946 lzma_mt mt_options = {
953 .check = LZMA_CHECK_SHA256 };
955 ret = lzma_stream_encoder_mt(&lzfile->strm, &mt_options);
958 lzma_options_lzma options;
959 lzma_lzma_preset(&options, level);
960 ret = lzma_alone_encoder(&lzfile->strm, &options);
962 } else { /* lzma_easy_decoder_memusage(level) is not ready yet, use hardcoded limit for now */
963 ret = lzma_auto_decoder(&lzfile->strm, mem_limit ? mem_limit : 100<<20, 0);
965 if (ret != LZMA_OK) {
968 rpmlog(RPMLOG_ERR, "liblzma: Memory allocation failed");
971 case LZMA_DATA_ERROR:
972 rpmlog(RPMLOG_ERR, "liblzma: File size limits exceeded");
976 rpmlog(RPMLOG_ERR, "liblzma: <Unknown error (%d), possibly a bug", ret);
986 static LZFILE *xzopen(const char *path, const char *mode)
988 return lzopen_internal(path, mode, -1, 1);
991 static LZFILE *xzdopen(int fd, const char *mode)
995 return lzopen_internal(0, mode, fd, 1);
998 static LZFILE *lzopen(const char *path, const char *mode)
1000 return lzopen_internal(path, mode, -1, 0);
1003 static LZFILE *lzdopen(int fd, const char *mode)
1007 return lzopen_internal(0, mode, fd, 0);
1010 static int lzflush(LZFILE *lzfile)
1012 return fflush(lzfile->file);
1015 static int lzclose(LZFILE *lzfile)
1023 if (lzfile->encoding) {
1025 lzfile->strm.avail_out = kBufferSize;
1026 lzfile->strm.next_out = lzfile->buf;
1027 ret = lzma_code(&lzfile->strm, LZMA_FINISH);
1028 if (ret != LZMA_OK && ret != LZMA_STREAM_END)
1030 n = kBufferSize - lzfile->strm.avail_out;
1031 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
1033 if (ret == LZMA_STREAM_END)
1037 lzma_end(&lzfile->strm);
1038 rc = fclose(lzfile->file);
1043 static ssize_t lzread(LZFILE *lzfile, void *buf, size_t len)
1048 if (!lzfile || lzfile->encoding)
1052 lzfile->strm.next_out = buf;
1053 lzfile->strm.avail_out = len;
1055 if (!lzfile->strm.avail_in) {
1056 lzfile->strm.next_in = lzfile->buf;
1057 lzfile->strm.avail_in = fread(lzfile->buf, 1, kBufferSize, lzfile->file);
1058 if (!lzfile->strm.avail_in)
1061 ret = lzma_code(&lzfile->strm, LZMA_RUN);
1062 if (ret == LZMA_STREAM_END) {
1064 return len - lzfile->strm.avail_out;
1068 if (!lzfile->strm.avail_out)
1075 static ssize_t lzwrite(LZFILE *lzfile, void *buf, size_t len)
1079 if (!lzfile || !lzfile->encoding)
1083 lzfile->strm.next_in = buf;
1084 lzfile->strm.avail_in = len;
1086 lzfile->strm.next_out = lzfile->buf;
1087 lzfile->strm.avail_out = kBufferSize;
1088 ret = lzma_code(&lzfile->strm, LZMA_RUN);
1091 n = kBufferSize - lzfile->strm.avail_out;
1092 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
1094 if (!lzfile->strm.avail_in)
1099 static void * lzdFileno(FD_t fd)
1106 for (int i = fd->nfps; i >= 0; i--) {
1107 FDSTACK_t * fps = &fd->fps[i];
1108 if (fps->io != xzdio && fps->io != lzdio)
1116 static FD_t xzdOpen(const char * path, const char * mode)
1120 if ((lzfile = xzopen(path, mode)) == NULL)
1123 fdPop(fd); fdPush(fd, xzdio, lzfile, -1);
1127 static FD_t xzdFdopen(FD_t fd, const char * fmode)
1132 if (fd == NULL || fmode == NULL) return NULL;
1133 fdno = fdFileno(fd);
1134 fdSetFdno(fd, -1); /* XXX skip the fdio close */
1135 if (fdno < 0) return NULL;
1136 lzfile = xzdopen(fdno, fmode);
1137 if (lzfile == NULL) return NULL;
1138 fdPush(fd, xzdio, lzfile, fdno);
1142 static FD_t lzdOpen(const char * path, const char * mode)
1146 if ((lzfile = lzopen(path, mode)) == NULL)
1149 fdPop(fd); fdPush(fd, xzdio, lzfile, -1);
1153 static FD_t lzdFdopen(FD_t fd, const char * fmode)
1158 if (fd == NULL || fmode == NULL) return NULL;
1159 fdno = fdFileno(fd);
1160 fdSetFdno(fd, -1); /* XXX skip the fdio close */
1161 if (fdno < 0) return NULL;
1162 lzfile = lzdopen(fdno, fmode);
1163 if (lzfile == NULL) return NULL;
1164 fdPush(fd, xzdio, lzfile, fdno);
1168 static int lzdFlush(FD_t fd)
1170 return lzflush(lzdFileno(fd));
1173 static ssize_t lzdRead(FD_t fd, void * buf, size_t count)
1178 lzfile = lzdFileno(fd);
1180 rc = lzread(lzfile, buf, count);
1182 fd->errcookie = "Lzma: decoding error";
1187 static ssize_t lzdWrite(FD_t fd, const void * buf, size_t count)
1192 lzfile = lzdFileno(fd);
1194 rc = lzwrite(lzfile, (void *)buf, count);
1196 fd->errcookie = "Lzma: encoding error";
1201 static int lzdClose(FD_t fd)
1206 lzfile = lzdFileno(fd);
1208 if (lzfile == NULL) return -2;
1209 rc = lzclose(lzfile);
1211 /* XXX TODO: preserve fd if errors */
1215 fd->errcookie = "lzclose error";
1216 fd->syserrno = errno;
1217 fd->errcookie = strerror(fd->syserrno);
1221 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "XZDIO", stderr);
1227 static struct FDIO_s xzdio_s = {
1228 lzdRead, lzdWrite, NULL, lzdClose, NULL, NULL, NULL, fdFileno,
1229 NULL, xzdOpen, lzdFileno, lzdFlush, NULL
1231 static const FDIO_t xzdio = &xzdio_s;
1233 static struct FDIO_s lzdio_s = {
1234 lzdRead, lzdWrite, NULL, lzdClose, NULL, NULL, NULL, fdFileno,
1235 NULL, lzdOpen, lzdFileno, lzdFlush, NULL
1237 static const FDIO_t lzdio = &lzdio_s;
1239 #endif /* HAVE_LZMA_H */
1241 /* =============================================================== */
1243 const char *Fstrerror(FD_t fd)
1246 return (errno ? strerror(errno) : "");
1247 return getFdErrstr(fd);
1250 #define FDIOVEC(_fd, _vec) \
1251 ((fdGetIo(_fd) && fdGetIo(_fd)->_vec) ? fdGetIo(_fd)->_vec : NULL)
1253 ssize_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
1258 fdio_read_function_t _read = FDIOVEC(fd, read);
1260 fdstat_enter(fd, FDSTAT_READ);
1262 rc = (_read ? (*_read) (fd, buf, size * nmemb) : -2);
1263 } while (rc == -1 && errno == EINTR);
1264 fdstat_exit(fd, FDSTAT_READ, rc);
1266 if (fd->digests && rc > 0)
1267 fdUpdateDigests(fd, buf, rc);
1270 DBGIO(fd, (stderr, "==>\tFread(%p,%p,%ld) rc %ld %s\n",
1271 fd, buf, (long)size * nmemb, (long)rc, fdbg(fd)));
1276 ssize_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
1281 fdio_write_function_t _write = FDIOVEC(fd, write);
1283 fdstat_enter(fd, FDSTAT_WRITE);
1285 rc = (_write ? _write(fd, buf, size * nmemb) : -2);
1286 } while (rc == -1 && errno == EINTR);
1287 fdstat_exit(fd, FDSTAT_WRITE, rc);
1289 if (fd->digests && rc > 0)
1290 fdUpdateDigests(fd, buf, rc);
1293 DBGIO(fd, (stderr, "==>\tFwrite(%p,%p,%ld) rc %ld %s\n",
1294 fd, buf, (long)size * nmemb, (long)rc, fdbg(fd)));
1299 int Fseek(FD_t fd, off_t offset, int whence)
1304 fdio_seek_function_t _seek = FDIOVEC(fd, seek);
1306 fdstat_enter(fd, FDSTAT_SEEK);
1307 rc = (_seek ? _seek(fd, offset, whence) : -2);
1308 fdstat_exit(fd, FDSTAT_SEEK, rc);
1311 DBGIO(fd, (stderr, "==>\tFseek(%p,%ld,%d) rc %lx %s\n",
1312 fd, (long)offset, whence, (unsigned long)rc, fdbg(fd)));
1325 fdstat_enter(fd, FDSTAT_CLOSE);
1326 while (fd->nfps >= 0) {
1327 fdio_close_function_t _close = FDIOVEC(fd, close);
1328 rc = _close ? _close(fd) : -2;
1336 fdstat_exit(fd, FDSTAT_CLOSE, rc);
1337 DBGIO(fd, (stderr, "==>\tFclose(%p) rc %lx %s\n",
1338 (fd ? fd : NULL), (unsigned long)rc, fdbg(fd)));
1345 * Convert stdio fmode to open(2) mode, filtering out zlib/bzlib flags.
1346 * returns stdio[0] = NUL on error.
1348 * - gzopen: [0-9] is compression level
1349 * - gzopen: 'f' is filtered (Z_FILTERED)
1350 * - gzopen: 'h' is Huffman encoding (Z_HUFFMAN_ONLY)
1351 * - bzopen: [1-9] is block size (modulo 100K)
1352 * - bzopen: 's' is smallmode
1353 * - HACK: '.' terminates, rest is type of I/O
1355 static void cvtfmode (const char *m,
1356 char *stdio, size_t nstdio,
1357 char *other, size_t nother,
1358 const char **end, int * f)
1365 flags |= O_WRONLY | O_CREAT | O_APPEND;
1366 if (--nstdio > 0) *stdio++ = *m;
1369 flags |= O_WRONLY | O_CREAT | O_TRUNC;
1370 if (--nstdio > 0) *stdio++ = *m;
1374 if (--nstdio > 0) *stdio++ = *m;
1383 while ((c = *m++) != '\0') {
1388 flags &= ~(O_RDONLY|O_WRONLY);
1390 if (--nstdio > 0) *stdio++ = c;
1394 if (--nstdio > 0) *stdio++ = c;
1399 if (--nstdio > 0) *stdio++ = c;
1403 if (--nother > 0) *other++ = c;
1410 *stdio = *other = '\0';
1412 *end = (*m != '\0' ? m : NULL);
1417 FD_t Fdopen(FD_t ofd, const char *fmode)
1419 char stdio[20], other[20], zstdio[40];
1420 const char *end = NULL;
1425 fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
1427 if (fd == NULL || fmode == NULL)
1430 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL);
1431 if (stdio[0] == '\0')
1434 strncat(zstdio, stdio, sizeof(zstdio) - strlen(zstdio) - 1);
1435 strncat(zstdio, other, sizeof(zstdio) - strlen(zstdio) - 1);
1437 if (end == NULL && other[0] == '\0')
1441 if (rstreq(end, "fdio")) {
1443 } else if (rstreq(end, "gzdio") || rstreq(end, "gzip")) {
1445 fd = gzdFdopen(fd, zstdio);
1447 } else if (rstreq(end, "bzdio") || rstreq(end, "bzip2")) {
1449 fd = bzdFdopen(fd, zstdio);
1452 } else if (rstreq(end, "xzdio") || rstreq(end, "xz")) {
1454 fd = xzdFdopen(fd, zstdio);
1455 } else if (rstreq(end, "lzdio") || rstreq(end, "lzma")) {
1457 fd = lzdFdopen(fd, zstdio);
1459 } else if (rstreq(end, "ufdio")) {
1462 } else if (other[0] != '\0') {
1463 for (end = other; *end && strchr("0123456789fh", *end); end++)
1467 fd = gzdFdopen(fd, zstdio);
1473 DBGIO(fd, (stderr, "==> Fdopen(%p,\"%s\") returns fd %p %s\n", ofd, fmode, (fd ? fd : NULL), fdbg(fd)));
1477 FD_t Fopen(const char *path, const char *fmode)
1479 char stdio[20], other[20];
1480 const char *end = NULL;
1481 mode_t perms = 0666;
1485 if (path == NULL || fmode == NULL)
1489 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, &flags);
1490 if (stdio[0] == '\0')
1493 if (end == NULL || rstreq(end, "fdio")) {
1495 fprintf(stderr, "*** Fopen fdio path %s fmode %s\n", path, fmode);
1496 fd = fdOpen(path, flags, perms);
1497 if (fdFileno(fd) < 0) {
1498 if (fd) (void) fdClose(fd);
1502 /* XXX gzdio and bzdio here too */
1504 switch (urlIsURL(path)) {
1511 case URL_IS_UNKNOWN:
1513 fprintf(stderr, "*** Fopen ufdio path %s fmode %s\n", path, fmode);
1514 fd = ufdOpen(path, flags, perms);
1515 if (fd == NULL || !(fdFileno(fd) >= 0))
1520 fprintf(stderr, "*** Fopen WTFO path %s fmode %s\n", path, fmode);
1528 fd = Fdopen(fd, fmode);
1530 DBGIO(fd, (stderr, "==>\tFopen(\"%s\",%x,0%o) %s\n",
1531 path, (unsigned)flags, (unsigned)perms, fdbg(fd)));
1540 fdio_fflush_function_t _fflush = FDIOVEC(fd, _fflush);
1542 rc = (_fflush ? _fflush(fd) : -2);
1547 off_t Ftell(FD_t fd)
1551 fdio_ftell_function_t _ftell = FDIOVEC(fd, _ftell);
1553 pos = (_ftell ? _ftell(fd) : -2);
1562 if (fd == NULL) return -1;
1563 for (i = fd->nfps; rc == 0 && i >= 0; i--) {
1564 FDSTACK_t * fps = &fd->fps[i];
1567 if (fps->io == gzdio) {
1568 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
1569 i--; /* XXX fdio under gzdio always has fdno == -1 */
1571 } else if (fps->io == bzdio) {
1572 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
1573 i--; /* XXX fdio under bzdio always has fdno == -1 */
1576 } else if (fps->io == xzdio || fps->io == lzdio) {
1577 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
1578 i--; /* XXX fdio under xzdio/lzdio always has fdno == -1 */
1581 /* XXX need to check ufdio/gzdio/bzdio/fdio errors correctly. */
1582 ec = (fdFileno(fd) < 0 ? -1 : 0);
1588 DBGIO(fd, (stderr, "==> Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd)));
1596 if (fd == NULL) return -1;
1597 for (i = fd->nfps ; rc == -1 && i >= 0; i--) {
1598 rc = fd->fps[i].fdno;
1601 DBGIO(fd, (stderr, "==> Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, fdbg(fd)));
1605 /* XXX this is naive */
1606 int Fcntl(FD_t fd, int op, void *lip)
1608 return fcntl(Fileno(fd), op, lip);
1611 rpmop fdOp(FD_t fd, fdOpX opx)
1615 if (fd != NULL && fd->stats != NULL && opx >= 0 && opx < FDSTAT_MAX)
1616 op = fd->stats->ops + opx;
1620 int rpmioSlurp(const char * fn, uint8_t ** bp, ssize_t * blenp)
1622 static const ssize_t blenmax = (32 * BUFSIZ);
1629 fd = Fopen(fn, "r.ufdio");
1630 if (fd == NULL || Ferror(fd)) {
1636 blen = (size >= 0 ? size : blenmax);
1639 b = xmalloc(blen+1);
1641 nb = Fread(b, sizeof(*b), blen, fd);
1642 if (Ferror(fd) || (size > 0 && nb != blen)) {
1646 if (blen == blenmax && nb < blen) {
1648 b = xrealloc(b, blen+1);
1654 if (fd) (void) Fclose(fd);
1663 else if (b) free(b);
1665 if (blenp) *blenp = blen;
1670 void fdInitDigest(FD_t fd, int hashalgo, rpmDigestFlags flags)
1672 if (fd->digests == NULL) {
1673 fd->digests = rpmDigestBundleNew();
1675 fdstat_enter(fd, FDSTAT_DIGEST);
1676 rpmDigestBundleAdd(fd->digests, hashalgo, flags);
1677 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);
1680 static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen)
1682 if (fd && fd->digests) {
1683 fdstat_enter(fd, FDSTAT_DIGEST);
1684 rpmDigestBundleUpdate(fd->digests, buf, buflen);
1685 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) buflen);
1689 void fdFiniDigest(FD_t fd, int hashalgo,
1690 void ** datap, size_t * lenp, int asAscii)
1692 if (fd && fd->digests) {
1693 fdstat_enter(fd, FDSTAT_DIGEST);
1694 rpmDigestBundleFinal(fd->digests, hashalgo, datap, lenp, asAscii);
1695 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);