9 #include <rpm/rpmlog.h>
10 #include <rpm/rpmmacro.h>
11 #include <rpm/rpmfileutil.h>
12 #include <rpm/rpmsw.h>
13 #include <rpm/rpmurl.h>
15 #include "rpmio/rpmio_internal.h"
19 #if HAVE_LIBIO_H && defined(_G_IO_IO_FILE_VERSION)
23 typedef struct _FDSTACK_s {
30 * Cumulative statistics for a descriptor.
33 struct rpmop_s ops[FDSTAT_MAX]; /*!< Cumulative statistics. */
37 * The FD_t File Handle data structure.
42 #define RPMIO_DEBUG_IO 0x40000000
43 #define RPMIO_DEBUG_REFS 0x20000000
45 #define FDMAGIC 0x04463138
48 int urlType; /* ufdio: */
50 ssize_t bytesRemain; /* ufdio: */
52 int syserrno; /* last system errno encountered */
53 const void *errcookie; /* gzdio/bzdio/ufdio/xzdio: */
55 FDSTAT_t stats; /* I/O statistics */
57 rpmDigestBundle digests;
60 #define DBG(_f, _m, _x) \
62 if ((_rpmio_debug | ((_f) ? ((FD_t)(_f))->flags : 0)) & (_m)) fprintf _x \
64 #define DBGIO(_f, _x) DBG((_f), RPMIO_DEBUG_IO, _x)
66 static FDIO_t fdGetIo(FD_t fd)
68 return (fd != NULL) ? fd->fps[fd->nfps].io : NULL;
71 static void fdSetIo(FD_t fd, FDIO_t io)
74 fd->fps[fd->nfps].io = io;
77 static void * fdGetFp(FD_t fd)
79 return (fd != NULL) ? fd->fps[fd->nfps].fp : NULL;
82 static void fdSetFp(FD_t fd, void * fp)
85 fd->fps[fd->nfps].fp = fp;
88 static void fdSetFdno(FD_t fd, int fdno)
91 fd->fps[fd->nfps].fdno = fdno;
94 static void fdPush(FD_t fd, FDIO_t io, void * fp, int fdno)
96 if (fd == NULL || fd->nfps >= (sizeof(fd->fps)/sizeof(fd->fps[0]) - 1))
104 static void fdPop(FD_t fd)
106 if (fd == NULL || fd->nfps < 0) return;
113 static FD_t c2f(void * cookie)
115 FD_t fd = (FD_t) cookie;
116 return (fd && fd->magic == FDMAGIC) ? fd : NULL;
119 void fdSetBundle(FD_t fd, rpmDigestBundle bundle)
122 fd->digests = bundle;
125 rpmDigestBundle fdGetBundle(FD_t fd)
127 return (fd != NULL) ? fd->digests : NULL;
130 static void * iotFileno(FD_t fd, FDIO_t iot)
137 for (int i = fd->nfps; i >= 0; i--) {
138 FDSTACK_t * fps = &fd->fps[i];
148 #define FDNREFS(fd) (fd ? ((FD_t)fd)->nrefs : -9)
150 #define FDONLY(fd) assert(fdGetIo(fd) == fdio)
151 #define GZDONLY(fd) assert(fdGetIo(fd) == gzdio)
152 #define BZDONLY(fd) assert(fdGetIo(fd) == bzdio)
153 #define LZDONLY(fd) assert(fdGetIo(fd) == xzdio || fdGetIo(fd) == lzdio)
155 #define UFDONLY(fd) /* assert(fdGetIo(fd) == ufdio) */
160 static int noLibio = 0;
162 static int noLibio = 1;
166 * \name RPMIO Vectors.
168 typedef ssize_t (*fdio_read_function_t) (void *cookie, char *buf, size_t nbytes);
169 typedef ssize_t (*fdio_write_function_t) (void *cookie, const char *buf, size_t nbytes);
170 typedef int (*fdio_seek_function_t) (void *cookie, _libio_pos_t pos, int whence);
171 typedef int (*fdio_close_function_t) (void *cookie);
172 typedef FD_t (*fdio_ref_function_t) ( void * cookie);
173 typedef FD_t (*fdio_deref_function_t) (FD_t fd);
174 typedef FD_t (*fdio_new_function_t) (void);
175 typedef int (*fdio_fileno_function_t) (void * cookie);
176 typedef FD_t (*fdio_open_function_t) (const char * path, int flags, mode_t mode);
177 typedef FD_t (*fdio_fopen_function_t) (const char * path, const char * fmode);
178 typedef void * (*fdio_ffileno_function_t) (FD_t fd);
179 typedef int (*fdio_fflush_function_t) (FD_t fd);
184 fdio_read_function_t read;
185 fdio_write_function_t write;
186 fdio_seek_function_t seek;
187 fdio_close_function_t close;
189 fdio_ref_function_t _fdref;
190 fdio_deref_function_t _fdderef;
191 fdio_new_function_t _fdnew;
192 fdio_fileno_function_t _fileno;
194 fdio_open_function_t _open;
195 fdio_fopen_function_t _fopen;
196 fdio_ffileno_function_t _ffileno;
197 fdio_fflush_function_t _fflush;
201 static const FDIO_t fdio;
202 static const FDIO_t fpio;
203 static const FDIO_t ufdio;
204 static const FDIO_t gzdio;
205 static const FDIO_t bzdio;
206 static const FDIO_t xzdio;
207 static const FDIO_t lzdio;
210 * Update digest(s) attached to fd.
212 static void fdUpdateDigests(FD_t fd, const unsigned char * buf, size_t buflen);
216 int _rpmio_debug = 0;
218 /* =============================================================== */
220 static const char * fdbg(FD_t fd)
222 static char buf[BUFSIZ];
230 if (fd->bytesRemain != -1) {
231 sprintf(be, " clen %d", (int)fd->bytesRemain);
235 for (i = fd->nfps; i >= 0; i--) {
236 FDSTACK_t * fps = &fd->fps[i];
241 if (fps->io == fdio) {
242 sprintf(be, "FD %d fp %p", fps->fdno, fps->fp);
243 } else if (fps->io == ufdio) {
244 sprintf(be, "UFD %d fp %p", fps->fdno, fps->fp);
246 } else if (fps->io == gzdio) {
247 sprintf(be, "GZD %p fdno %d", fps->fp, fps->fdno);
250 } else if (fps->io == bzdio) {
251 sprintf(be, "BZD %p fdno %d", fps->fp, fps->fdno);
254 } else if (fps->io == xzdio) {
255 sprintf(be, "XZD %p fdno %d", fps->fp, fps->fdno);
256 } else if (fps->io == lzdio) {
257 sprintf(be, "LZD %p fdno %d", fps->fp, fps->fdno);
259 } else if (fps->io == fpio) {
260 sprintf(be, "%s %p(%d) fdno %d",
261 (fps->fdno < 0 ? "LIBIO" : "FP"),
262 fps->fp, fileno(((FILE *)fps->fp)), fps->fdno);
264 sprintf(be, "??? io %p fp %p fdno %d ???",
265 fps->io, fps->fp, fps->fdno);
273 static void fdstat_enter(FD_t fd, fdOpX opx)
275 if (fd == NULL) return;
276 if (fd->stats != NULL)
277 (void) rpmswEnter(fdOp(fd, opx), (ssize_t) 0);
280 static void fdstat_exit(FD_t fd, fdOpX opx, ssize_t rc)
282 if (fd == NULL) return;
284 fd->syserrno = errno;
285 else if (rc > 0 && fd->bytesRemain > 0)
289 fd->bytesRemain -= rc;
294 if (fd->stats != NULL)
295 (void) rpmswExit(fdOp(fd, opx), rc);
298 static void fdstat_print(FD_t fd, const char * msg, FILE * fp)
300 static const int usec_scale = (1000*1000);
303 if (fd == NULL || fd->stats == NULL) return;
304 for (opx = 0; opx < 4; opx++) {
305 rpmop op = &fd->stats->ops[opx];
306 if (op->count <= 0) continue;
309 if (msg) fprintf(fp, "%s:", msg);
310 fprintf(fp, "%8d reads, %8ld total bytes in %d.%06d secs\n",
311 op->count, (long)op->bytes,
312 (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
315 if (msg) fprintf(fp, "%s:", msg);
316 fprintf(fp, "%8d writes, %8ld total bytes in %d.%06d secs\n",
317 op->count, (long)op->bytes,
318 (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
328 /* =============================================================== */
329 off_t fdSize(FD_t fd)
334 if (fd != NULL && fstat(Fileno(fd), &sb) == 0)
344 if ((nfdno = dup(fdno)) < 0)
347 fdSetFdno(fd, nfdno);
348 DBGIO(fd, (stderr, "==> fdDup(%d) fd %p %s\n", fdno, (fd ? fd : NULL), fdbg(fd)));
352 static int fdSeekNot(void * cookie, _libio_pos_t pos, int whence)
359 static int fdFileno(void * cookie)
361 FD_t fd = c2f(cookie);
362 return (fd != NULL) ? fd->fps[0].fdno : -2;
365 FILE * fdGetFILE(FD_t fd)
367 return ((FILE *)fdGetFp(fd));
370 /* =============================================================== */
372 FD_t fdLink(void * cookie)
374 FD_t fd = c2f(cookie);
382 FD_t fdFree( FD_t fd)
387 fd->stats = _free(fd->stats);
389 fd->digests = rpmDigestBundleFree(fd->digests);
400 FD_t fd = xcalloc(1, sizeof(*fd));
401 if (fd == NULL) /* XXX xmalloc never returns NULL */
406 fd->urlType = URL_IS_UNKNOWN;
409 memset(fd->fps, 0, sizeof(fd->fps));
411 fd->fps[0].io = fdio;
412 fd->fps[0].fp = NULL;
413 fd->fps[0].fdno = -1;
415 fd->bytesRemain = -1;
417 fd->errcookie = NULL;
418 fd->stats = xcalloc(1, sizeof(*fd->stats));
426 static ssize_t fdRead(void * cookie, char * buf, size_t count)
428 FD_t fd = c2f(cookie);
431 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
433 fdstat_enter(fd, FDSTAT_READ);
434 rc = read(fdFileno(fd), buf, (count > fd->bytesRemain ? fd->bytesRemain : count));
435 fdstat_exit(fd, FDSTAT_READ, rc);
437 if (fd->digests && rc > 0) fdUpdateDigests(fd, (void *)buf, rc);
439 DBGIO(fd, (stderr, "==>\tfdRead(%p,%p,%ld) rc %ld %s\n", cookie, buf, (long)count, (long)rc, fdbg(fd)));
446 static ssize_t fdWrite(void * cookie, const char * buf, size_t count)
448 FD_t fd = c2f(cookie);
449 int fdno = fdFileno(fd);
452 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
454 if (fd->digests && count > 0) fdUpdateDigests(fd, (void *)buf, count);
456 if (count == 0) return 0;
458 fdstat_enter(fd, FDSTAT_WRITE);
459 rc = write(fdno, buf, (count > fd->bytesRemain ? fd->bytesRemain : count));
460 fdstat_exit(fd, FDSTAT_WRITE, rc);
462 DBGIO(fd, (stderr, "==>\tfdWrite(%p,%p,%ld) rc %ld %s\n", cookie, buf, (long)count, (long)rc, fdbg(fd)));
467 static int fdSeek(void * cookie, _libio_pos_t pos, int whence)
469 #ifdef USE_COOKIE_SEEK_POINTER
470 _IO_off64_t p = *pos;
474 FD_t fd = c2f(cookie);
480 assert(fd->bytesRemain == -1); /* XXX FIXME fadio only for now */
481 fdstat_enter(fd, FDSTAT_SEEK);
482 rc = lseek(fdFileno(fd), p, whence);
483 fdstat_exit(fd, FDSTAT_SEEK, rc);
485 DBGIO(fd, (stderr, "==>\tfdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd)));
492 static int fdClose( void * cookie)
494 FD_t fd = c2f(cookie);
498 if (fd == NULL) return -2;
503 fdstat_enter(fd, FDSTAT_CLOSE);
504 rc = ((fdno >= 0) ? close(fdno) : -2);
505 fdstat_exit(fd, FDSTAT_CLOSE, rc);
507 DBGIO(fd, (stderr, "==>\tfdClose(%p) rc %lx %s\n", (fd ? fd : NULL), (unsigned long)rc, fdbg(fd)));
515 static FD_t fdOpen(const char *path, int flags, mode_t mode)
520 fdno = open(path, flags, mode);
521 if (fdno < 0) return NULL;
522 if (fcntl(fdno, F_SETFD, FD_CLOEXEC)) {
529 DBGIO(fd, (stderr, "==>\tfdOpen(\"%s\",%x,0%o) %s\n", path, (unsigned)flags, (unsigned)mode, fdbg(fd)));
533 static const struct FDIO_s fdio_s = {
534 fdRead, fdWrite, fdSeek, fdClose, fdLink, fdFree, fdNew, fdFileno,
535 fdOpen, NULL, fdGetFp, NULL
537 static const FDIO_t fdio = &fdio_s ;
539 int ufdCopy(FD_t sfd, FD_t tfd)
547 rc = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd);
555 rc = Fwrite(buf, sizeof(buf[0]), itemsRead, tfd);
558 if (rc != itemsRead) {
563 itemsCopied += itemsRead;
566 DBGIO(sfd, (stderr, "++ copied %d bytes\n", itemsCopied));
572 * Deal with remote url's by fetching them with a helper application
573 * and treat as local file afterwards.
575 * - better error checking + reporting
576 * - curl & friends don't know about hkp://, transform to http?
579 static FD_t urlOpen(const char * url, int flags, mode_t mode)
583 int rc = 1; /* assume failure */
585 fd = rpmMkTempFile(NULL, &dest);
591 rc = urlGetFile(url, dest);
593 fd = fdOpen(dest, flags, mode);
603 static FD_t ufdOpen(const char * url, int flags, mode_t mode)
607 urltype urlType = urlPath(url, &path);
610 fprintf(stderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mode);
617 fd = urlOpen(url, flags, mode);
618 /* we're dealing with local file when urlOpen() returns */
619 urlType = URL_IS_UNKNOWN;
622 if ((flags & O_ACCMODE) == O_RDWR) {
625 fd = fdDup((flags & O_ACCMODE) == O_WRONLY ?
626 STDOUT_FILENO : STDIN_FILENO);
632 fd = fdOpen(path, flags, mode);
636 if (fd == NULL) return NULL;
639 fd->bytesRemain = -1;
640 fd->urlType = urlType;
642 if (Fileno(fd) < 0) {
646 DBGIO(fd, (stderr, "==>\tufdOpen(\"%s\",%x,0%o) %s\n", url, (unsigned)flags, (unsigned)mode, fdbg(fd)));
650 static const struct FDIO_s ufdio_s = {
651 fdRead, fdWrite, fdSeek, fdClose, fdLink, fdFree, fdNew, fdFileno,
652 ufdOpen, NULL, fdGetFp, NULL
654 static const FDIO_t ufdio = &ufdio_s ;
656 ssize_t timedRead(FD_t fd, void * bufptr, size_t length)
658 return ufdio->read(fd, bufptr, length);
661 /* =============================================================== */
662 /* Support for GZIP library.
668 static void * gzdFileno(FD_t fd)
670 return iotFileno(fd, gzdio);
674 FD_t gzdOpen(const char * path, const char * fmode)
678 if ((gzfile = gzopen(path, fmode)) == NULL)
681 fdPop(fd); fdPush(fd, gzdio, gzfile, -1);
683 DBGIO(fd, (stderr, "==>\tgzdOpen(\"%s\", \"%s\") fd %p %s\n", path, fmode, (fd ? fd : NULL), fdbg(fd)));
687 static FD_t gzdFdopen(void * cookie, const char *fmode)
689 FD_t fd = c2f(cookie);
693 if (fd == NULL || fmode == NULL) return NULL;
695 fdSetFdno(fd, -1); /* XXX skip the fdio close */
696 if (fdno < 0) return NULL;
697 gzfile = gzdopen(fdno, fmode);
698 if (gzfile == NULL) return NULL;
700 fdPush(fd, gzdio, gzfile, fdno); /* Push gzdio onto stack */
705 static int gzdFlush(FD_t fd)
708 gzfile = gzdFileno(fd);
709 if (gzfile == NULL) return -2;
710 return gzflush(gzfile, Z_SYNC_FLUSH); /* XXX W2DO? */
713 /* =============================================================== */
714 static ssize_t gzdRead(void * cookie, char * buf, size_t count)
716 FD_t fd = c2f(cookie);
720 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
722 gzfile = gzdFileno(fd);
723 if (gzfile == NULL) return -2; /* XXX can't happen */
725 fdstat_enter(fd, FDSTAT_READ);
726 rc = gzread(gzfile, buf, count);
727 DBGIO(fd, (stderr, "==>\tgzdRead(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
730 fd->errcookie = gzerror(gzfile, &zerror);
731 if (zerror == Z_ERRNO) {
732 fd->syserrno = errno;
733 fd->errcookie = strerror(fd->syserrno);
735 } else if (rc >= 0) {
736 fdstat_exit(fd, FDSTAT_READ, rc);
737 if (fd->digests && rc > 0) fdUpdateDigests(fd, (void *)buf, rc);
742 static ssize_t gzdWrite(void * cookie, const char * buf, size_t count)
744 FD_t fd = c2f(cookie);
748 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
750 if (fd->digests && count > 0) fdUpdateDigests(fd, (void *)buf, count);
752 gzfile = gzdFileno(fd);
753 if (gzfile == NULL) return -2; /* XXX can't happen */
755 fdstat_enter(fd, FDSTAT_WRITE);
756 rc = gzwrite(gzfile, (void *)buf, count);
757 DBGIO(fd, (stderr, "==>\tgzdWrite(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
760 fd->errcookie = gzerror(gzfile, &zerror);
761 if (zerror == Z_ERRNO) {
762 fd->syserrno = errno;
763 fd->errcookie = strerror(fd->syserrno);
766 fdstat_exit(fd, FDSTAT_WRITE, rc);
771 /* XXX zlib-1.0.4 has not */
772 static int gzdSeek(void * cookie, _libio_pos_t pos, int whence)
774 #ifdef USE_COOKIE_SEEK_POINTER
775 _IO_off64_t p = *pos;
781 FD_t fd = c2f(cookie);
784 if (fd == NULL) return -2;
785 assert(fd->bytesRemain == -1); /* XXX FIXME */
787 gzfile = gzdFileno(fd);
788 if (gzfile == NULL) return -2; /* XXX can't happen */
790 fdstat_enter(fd, FDSTAT_SEEK);
791 rc = gzseek(gzfile, p, whence);
792 DBGIO(fd, (stderr, "==>\tgzdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd)));
795 fd->errcookie = gzerror(gzfile, &zerror);
796 if (zerror == Z_ERRNO) {
797 fd->syserrno = errno;
798 fd->errcookie = strerror(fd->syserrno);
800 } else if (rc >= 0) {
801 fdstat_exit(fd, FDSTAT_SEEK, rc);
809 static int gzdClose( void * cookie)
811 FD_t fd = c2f(cookie);
815 gzfile = gzdFileno(fd);
816 if (gzfile == NULL) return -2; /* XXX can't happen */
818 fdstat_enter(fd, FDSTAT_CLOSE);
819 rc = gzclose(gzfile);
821 /* XXX TODO: preserve fd if errors */
824 DBGIO(fd, (stderr, "==>\tgzdClose(%p) zerror %d %s\n", cookie, rc, fdbg(fd)));
826 fd->errcookie = "gzclose error";
828 fd->syserrno = errno;
829 fd->errcookie = strerror(fd->syserrno);
831 } else if (rc >= 0) {
832 fdstat_exit(fd, FDSTAT_CLOSE, rc);
836 DBGIO(fd, (stderr, "==>\tgzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
838 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "GZDIO", stderr);
844 static const struct FDIO_s gzdio_s = {
845 gzdRead, gzdWrite, gzdSeek, gzdClose, fdLink, fdFree, fdNew, fdFileno,
846 NULL, gzdOpen, gzdFileno, gzdFlush
848 static const FDIO_t gzdio = &gzdio_s ;
850 #endif /* HAVE_ZLIB_H */
852 /* =============================================================== */
853 /* Support for BZIP2 library.
860 # define bzopen BZ2_bzopen
861 # define bzclose BZ2_bzclose
862 # define bzdopen BZ2_bzdopen
863 # define bzerror BZ2_bzerror
864 # define bzflush BZ2_bzflush
865 # define bzread BZ2_bzread
866 # define bzwrite BZ2_bzwrite
867 #endif /* HAVE_BZ2_1_0 */
869 static void * bzdFileno(FD_t fd)
871 return iotFileno(fd, bzdio);
874 static FD_t bzdOpen(const char * path, const char * mode)
878 if ((bzfile = bzopen(path, mode)) == NULL)
881 fdPop(fd); fdPush(fd, bzdio, bzfile, -1);
885 static FD_t bzdFdopen(void * cookie, const char * fmode)
887 FD_t fd = c2f(cookie);
891 if (fd == NULL || fmode == NULL) return NULL;
893 fdSetFdno(fd, -1); /* XXX skip the fdio close */
894 if (fdno < 0) return NULL;
895 bzfile = bzdopen(fdno, fmode);
896 if (bzfile == NULL) return NULL;
898 fdPush(fd, bzdio, bzfile, fdno); /* Push bzdio onto stack */
903 static int bzdFlush(FD_t fd)
905 return bzflush(bzdFileno(fd));
908 /* =============================================================== */
909 static ssize_t bzdRead(void * cookie, char * buf, size_t count)
911 FD_t fd = c2f(cookie);
915 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
916 bzfile = bzdFileno(fd);
917 fdstat_enter(fd, FDSTAT_READ);
919 rc = bzread(bzfile, buf, count);
923 fd->errcookie = bzerror(bzfile, &zerror);
924 } else if (rc >= 0) {
925 fdstat_exit(fd, FDSTAT_READ, rc);
926 if (fd->digests && rc > 0) fdUpdateDigests(fd, (void *)buf, rc);
931 static ssize_t bzdWrite(void * cookie, const char * buf, size_t count)
933 FD_t fd = c2f(cookie);
937 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
939 if (fd->digests && count > 0) fdUpdateDigests(fd, (void *)buf, count);
941 bzfile = bzdFileno(fd);
942 fdstat_enter(fd, FDSTAT_WRITE);
943 rc = bzwrite(bzfile, (void *)buf, count);
946 fd->errcookie = bzerror(bzfile, &zerror);
948 fdstat_exit(fd, FDSTAT_WRITE, rc);
953 static int bzdClose( void * cookie)
955 FD_t fd = c2f(cookie);
959 bzfile = bzdFileno(fd);
961 if (bzfile == NULL) return -2;
962 fdstat_enter(fd, FDSTAT_CLOSE);
965 rc = 0; /* XXX FIXME */
967 /* XXX TODO: preserve fd if errors */
972 fd->errcookie = bzerror(bzfile, &zerror);
973 } else if (rc >= 0) {
974 fdstat_exit(fd, FDSTAT_CLOSE, rc);
978 DBGIO(fd, (stderr, "==>\tbzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
980 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "BZDIO", stderr);
986 static const struct FDIO_s bzdio_s = {
987 bzdRead, bzdWrite, fdSeekNot, bzdClose, fdLink, fdFree, fdNew, fdFileno,
988 NULL, bzdOpen, bzdFileno, bzdFlush
990 static const FDIO_t bzdio = &bzdio_s ;
992 #endif /* HAVE_BZLIB_H */
994 /* =============================================================== */
995 static const char * getFdErrstr (FD_t fd)
997 const char *errstr = NULL;
1000 if (fdGetIo(fd) == gzdio) {
1001 errstr = fd->errcookie;
1003 #endif /* HAVE_ZLIB_H */
1006 if (fdGetIo(fd) == bzdio) {
1007 errstr = fd->errcookie;
1009 #endif /* HAVE_BZLIB_H */
1011 if (fdGetIo(fd) == xzdio || fdGetIo(fd) == lzdio) {
1012 errstr = fd->errcookie;
1014 #endif /* HAVE_LZMA_H */
1016 errstr = (fd->syserrno ? strerror(fd->syserrno) : "");
1022 /* =============================================================== */
1023 /* Support for LZMA library.
1028 #include <sys/types.h>
1029 #include <inttypes.h>
1032 #define kBufferSize (1 << 15)
1034 typedef struct lzfile {
1036 uint8_t buf[kBufferSize];
1047 static LZFILE *lzopen_internal(const char *path, const char *mode, int fd, int xz)
1049 int level = 7; /* Use XZ's default compression level if unspecified */
1054 lzma_stream init_strm = LZMA_STREAM_INIT;
1056 for (; *mode; mode++) {
1059 else if (*mode == 'r')
1061 else if (*mode >= '1' && *mode <= '9')
1062 level = *mode - '0';
1065 fp = fdopen(fd, encoding ? "w" : "r");
1067 fp = fopen(path, encoding ? "w" : "r");
1070 lzfile = calloc(1, sizeof(*lzfile));
1077 lzfile->encoding = encoding;
1079 lzfile->strm = init_strm;
1082 ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
1084 lzma_options_lzma options;
1085 lzma_lzma_preset(&options, level);
1086 ret = lzma_alone_encoder(&lzfile->strm, &options);
1088 } else { /* lzma_easy_decoder_memusage(level) is not ready yet, use hardcoded limit for now */
1089 ret = lzma_auto_decoder(&lzfile->strm, 100<<20, 0);
1091 if (ret != LZMA_OK) {
1099 static LZFILE *xzopen(const char *path, const char *mode)
1101 return lzopen_internal(path, mode, -1, 1);
1104 static LZFILE *xzdopen(int fd, const char *mode)
1108 return lzopen_internal(0, mode, fd, 1);
1111 static LZFILE *lzopen(const char *path, const char *mode)
1113 return lzopen_internal(path, mode, -1, 0);
1116 static LZFILE *lzdopen(int fd, const char *mode)
1120 return lzopen_internal(0, mode, fd, 0);
1123 static int lzflush(LZFILE *lzfile)
1125 return fflush(lzfile->file);
1128 static int lzclose(LZFILE *lzfile)
1136 if (lzfile->encoding) {
1138 lzfile->strm.avail_out = kBufferSize;
1139 lzfile->strm.next_out = lzfile->buf;
1140 ret = lzma_code(&lzfile->strm, LZMA_FINISH);
1141 if (ret != LZMA_OK && ret != LZMA_STREAM_END)
1143 n = kBufferSize - lzfile->strm.avail_out;
1144 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
1146 if (ret == LZMA_STREAM_END)
1150 lzma_end(&lzfile->strm);
1151 rc = fclose(lzfile->file);
1156 static ssize_t lzread(LZFILE *lzfile, void *buf, size_t len)
1161 if (!lzfile || lzfile->encoding)
1165 lzfile->strm.next_out = buf;
1166 lzfile->strm.avail_out = len;
1168 if (!lzfile->strm.avail_in) {
1169 lzfile->strm.next_in = lzfile->buf;
1170 lzfile->strm.avail_in = fread(lzfile->buf, 1, kBufferSize, lzfile->file);
1171 if (!lzfile->strm.avail_in)
1174 ret = lzma_code(&lzfile->strm, LZMA_RUN);
1175 if (ret == LZMA_STREAM_END) {
1177 return len - lzfile->strm.avail_out;
1181 if (!lzfile->strm.avail_out)
1188 static ssize_t lzwrite(LZFILE *lzfile, void *buf, size_t len)
1192 if (!lzfile || !lzfile->encoding)
1196 lzfile->strm.next_in = buf;
1197 lzfile->strm.avail_in = len;
1199 lzfile->strm.next_out = lzfile->buf;
1200 lzfile->strm.avail_out = kBufferSize;
1201 ret = lzma_code(&lzfile->strm, LZMA_RUN);
1204 n = kBufferSize - lzfile->strm.avail_out;
1205 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
1207 if (!lzfile->strm.avail_in)
1212 /* =============================================================== */
1214 static void * lzdFileno(FD_t fd)
1221 for (int i = fd->nfps; i >= 0; i--) {
1222 FDSTACK_t * fps = &fd->fps[i];
1223 if (fps->io != xzdio && fps->io != lzdio)
1231 static FD_t xzdOpen(const char * path, const char * mode)
1235 if ((lzfile = xzopen(path, mode)) == NULL)
1238 fdPop(fd); fdPush(fd, xzdio, lzfile, -1);
1242 static FD_t xzdFdopen(void * cookie, const char * fmode)
1244 FD_t fd = c2f(cookie);
1248 if (fd == NULL || fmode == NULL) return NULL;
1249 fdno = fdFileno(fd);
1250 fdSetFdno(fd, -1); /* XXX skip the fdio close */
1251 if (fdno < 0) return NULL;
1252 lzfile = xzdopen(fdno, fmode);
1253 if (lzfile == NULL) return NULL;
1254 fdPush(fd, xzdio, lzfile, fdno);
1258 static FD_t lzdOpen(const char * path, const char * mode)
1262 if ((lzfile = lzopen(path, mode)) == NULL)
1265 fdPop(fd); fdPush(fd, xzdio, lzfile, -1);
1269 static FD_t lzdFdopen(void * cookie, const char * fmode)
1271 FD_t fd = c2f(cookie);
1275 if (fd == NULL || fmode == NULL) return NULL;
1276 fdno = fdFileno(fd);
1277 fdSetFdno(fd, -1); /* XXX skip the fdio close */
1278 if (fdno < 0) return NULL;
1279 lzfile = lzdopen(fdno, fmode);
1280 if (lzfile == NULL) return NULL;
1281 fdPush(fd, xzdio, lzfile, fdno);
1285 static int lzdFlush(FD_t fd)
1287 return lzflush(lzdFileno(fd));
1290 /* =============================================================== */
1291 static ssize_t lzdRead(void * cookie, char * buf, size_t count)
1293 FD_t fd = c2f(cookie);
1297 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
1298 lzfile = lzdFileno(fd);
1299 fdstat_enter(fd, FDSTAT_READ);
1301 rc = lzread(lzfile, buf, count);
1303 fd->errcookie = "Lzma: decoding error";
1304 } else if (rc >= 0) {
1305 fdstat_exit(fd, FDSTAT_READ, rc);
1306 if (fd->digests && rc > 0) fdUpdateDigests(fd, (void *)buf, rc);
1311 static ssize_t lzdWrite(void * cookie, const char * buf, size_t count)
1313 FD_t fd = c2f(cookie);
1317 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
1319 if (fd->digests && count > 0) fdUpdateDigests(fd, (void *)buf, count);
1321 lzfile = lzdFileno(fd);
1323 fdstat_enter(fd, FDSTAT_WRITE);
1324 rc = lzwrite(lzfile, (void *)buf, count);
1326 fd->errcookie = "Lzma: encoding error";
1327 } else if (rc > 0) {
1328 fdstat_exit(fd, FDSTAT_WRITE, rc);
1333 static int lzdClose(void * cookie)
1335 FD_t fd = c2f(cookie);
1339 lzfile = lzdFileno(fd);
1341 if (lzfile == NULL) return -2;
1342 fdstat_enter(fd, FDSTAT_CLOSE);
1343 rc = lzclose(lzfile);
1345 /* XXX TODO: preserve fd if errors */
1349 fd->errcookie = strerror(ferror(lzfile->file));
1350 } else if (rc >= 0) {
1351 fdstat_exit(fd, FDSTAT_CLOSE, rc);
1355 DBGIO(fd, (stderr, "==>\tlzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
1357 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "XZDIO", stderr);
1363 static struct FDIO_s xzdio_s = {
1364 lzdRead, lzdWrite, fdSeekNot, lzdClose, NULL, NULL, NULL, fdFileno,
1365 NULL, xzdOpen, lzdFileno, lzdFlush
1367 static const FDIO_t xzdio = &xzdio_s;
1369 static struct FDIO_s lzdio_s = {
1370 lzdRead, lzdWrite, fdSeekNot, lzdClose, NULL, NULL, NULL, fdFileno,
1371 NULL, lzdOpen, lzdFileno, lzdFlush
1373 static const FDIO_t lzdio = &lzdio_s;
1375 #endif /* HAVE_LZMA_H */
1377 /* =============================================================== */
1379 const char *Fstrerror(FD_t fd)
1382 return (errno ? strerror(errno) : "");
1383 return getFdErrstr(fd);
1386 #define FDIOVEC(_fd, _vec) \
1387 ((fdGetIo(_fd) && fdGetIo(_fd)->_vec) ? fdGetIo(_fd)->_vec : NULL)
1389 ssize_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd) {
1390 fdio_read_function_t _read;
1396 if (fdGetIo(fd) == fpio) {
1397 rc = fread(buf, size, nmemb, fdGetFILE(fd));
1401 _read = FDIOVEC(fd, read);
1403 rc = (_read ? (*_read) (fd, buf, size * nmemb) : -2);
1407 ssize_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
1409 fdio_write_function_t _write;
1415 if (fdGetIo(fd) == fpio) {
1416 rc = fwrite(buf, size, nmemb, fdGetFILE(fd));
1420 _write = FDIOVEC(fd, write);
1422 rc = (_write ? _write(fd, buf, size * nmemb) : -2);
1426 int Fseek(FD_t fd, _libio_off_t offset, int whence) {
1427 fdio_seek_function_t _seek;
1428 #ifdef USE_COOKIE_SEEK_POINTER
1429 _IO_off64_t o64 = offset;
1430 _libio_pos_t pos = &o64;
1432 _libio_pos_t pos = offset;
1440 if (fdGetIo(fd) == fpio) {
1444 rc = fseek(fp, offset, whence);
1448 _seek = FDIOVEC(fd, seek);
1450 rc = (_seek ? _seek(fd, pos, whence) : -2);
1462 while (fd->nfps >= 0) {
1463 FDSTACK_t * fps = &fd->fps[fd->nfps];
1465 if (fps->io == fpio) {
1478 fdio_close_function_t _close = FDIOVEC(fd, close);
1479 rc = _close ? _close(fd) : -2;
1492 * Convert stdio fmode to open(2) mode, filtering out zlib/bzlib flags.
1493 * returns stdio[0] = NUL on error.
1495 * - gzopen: [0-9] is compression level
1496 * - gzopen: 'f' is filtered (Z_FILTERED)
1497 * - gzopen: 'h' is Huffman encoding (Z_HUFFMAN_ONLY)
1498 * - bzopen: [1-9] is block size (modulo 100K)
1499 * - bzopen: 's' is smallmode
1500 * - HACK: '.' terminates, rest is type of I/O
1502 static void cvtfmode (const char *m,
1503 char *stdio, size_t nstdio,
1504 char *other, size_t nother,
1505 const char **end, int * f)
1512 flags |= O_WRONLY | O_CREAT | O_APPEND;
1513 if (--nstdio > 0) *stdio++ = *m;
1516 flags |= O_WRONLY | O_CREAT | O_TRUNC;
1517 if (--nstdio > 0) *stdio++ = *m;
1521 if (--nstdio > 0) *stdio++ = *m;
1530 while ((c = *m++) != '\0') {
1535 flags &= ~(O_RDONLY|O_WRONLY);
1537 if (--nstdio > 0) *stdio++ = c;
1541 if (--nstdio > 0) *stdio++ = c;
1546 if (--nstdio > 0) *stdio++ = c;
1550 if (--nother > 0) *other++ = c;
1557 *stdio = *other = '\0';
1559 *end = (*m != '\0' ? m : NULL);
1565 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0
1566 /* XXX retrofit glibc-2.1.x typedef on glibc-2.0.x systems */
1567 typedef _IO_cookie_io_functions_t cookie_io_functions_t;
1571 FD_t Fdopen(FD_t ofd, const char *fmode)
1573 char stdio[20], other[20], zstdio[20];
1574 const char *end = NULL;
1579 fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
1581 if (fd == NULL || fmode == NULL)
1584 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL);
1585 if (stdio[0] == '\0')
1588 strncat(zstdio, stdio, sizeof(zstdio) - strlen(zstdio));
1589 strncat(zstdio, other, sizeof(zstdio) - strlen(zstdio));
1591 if (end == NULL && other[0] == '\0')
1595 if (rstreq(end, "fdio")) {
1598 } else if (rstreq(end, "gzdio") || rstreq(end, "gzip")) {
1600 fd = gzdFdopen(fd, zstdio);
1603 } else if (rstreq(end, "bzdio") || rstreq(end, "bzip2")) {
1605 fd = bzdFdopen(fd, zstdio);
1608 } else if (rstreq(end, "xzdio") || rstreq(end, "xz")) {
1610 fd = xzdFdopen(fd, zstdio);
1611 } else if (rstreq(end, "lzdio") || rstreq(end, "lzma")) {
1613 fd = lzdFdopen(fd, zstdio);
1615 } else if (rstreq(end, "ufdio")) {
1617 } else if (rstreq(end, "fpio")) {
1620 int fdno = Fileno(fd);
1621 FILE * fp = fdopen(fdno, stdio);
1623 fprintf(stderr, "*** Fdopen fpio fp %p\n", (void *)fp);
1626 /* XXX gzdio/bzdio use fp for private data */
1627 if (fdGetFp(fd) == NULL)
1629 fdPush(fd, fpio, fp, fdno); /* Push fpio onto stack */
1632 } else if (other[0] != '\0') {
1633 for (end = other; *end && strchr("0123456789fh", *end); end++)
1637 fd = gzdFdopen(fd, zstdio);
1647 { cookie_io_functions_t ciof;
1648 ciof.read = iof->read;
1649 ciof.write = iof->write;
1650 ciof.seek = iof->seek;
1651 ciof.close = iof->close;
1652 fp = fopencookie(fd, stdio, ciof);
1653 DBGIO(fd, (stderr, "==> fopencookie(%p,\"%s\",*%p) returns fp %p\n", fd, stdio, iof, fp));
1658 /* XXX gzdio/bzdio use fp for private data */
1659 if (fdGetFp(fd) == NULL)
1661 fdPush(fd, fpio, fp, fileno(fp)); /* Push fpio onto stack */
1666 DBGIO(fd, (stderr, "==> Fdopen(%p,\"%s\") returns fd %p %s\n", ofd, fmode, (fd ? fd : NULL), fdbg(fd)));
1670 FD_t Fopen(const char *path, const char *fmode)
1672 char stdio[20], other[20];
1673 const char *end = NULL;
1674 mode_t perms = 0666;
1678 if (path == NULL || fmode == NULL)
1682 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, &flags);
1683 if (stdio[0] == '\0')
1686 if (end == NULL || rstreq(end, "fdio")) {
1688 fprintf(stderr, "*** Fopen fdio path %s fmode %s\n", path, fmode);
1689 fd = fdOpen(path, flags, perms);
1690 if (fdFileno(fd) < 0) {
1691 if (fd) (void) fdClose(fd);
1695 /* XXX gzdio and bzdio here too */
1697 switch (urlIsURL(path)) {
1704 case URL_IS_UNKNOWN:
1706 fprintf(stderr, "*** Fopen ufdio path %s fmode %s\n", path, fmode);
1707 fd = ufdOpen(path, flags, perms);
1708 if (fd == NULL || !(fdFileno(fd) >= 0))
1713 fprintf(stderr, "*** Fopen WTFO path %s fmode %s\n", path, fmode);
1721 fd = Fdopen(fd, fmode);
1728 if (fd == NULL) return -1;
1729 if (fdGetIo(fd) == fpio)
1730 return fflush(fdGetFILE(fd));
1734 if (vh && fdGetIo(fd) == gzdio)
1735 return gzdFlush(vh);
1738 if (vh && fdGetIo(fd) == bzdio)
1739 return bzdFlush(vh);
1742 if (vh && (fdGetIo(fd) == xzdio || fdGetIo(fd) == lzdio))
1743 return lzdFlush(vh);
1745 /* FIXME: If we get here, something went wrong above */
1749 off_t Ftell(FD_t fd)
1752 off_t pos = -2; /* assume not implemented */
1754 if (fd == NULL) return -1;
1756 /* this wont work correctly for compressed types */
1757 if (iot == fpio || iot == fdio || iot == ufdio) {
1758 pos = lseek(Fileno(fd), 0, SEEK_CUR);
1768 if (fd == NULL) return -1;
1769 for (i = fd->nfps; rc == 0 && i >= 0; i--) {
1770 FDSTACK_t * fps = &fd->fps[i];
1773 if (fps->io == fpio) {
1774 ec = ferror(fdGetFILE(fd));
1776 } else if (fps->io == gzdio) {
1777 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
1778 i--; /* XXX fdio under gzdio always has fdno == -1 */
1781 } else if (fps->io == bzdio) {
1782 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
1783 i--; /* XXX fdio under bzdio always has fdno == -1 */
1786 } else if (fps->io == xzdio || fps->io == lzdio) {
1787 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
1788 i--; /* XXX fdio under xzdio/lzdio always has fdno == -1 */
1791 /* XXX need to check ufdio/gzdio/bzdio/fdio errors correctly. */
1792 ec = (fdFileno(fd) < 0 ? -1 : 0);
1798 DBGIO(fd, (stderr, "==> Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd)));
1806 if (fd == NULL) return -1;
1807 for (i = fd->nfps ; rc == -1 && i >= 0; i--) {
1808 rc = fd->fps[i].fdno;
1811 DBGIO(fd, (stderr, "==> Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, fdbg(fd)));
1815 /* XXX this is naive */
1816 int Fcntl(FD_t fd, int op, void *lip)
1818 return fcntl(Fileno(fd), op, lip);
1821 rpmop fdOp(FD_t fd, fdOpX opx)
1825 if (fd != NULL && fd->stats != NULL && opx >= 0 && opx < FDSTAT_MAX)
1826 op = fd->stats->ops + opx;
1830 int rpmioSlurp(const char * fn, uint8_t ** bp, ssize_t * blenp)
1832 static const ssize_t blenmax = (32 * BUFSIZ);
1839 fd = Fopen(fn, "r.ufdio");
1840 if (fd == NULL || Ferror(fd)) {
1846 blen = (size >= 0 ? size : blenmax);
1849 b = xmalloc(blen+1);
1851 nb = Fread(b, sizeof(*b), blen, fd);
1852 if (Ferror(fd) || (size > 0 && nb != blen)) {
1856 if (blen == blenmax && nb < blen) {
1858 b = xrealloc(b, blen+1);
1864 if (fd) (void) Fclose(fd);
1873 else if (b) free(b);
1875 if (blenp) *blenp = blen;
1880 static const struct FDIO_s fpio_s = {
1881 fdRead, fdWrite, fdSeek, fdClose, fdLink, fdFree, fdNew, fdFileno,
1882 ufdOpen, NULL, fdGetFp, NULL
1884 static const FDIO_t fpio = &fpio_s ;
1886 void fdInitDigest(FD_t fd, pgpHashAlgo hashalgo, int flags)
1888 if (fd->digests == NULL) {
1889 fd->digests = rpmDigestBundleNew();
1891 fdstat_enter(fd, FDSTAT_DIGEST);
1892 rpmDigestBundleAdd(fd->digests, hashalgo, flags);
1893 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);
1896 static void fdUpdateDigests(FD_t fd, const unsigned char * buf, size_t buflen)
1898 if (fd && fd->digests) {
1899 fdstat_enter(fd, FDSTAT_DIGEST);
1900 rpmDigestBundleUpdate(fd->digests, buf, buflen);
1901 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) buflen);
1905 void fdFiniDigest(FD_t fd, pgpHashAlgo hashalgo,
1910 if (fd && fd->digests) {
1911 fdstat_enter(fd, FDSTAT_DIGEST);
1912 rpmDigestBundleFinal(fd->digests, hashalgo, datap, lenp, asAscii);
1913 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);