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 typedef struct _FDSTACK_s {
26 * Cumulative statistics for a descriptor.
29 struct rpmop_s ops[FDSTAT_MAX]; /*!< Cumulative statistics. */
33 * The FD_t File Handle data structure.
38 #define RPMIO_DEBUG_IO 0x40000000
40 #define FDMAGIC 0x04463138
43 int urlType; /* ufdio: */
45 int syserrno; /* last system errno encountered */
46 const char *errcookie; /* gzdio/bzdio/ufdio/xzdio: */
48 char *descr; /* file name (or other description) */
49 FDSTAT_t stats; /* I/O statistics */
51 rpmDigestBundle digests;
54 #define DBG(_f, _m, _x) \
56 if ((_rpmio_debug | ((_f) ? ((FD_t)(_f))->flags : 0)) & (_m)) fprintf _x \
58 #define DBGIO(_f, _x) DBG((_f), RPMIO_DEBUG_IO, _x)
60 static FDIO_t fdGetIo(FD_t fd)
62 return (fd != NULL) ? fd->fps[fd->nfps].io : NULL;
65 static void fdSetIo(FD_t fd, FDIO_t io)
68 fd->fps[fd->nfps].io = io;
71 static void * fdGetFp(FD_t fd)
73 return (fd != NULL) ? fd->fps[fd->nfps].fp : NULL;
76 static void fdSetFp(FD_t fd, void * fp)
79 fd->fps[fd->nfps].fp = fp;
82 static void fdSetFdno(FD_t fd, int fdno)
85 fd->fps[fd->nfps].fdno = fdno;
88 static void fdPush(FD_t fd, FDIO_t io, void * fp, int fdno)
90 if (fd == NULL || fd->nfps >= (sizeof(fd->fps)/sizeof(fd->fps[0]) - 1))
98 static void fdPop(FD_t fd)
100 if (fd == NULL || fd->nfps < 0) return;
107 void fdSetBundle(FD_t fd, rpmDigestBundle bundle)
110 fd->digests = bundle;
113 rpmDigestBundle fdGetBundle(FD_t fd)
115 return (fd != NULL) ? fd->digests : NULL;
118 static void * iotFileno(FD_t fd, FDIO_t iot)
125 for (int i = fd->nfps; i >= 0; i--) {
126 FDSTACK_t * fps = &fd->fps[i];
137 * \name RPMIO Vectors.
139 typedef ssize_t (*fdio_read_function_t) (FD_t fd, void *buf, size_t nbytes);
140 typedef ssize_t (*fdio_write_function_t) (FD_t fd, const void *buf, size_t nbytes);
141 typedef int (*fdio_seek_function_t) (FD_t fd, off_t pos, int whence);
142 typedef int (*fdio_close_function_t) (FD_t fd);
143 typedef FD_t (*fdio_ref_function_t) (FD_t fd);
144 typedef FD_t (*fdio_deref_function_t) (FD_t fd);
145 typedef FD_t (*fdio_new_function_t) (const char *descr);
146 typedef int (*fdio_fileno_function_t) (FD_t fd);
147 typedef FD_t (*fdio_open_function_t) (const char * path, int flags, mode_t mode);
148 typedef FD_t (*fdio_fopen_function_t) (const char * path, const char * fmode);
149 typedef void * (*fdio_ffileno_function_t) (FD_t fd);
150 typedef int (*fdio_fflush_function_t) (FD_t fd);
151 typedef long (*fdio_ftell_function_t) (FD_t);
154 fdio_read_function_t read;
155 fdio_write_function_t write;
156 fdio_seek_function_t seek;
157 fdio_close_function_t close;
159 fdio_ref_function_t _fdref;
160 fdio_deref_function_t _fdderef;
161 fdio_new_function_t _fdnew;
162 fdio_fileno_function_t _fileno;
164 fdio_open_function_t _open;
165 fdio_fopen_function_t _fopen;
166 fdio_ffileno_function_t _ffileno;
167 fdio_fflush_function_t _fflush;
168 fdio_ftell_function_t _ftell;
172 static const FDIO_t fdio;
173 static const FDIO_t ufdio;
174 static const FDIO_t gzdio;
175 static const FDIO_t bzdio;
176 static const FDIO_t xzdio;
177 static const FDIO_t lzdio;
180 * Update digest(s) attached to fd.
182 static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen);
183 static FD_t fdNew(const char *descr);
186 int _rpmio_debug = 0;
188 /* =============================================================== */
190 static const char * fdbg(FD_t fd)
192 static char buf[BUFSIZ];
201 for (i = fd->nfps; i >= 0; i--) {
202 FDSTACK_t * fps = &fd->fps[i];
207 if (fps->io == fdio) {
208 sprintf(be, "FD %d fp %p", fps->fdno, fps->fp);
209 } else if (fps->io == ufdio) {
210 sprintf(be, "UFD %d fp %p", fps->fdno, fps->fp);
211 } else if (fps->io == gzdio) {
212 sprintf(be, "GZD %p fdno %d", fps->fp, fps->fdno);
214 } else if (fps->io == bzdio) {
215 sprintf(be, "BZD %p fdno %d", fps->fp, fps->fdno);
218 } else if (fps->io == xzdio) {
219 sprintf(be, "XZD %p fdno %d", fps->fp, fps->fdno);
220 } else if (fps->io == lzdio) {
221 sprintf(be, "LZD %p fdno %d", fps->fp, fps->fdno);
224 sprintf(be, "??? io %p fp %p fdno %d ???",
225 fps->io, fps->fp, fps->fdno);
233 static void fdstat_enter(FD_t fd, fdOpX opx)
235 if (fd->stats != NULL)
236 (void) rpmswEnter(fdOp(fd, opx), (ssize_t) 0);
239 static void fdstat_exit(FD_t fd, fdOpX opx, ssize_t rc)
242 fd->syserrno = errno;
243 if (fd->stats != NULL)
244 (void) rpmswExit(fdOp(fd, opx), rc);
247 static void fdstat_print(FD_t fd, const char * msg, FILE * fp)
249 static const int usec_scale = (1000*1000);
252 if (fd == NULL || fd->stats == NULL) return;
253 for (opx = 0; opx < 4; opx++) {
254 rpmop op = &fd->stats->ops[opx];
255 if (op->count <= 0) continue;
258 if (msg) fprintf(fp, "%s:", msg);
259 fprintf(fp, "%8d reads, %8ld total bytes in %d.%06d secs\n",
260 op->count, (long)op->bytes,
261 (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
264 if (msg) fprintf(fp, "%s:", msg);
265 fprintf(fp, "%8d writes, %8ld total bytes in %d.%06d secs\n",
266 op->count, (long)op->bytes,
267 (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
277 off_t fdSize(FD_t fd)
282 if (fd != NULL && fstat(Fileno(fd), &sb) == 0)
292 if ((nfdno = dup(fdno)) < 0)
295 fdSetFdno(fd, nfdno);
296 DBGIO(fd, (stderr, "==> fdDup(%d) fd %p %s\n", fdno, (fd ? fd : NULL), fdbg(fd)));
300 /* Regular fd doesn't have fflush() equivalent but its not an error either */
301 static int fdFlush(FD_t fd)
306 static int fdFileno(FD_t fd)
308 return (fd != NULL) ? fd->fps[0].fdno : -2;
311 const char * Fdescr(FD_t fd)
316 /* Lazy lookup if description is not set (eg dupped fd) */
317 if (fd->descr == NULL) {
318 int fdno = fd->fps[fd->nfps].fdno;
319 #if defined(__linux__)
320 /* Grab the path from /proc if we can */
321 char *procpath = NULL;
325 rasprintf(&procpath, "/proc/self/fd/%d", fdno);
326 llen = readlink(procpath, buf, sizeof(buf)-1);
331 /* Real paths in /proc are always absolute */
333 fd->descr = xstrdup(buf);
335 fd->descr = rstrscat(NULL, "[", buf, "]", NULL);
338 /* Still no description, base it on fdno which is always there */
339 if (fd->descr == NULL)
340 rasprintf(&(fd->descr), "[fd %d]", fdno);
352 FD_t fdFree( FD_t fd)
357 fd->stats = _free(fd->stats);
359 fd->digests = rpmDigestBundleFree(fd->digests);
367 FD_t fdNew(const char *descr)
369 FD_t fd = xcalloc(1, sizeof(*fd));
370 if (fd == NULL) /* XXX xmalloc never returns NULL */
375 fd->urlType = URL_IS_UNKNOWN;
378 memset(fd->fps, 0, sizeof(fd->fps));
380 fd->fps[0].io = fdio;
381 fd->fps[0].fp = NULL;
382 fd->fps[0].fdno = -1;
385 fd->errcookie = NULL;
386 fd->stats = xcalloc(1, sizeof(*fd->stats));
388 fd->descr = descr ? xstrdup(descr) : NULL;
393 static ssize_t fdRead(FD_t fd, void * buf, size_t count)
395 return read(fdFileno(fd), buf, count);
398 static ssize_t fdWrite(FD_t fd, const void * buf, size_t count)
403 return write(fdFileno(fd), buf, count);
406 static int fdSeek(FD_t fd, off_t pos, int whence)
408 return lseek(fdFileno(fd), pos, whence);
411 static int fdClose(FD_t fd)
416 if (fd == NULL) return -2;
421 rc = ((fdno >= 0) ? close(fdno) : -2);
427 static FD_t fdOpen(const char *path, int flags, mode_t mode)
432 fdno = open(path, flags, mode);
433 if (fdno < 0) return NULL;
434 if (fcntl(fdno, F_SETFD, FD_CLOEXEC)) {
444 static long fdTell(FD_t fd)
446 return lseek(Fileno(fd), 0, SEEK_CUR);
449 static const struct FDIO_s fdio_s = {
450 fdRead, fdWrite, fdSeek, fdClose, fdLink, fdFree, fdNew, fdFileno,
451 fdOpen, NULL, fdGetFp, fdFlush, fdTell
453 static const FDIO_t fdio = &fdio_s ;
455 int ufdCopy(FD_t sfd, FD_t tfd)
463 rc = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd);
471 rc = Fwrite(buf, sizeof(buf[0]), itemsRead, tfd);
474 if (rc != itemsRead) {
479 itemsCopied += itemsRead;
482 DBGIO(sfd, (stderr, "++ copied %d bytes\n", itemsCopied));
488 * Deal with remote url's by fetching them with a helper application
489 * and treat as local file afterwards.
491 * - better error checking + reporting
492 * - curl & friends don't know about hkp://, transform to http?
495 static FD_t urlOpen(const char * url, int flags, mode_t mode)
499 int rc = 1; /* assume failure */
501 fd = rpmMkTempFile(NULL, &dest);
507 rc = urlGetFile(url, dest);
509 fd = fdOpen(dest, flags, mode);
519 static FD_t ufdOpen(const char * url, int flags, mode_t mode)
523 urltype urlType = urlPath(url, &path);
526 fprintf(stderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mode);
533 fd = urlOpen(url, flags, mode);
534 /* we're dealing with local file when urlOpen() returns */
535 urlType = URL_IS_UNKNOWN;
538 if ((flags & O_ACCMODE) == O_RDWR) {
541 fd = fdDup((flags & O_ACCMODE) == O_WRONLY ?
542 STDOUT_FILENO : STDIN_FILENO);
548 fd = fdOpen(path, flags, mode);
552 if (fd == NULL) return NULL;
555 fd->urlType = urlType;
557 if (Fileno(fd) < 0) {
564 static const struct FDIO_s ufdio_s = {
565 fdRead, fdWrite, fdSeek, fdClose, fdLink, fdFree, fdNew, fdFileno,
566 ufdOpen, NULL, fdGetFp, fdFlush, fdTell
568 static const FDIO_t ufdio = &ufdio_s ;
570 /* =============================================================== */
571 /* Support for GZIP library. */
574 static void * gzdFileno(FD_t fd)
576 return iotFileno(fd, gzdio);
580 FD_t gzdOpen(const char * path, const char * fmode)
584 if ((gzfile = gzopen(path, fmode)) == NULL)
587 fdPop(fd); fdPush(fd, gzdio, gzfile, -1);
592 static FD_t gzdFdopen(FD_t fd, const char *fmode)
597 if (fd == NULL || fmode == NULL) return NULL;
599 fdSetFdno(fd, -1); /* XXX skip the fdio close */
600 if (fdno < 0) return NULL;
601 gzfile = gzdopen(fdno, fmode);
602 if (gzfile == NULL) return NULL;
604 fdPush(fd, gzdio, gzfile, fdno); /* Push gzdio onto stack */
609 static int gzdFlush(FD_t fd)
612 gzfile = gzdFileno(fd);
613 if (gzfile == NULL) return -2;
614 return gzflush(gzfile, Z_SYNC_FLUSH); /* XXX W2DO? */
617 static ssize_t gzdRead(FD_t fd, void * buf, size_t count)
622 gzfile = gzdFileno(fd);
623 if (gzfile == NULL) return -2; /* XXX can't happen */
625 rc = gzread(gzfile, buf, count);
628 fd->errcookie = gzerror(gzfile, &zerror);
629 if (zerror == Z_ERRNO) {
630 fd->syserrno = errno;
631 fd->errcookie = strerror(fd->syserrno);
637 static ssize_t gzdWrite(FD_t fd, const void * buf, size_t count)
642 gzfile = gzdFileno(fd);
643 if (gzfile == NULL) return -2; /* XXX can't happen */
645 rc = gzwrite(gzfile, (void *)buf, count);
648 fd->errcookie = gzerror(gzfile, &zerror);
649 if (zerror == Z_ERRNO) {
650 fd->syserrno = errno;
651 fd->errcookie = strerror(fd->syserrno);
657 /* XXX zlib-1.0.4 has not */
658 static int gzdSeek(FD_t fd, off_t pos, int whence)
665 if (fd == NULL) return -2;
667 gzfile = gzdFileno(fd);
668 if (gzfile == NULL) return -2; /* XXX can't happen */
670 rc = gzseek(gzfile, p, whence);
673 fd->errcookie = gzerror(gzfile, &zerror);
674 if (zerror == Z_ERRNO) {
675 fd->syserrno = errno;
676 fd->errcookie = strerror(fd->syserrno);
685 static int gzdClose(FD_t fd)
690 gzfile = gzdFileno(fd);
691 if (gzfile == NULL) return -2; /* XXX can't happen */
693 rc = gzclose(gzfile);
695 /* XXX TODO: preserve fd if errors */
699 fd->errcookie = "gzclose error";
701 fd->syserrno = errno;
702 fd->errcookie = strerror(fd->syserrno);
707 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "GZDIO", stderr);
713 static long gzdTell(FD_t fd)
716 gzFile gzfile = gzdFileno(fd);
718 if (gzfile != NULL) {
720 pos = gztell(gzfile);
723 fd->errcookie = gzerror(gzfile, &zerror);
724 if (zerror == Z_ERRNO) {
725 fd->syserrno = errno;
726 fd->errcookie = strerror(fd->syserrno);
735 static const struct FDIO_s gzdio_s = {
736 gzdRead, gzdWrite, gzdSeek, gzdClose, fdLink, fdFree, fdNew, fdFileno,
737 NULL, gzdOpen, gzdFileno, gzdFlush, gzdTell
739 static const FDIO_t gzdio = &gzdio_s ;
741 /* =============================================================== */
742 /* Support for BZIP2 library. */
747 static void * bzdFileno(FD_t fd)
749 return iotFileno(fd, bzdio);
752 static FD_t bzdOpen(const char * path, const char * mode)
756 if ((bzfile = BZ2_bzopen(path, mode)) == NULL)
759 fdPop(fd); fdPush(fd, bzdio, bzfile, -1);
763 static FD_t bzdFdopen(FD_t fd, const char * fmode)
768 if (fd == NULL || fmode == NULL) return NULL;
770 fdSetFdno(fd, -1); /* XXX skip the fdio close */
771 if (fdno < 0) return NULL;
772 bzfile = BZ2_bzdopen(fdno, fmode);
773 if (bzfile == NULL) return NULL;
775 fdPush(fd, bzdio, bzfile, fdno); /* Push bzdio onto stack */
780 static int bzdFlush(FD_t fd)
782 return BZ2_bzflush(bzdFileno(fd));
785 static ssize_t bzdRead(FD_t fd, void * buf, size_t count)
790 bzfile = bzdFileno(fd);
792 rc = BZ2_bzread(bzfile, buf, count);
796 fd->errcookie = BZ2_bzerror(bzfile, &zerror);
801 static ssize_t bzdWrite(FD_t fd, const void * buf, size_t count)
806 bzfile = bzdFileno(fd);
807 rc = BZ2_bzwrite(bzfile, (void *)buf, count);
810 fd->errcookie = BZ2_bzerror(bzfile, &zerror);
815 static int bzdClose(FD_t fd)
820 bzfile = bzdFileno(fd);
822 if (bzfile == NULL) return -2;
825 rc = 0; /* XXX FIXME */
827 /* XXX TODO: preserve fd if errors */
832 fd->errcookie = BZ2_bzerror(bzfile, &zerror);
836 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "BZDIO", stderr);
842 static const struct FDIO_s bzdio_s = {
843 bzdRead, bzdWrite, NULL, bzdClose, fdLink, fdFree, fdNew, fdFileno,
844 NULL, bzdOpen, bzdFileno, bzdFlush, NULL
846 static const FDIO_t bzdio = &bzdio_s ;
848 #endif /* HAVE_BZLIB_H */
850 static const char * getFdErrstr (FD_t fd)
852 const char *errstr = NULL;
854 if (fdGetIo(fd) == gzdio) {
855 errstr = fd->errcookie;
858 if (fdGetIo(fd) == bzdio) {
859 errstr = fd->errcookie;
861 #endif /* HAVE_BZLIB_H */
863 if (fdGetIo(fd) == xzdio || fdGetIo(fd) == lzdio) {
864 errstr = fd->errcookie;
866 #endif /* HAVE_LZMA_H */
868 errstr = (fd->syserrno ? strerror(fd->syserrno) : "");
874 /* =============================================================== */
875 /* Support for LZMA library. */
879 #include <sys/types.h>
880 #include <inttypes.h>
883 #define kBufferSize (1 << 15)
885 typedef struct lzfile {
887 uint8_t buf[kBufferSize];
898 static LZFILE *lzopen_internal(const char *path, const char *mode, int fd, int xz)
900 int level = 7; /* Use XZ's default compression level if unspecified */
905 lzma_stream init_strm = LZMA_STREAM_INIT;
907 for (; *mode; mode++) {
910 else if (*mode == 'r')
912 else if (*mode >= '1' && *mode <= '9')
916 fp = fdopen(fd, encoding ? "w" : "r");
918 fp = fopen(path, encoding ? "w" : "r");
921 lzfile = calloc(1, sizeof(*lzfile));
928 lzfile->encoding = encoding;
930 lzfile->strm = init_strm;
933 ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
935 lzma_options_lzma options;
936 lzma_lzma_preset(&options, level);
937 ret = lzma_alone_encoder(&lzfile->strm, &options);
939 } else { /* lzma_easy_decoder_memusage(level) is not ready yet, use hardcoded limit for now */
940 ret = lzma_auto_decoder(&lzfile->strm, 100<<20, 0);
942 if (ret != LZMA_OK) {
950 static LZFILE *xzopen(const char *path, const char *mode)
952 return lzopen_internal(path, mode, -1, 1);
955 static LZFILE *xzdopen(int fd, const char *mode)
959 return lzopen_internal(0, mode, fd, 1);
962 static LZFILE *lzopen(const char *path, const char *mode)
964 return lzopen_internal(path, mode, -1, 0);
967 static LZFILE *lzdopen(int fd, const char *mode)
971 return lzopen_internal(0, mode, fd, 0);
974 static int lzflush(LZFILE *lzfile)
976 return fflush(lzfile->file);
979 static int lzclose(LZFILE *lzfile)
987 if (lzfile->encoding) {
989 lzfile->strm.avail_out = kBufferSize;
990 lzfile->strm.next_out = lzfile->buf;
991 ret = lzma_code(&lzfile->strm, LZMA_FINISH);
992 if (ret != LZMA_OK && ret != LZMA_STREAM_END)
994 n = kBufferSize - lzfile->strm.avail_out;
995 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
997 if (ret == LZMA_STREAM_END)
1001 lzma_end(&lzfile->strm);
1002 rc = fclose(lzfile->file);
1007 static ssize_t lzread(LZFILE *lzfile, void *buf, size_t len)
1012 if (!lzfile || lzfile->encoding)
1016 lzfile->strm.next_out = buf;
1017 lzfile->strm.avail_out = len;
1019 if (!lzfile->strm.avail_in) {
1020 lzfile->strm.next_in = lzfile->buf;
1021 lzfile->strm.avail_in = fread(lzfile->buf, 1, kBufferSize, lzfile->file);
1022 if (!lzfile->strm.avail_in)
1025 ret = lzma_code(&lzfile->strm, LZMA_RUN);
1026 if (ret == LZMA_STREAM_END) {
1028 return len - lzfile->strm.avail_out;
1032 if (!lzfile->strm.avail_out)
1039 static ssize_t lzwrite(LZFILE *lzfile, void *buf, size_t len)
1043 if (!lzfile || !lzfile->encoding)
1047 lzfile->strm.next_in = buf;
1048 lzfile->strm.avail_in = len;
1050 lzfile->strm.next_out = lzfile->buf;
1051 lzfile->strm.avail_out = kBufferSize;
1052 ret = lzma_code(&lzfile->strm, LZMA_RUN);
1055 n = kBufferSize - lzfile->strm.avail_out;
1056 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
1058 if (!lzfile->strm.avail_in)
1063 static void * lzdFileno(FD_t fd)
1070 for (int i = fd->nfps; i >= 0; i--) {
1071 FDSTACK_t * fps = &fd->fps[i];
1072 if (fps->io != xzdio && fps->io != lzdio)
1080 static FD_t xzdOpen(const char * path, const char * mode)
1084 if ((lzfile = xzopen(path, mode)) == NULL)
1087 fdPop(fd); fdPush(fd, xzdio, lzfile, -1);
1091 static FD_t xzdFdopen(FD_t fd, const char * fmode)
1096 if (fd == NULL || fmode == NULL) return NULL;
1097 fdno = fdFileno(fd);
1098 fdSetFdno(fd, -1); /* XXX skip the fdio close */
1099 if (fdno < 0) return NULL;
1100 lzfile = xzdopen(fdno, fmode);
1101 if (lzfile == NULL) return NULL;
1102 fdPush(fd, xzdio, lzfile, fdno);
1106 static FD_t lzdOpen(const char * path, const char * mode)
1110 if ((lzfile = lzopen(path, mode)) == NULL)
1113 fdPop(fd); fdPush(fd, xzdio, lzfile, -1);
1117 static FD_t lzdFdopen(FD_t fd, const char * fmode)
1122 if (fd == NULL || fmode == NULL) return NULL;
1123 fdno = fdFileno(fd);
1124 fdSetFdno(fd, -1); /* XXX skip the fdio close */
1125 if (fdno < 0) return NULL;
1126 lzfile = lzdopen(fdno, fmode);
1127 if (lzfile == NULL) return NULL;
1128 fdPush(fd, xzdio, lzfile, fdno);
1132 static int lzdFlush(FD_t fd)
1134 return lzflush(lzdFileno(fd));
1137 static ssize_t lzdRead(FD_t fd, void * buf, size_t count)
1142 lzfile = lzdFileno(fd);
1144 rc = lzread(lzfile, buf, count);
1146 fd->errcookie = "Lzma: decoding error";
1151 static ssize_t lzdWrite(FD_t fd, const void * buf, size_t count)
1156 lzfile = lzdFileno(fd);
1158 rc = lzwrite(lzfile, (void *)buf, count);
1160 fd->errcookie = "Lzma: encoding error";
1165 static int lzdClose(FD_t fd)
1170 lzfile = lzdFileno(fd);
1172 if (lzfile == NULL) return -2;
1173 rc = lzclose(lzfile);
1175 /* XXX TODO: preserve fd if errors */
1179 fd->errcookie = "lzclose error";
1180 fd->syserrno = errno;
1181 fd->errcookie = strerror(fd->syserrno);
1185 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "XZDIO", stderr);
1191 static struct FDIO_s xzdio_s = {
1192 lzdRead, lzdWrite, NULL, lzdClose, NULL, NULL, NULL, fdFileno,
1193 NULL, xzdOpen, lzdFileno, lzdFlush, NULL
1195 static const FDIO_t xzdio = &xzdio_s;
1197 static struct FDIO_s lzdio_s = {
1198 lzdRead, lzdWrite, NULL, lzdClose, NULL, NULL, NULL, fdFileno,
1199 NULL, lzdOpen, lzdFileno, lzdFlush, NULL
1201 static const FDIO_t lzdio = &lzdio_s;
1203 #endif /* HAVE_LZMA_H */
1205 /* =============================================================== */
1207 const char *Fstrerror(FD_t fd)
1210 return (errno ? strerror(errno) : "");
1211 return getFdErrstr(fd);
1214 #define FDIOVEC(_fd, _vec) \
1215 ((fdGetIo(_fd) && fdGetIo(_fd)->_vec) ? fdGetIo(_fd)->_vec : NULL)
1217 ssize_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
1222 fdio_read_function_t _read = FDIOVEC(fd, read);
1224 fdstat_enter(fd, FDSTAT_READ);
1225 rc = (_read ? (*_read) (fd, buf, size * nmemb) : -2);
1226 fdstat_exit(fd, FDSTAT_READ, rc);
1228 if (fd->digests && rc > 0)
1229 fdUpdateDigests(fd, buf, rc);
1232 DBGIO(fd, (stderr, "==>\tFread(%p,%p,%ld) rc %ld %s\n",
1233 fd, buf, (long)size * nmemb, (long)rc, fdbg(fd)));
1238 ssize_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
1243 fdio_write_function_t _write = FDIOVEC(fd, write);
1245 fdstat_enter(fd, FDSTAT_WRITE);
1246 rc = (_write ? _write(fd, buf, size * nmemb) : -2);
1247 fdstat_exit(fd, FDSTAT_WRITE, rc);
1249 if (fd->digests && rc > 0)
1250 fdUpdateDigests(fd, buf, rc);
1253 DBGIO(fd, (stderr, "==>\tFwrite(%p,%p,%ld) rc %ld %s\n",
1254 fd, buf, (long)size * nmemb, (long)rc, fdbg(fd)));
1259 int Fseek(FD_t fd, off_t offset, int whence)
1264 fdio_seek_function_t _seek = FDIOVEC(fd, seek);
1266 fdstat_enter(fd, FDSTAT_SEEK);
1267 rc = (_seek ? _seek(fd, offset, whence) : -2);
1268 fdstat_exit(fd, FDSTAT_SEEK, rc);
1271 DBGIO(fd, (stderr, "==>\tFseek(%p,%ld,%d) rc %lx %s\n",
1272 fd, (long)offset, whence, (unsigned long)rc, fdbg(fd)));
1285 fdstat_enter(fd, FDSTAT_CLOSE);
1286 while (fd->nfps >= 0) {
1287 fdio_close_function_t _close = FDIOVEC(fd, close);
1288 rc = _close ? _close(fd) : -2;
1296 fdstat_exit(fd, FDSTAT_CLOSE, rc);
1297 DBGIO(fd, (stderr, "==>\tFclose(%p) rc %lx %s\n",
1298 (fd ? fd : NULL), (unsigned long)rc, fdbg(fd)));
1305 * Convert stdio fmode to open(2) mode, filtering out zlib/bzlib flags.
1306 * returns stdio[0] = NUL on error.
1308 * - gzopen: [0-9] is compression level
1309 * - gzopen: 'f' is filtered (Z_FILTERED)
1310 * - gzopen: 'h' is Huffman encoding (Z_HUFFMAN_ONLY)
1311 * - bzopen: [1-9] is block size (modulo 100K)
1312 * - bzopen: 's' is smallmode
1313 * - HACK: '.' terminates, rest is type of I/O
1315 static void cvtfmode (const char *m,
1316 char *stdio, size_t nstdio,
1317 char *other, size_t nother,
1318 const char **end, int * f)
1325 flags |= O_WRONLY | O_CREAT | O_APPEND;
1326 if (--nstdio > 0) *stdio++ = *m;
1329 flags |= O_WRONLY | O_CREAT | O_TRUNC;
1330 if (--nstdio > 0) *stdio++ = *m;
1334 if (--nstdio > 0) *stdio++ = *m;
1343 while ((c = *m++) != '\0') {
1348 flags &= ~(O_RDONLY|O_WRONLY);
1350 if (--nstdio > 0) *stdio++ = c;
1354 if (--nstdio > 0) *stdio++ = c;
1359 if (--nstdio > 0) *stdio++ = c;
1363 if (--nother > 0) *other++ = c;
1370 *stdio = *other = '\0';
1372 *end = (*m != '\0' ? m : NULL);
1377 FD_t Fdopen(FD_t ofd, const char *fmode)
1379 char stdio[20], other[20], zstdio[20];
1380 const char *end = NULL;
1385 fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
1387 if (fd == NULL || fmode == NULL)
1390 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL);
1391 if (stdio[0] == '\0')
1394 strncat(zstdio, stdio, sizeof(zstdio) - strlen(zstdio));
1395 strncat(zstdio, other, sizeof(zstdio) - strlen(zstdio));
1397 if (end == NULL && other[0] == '\0')
1401 if (rstreq(end, "fdio")) {
1403 } else if (rstreq(end, "gzdio") || rstreq(end, "gzip")) {
1405 fd = gzdFdopen(fd, zstdio);
1407 } else if (rstreq(end, "bzdio") || rstreq(end, "bzip2")) {
1409 fd = bzdFdopen(fd, zstdio);
1412 } else if (rstreq(end, "xzdio") || rstreq(end, "xz")) {
1414 fd = xzdFdopen(fd, zstdio);
1415 } else if (rstreq(end, "lzdio") || rstreq(end, "lzma")) {
1417 fd = lzdFdopen(fd, zstdio);
1419 } else if (rstreq(end, "ufdio")) {
1422 } else if (other[0] != '\0') {
1423 for (end = other; *end && strchr("0123456789fh", *end); end++)
1427 fd = gzdFdopen(fd, zstdio);
1433 DBGIO(fd, (stderr, "==> Fdopen(%p,\"%s\") returns fd %p %s\n", ofd, fmode, (fd ? fd : NULL), fdbg(fd)));
1437 FD_t Fopen(const char *path, const char *fmode)
1439 char stdio[20], other[20];
1440 const char *end = NULL;
1441 mode_t perms = 0666;
1445 if (path == NULL || fmode == NULL)
1449 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, &flags);
1450 if (stdio[0] == '\0')
1453 if (end == NULL || rstreq(end, "fdio")) {
1455 fprintf(stderr, "*** Fopen fdio path %s fmode %s\n", path, fmode);
1456 fd = fdOpen(path, flags, perms);
1457 if (fdFileno(fd) < 0) {
1458 if (fd) (void) fdClose(fd);
1462 /* XXX gzdio and bzdio here too */
1464 switch (urlIsURL(path)) {
1471 case URL_IS_UNKNOWN:
1473 fprintf(stderr, "*** Fopen ufdio path %s fmode %s\n", path, fmode);
1474 fd = ufdOpen(path, flags, perms);
1475 if (fd == NULL || !(fdFileno(fd) >= 0))
1480 fprintf(stderr, "*** Fopen WTFO path %s fmode %s\n", path, fmode);
1488 fd = Fdopen(fd, fmode);
1490 DBGIO(fd, (stderr, "==>\tFopen(\"%s\",%x,0%o) %s\n",
1491 path, (unsigned)flags, (unsigned)perms, fdbg(fd)));
1500 fdio_fflush_function_t _fflush = FDIOVEC(fd, _fflush);
1502 rc = (_fflush ? _fflush(fd) : -2);
1507 off_t Ftell(FD_t fd)
1511 fdio_ftell_function_t _ftell = FDIOVEC(fd, _ftell);
1513 pos = (_ftell ? _ftell(fd) : -2);
1522 if (fd == NULL) return -1;
1523 for (i = fd->nfps; rc == 0 && i >= 0; i--) {
1524 FDSTACK_t * fps = &fd->fps[i];
1527 if (fps->io == gzdio) {
1528 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
1529 i--; /* XXX fdio under gzdio always has fdno == -1 */
1531 } else if (fps->io == bzdio) {
1532 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
1533 i--; /* XXX fdio under bzdio always has fdno == -1 */
1536 } else if (fps->io == xzdio || fps->io == lzdio) {
1537 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
1538 i--; /* XXX fdio under xzdio/lzdio always has fdno == -1 */
1541 /* XXX need to check ufdio/gzdio/bzdio/fdio errors correctly. */
1542 ec = (fdFileno(fd) < 0 ? -1 : 0);
1548 DBGIO(fd, (stderr, "==> Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd)));
1556 if (fd == NULL) return -1;
1557 for (i = fd->nfps ; rc == -1 && i >= 0; i--) {
1558 rc = fd->fps[i].fdno;
1561 DBGIO(fd, (stderr, "==> Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, fdbg(fd)));
1565 /* XXX this is naive */
1566 int Fcntl(FD_t fd, int op, void *lip)
1568 return fcntl(Fileno(fd), op, lip);
1571 rpmop fdOp(FD_t fd, fdOpX opx)
1575 if (fd != NULL && fd->stats != NULL && opx >= 0 && opx < FDSTAT_MAX)
1576 op = fd->stats->ops + opx;
1580 int rpmioSlurp(const char * fn, uint8_t ** bp, ssize_t * blenp)
1582 static const ssize_t blenmax = (32 * BUFSIZ);
1589 fd = Fopen(fn, "r.ufdio");
1590 if (fd == NULL || Ferror(fd)) {
1596 blen = (size >= 0 ? size : blenmax);
1599 b = xmalloc(blen+1);
1601 nb = Fread(b, sizeof(*b), blen, fd);
1602 if (Ferror(fd) || (size > 0 && nb != blen)) {
1606 if (blen == blenmax && nb < blen) {
1608 b = xrealloc(b, blen+1);
1614 if (fd) (void) Fclose(fd);
1623 else if (b) free(b);
1625 if (blenp) *blenp = blen;
1630 void fdInitDigest(FD_t fd, int hashalgo, rpmDigestFlags flags)
1632 if (fd->digests == NULL) {
1633 fd->digests = rpmDigestBundleNew();
1635 fdstat_enter(fd, FDSTAT_DIGEST);
1636 rpmDigestBundleAdd(fd->digests, hashalgo, flags);
1637 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);
1640 static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen)
1642 if (fd && fd->digests) {
1643 fdstat_enter(fd, FDSTAT_DIGEST);
1644 rpmDigestBundleUpdate(fd->digests, buf, buflen);
1645 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) buflen);
1649 void fdFiniDigest(FD_t fd, int hashalgo,
1650 void ** datap, size_t * lenp, int asAscii)
1652 if (fd && fd->digests) {
1653 fdstat_enter(fd, FDSTAT_DIGEST);
1654 rpmDigestBundleFinal(fd->digests, hashalgo, datap, lenp, asAscii);
1655 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);