add rpmlog(RPMLOG_ERR, ...) for liblzma return codes
[platform/upstream/rpm.git] / rpmio / rpmio.c
1 /** \ingroup rpmio
2  * \file rpmio/rpmio.c
3  */
4
5 #include "system.h"
6 #include <stdarg.h>
7 #include <errno.h>
8
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>
14
15 #include "rpmio/rpmio_internal.h"
16
17 #include "debug.h"
18
19 typedef struct _FDSTACK_s {
20     FDIO_t              io;
21     void *              fp;
22     int                 fdno;
23 } FDSTACK_t;
24
25 /** \ingroup rpmio
26  * Cumulative statistics for a descriptor.
27  */
28 typedef struct {
29     struct rpmop_s      ops[FDSTAT_MAX];        /*!< Cumulative statistics. */
30 } * FDSTAT_t;
31
32 /** \ingroup rpmio
33  * The FD_t File Handle data structure.
34  */
35 struct _FD_s {
36     int         nrefs;
37     int         flags;
38 #define RPMIO_DEBUG_IO          0x40000000
39     int         magic;
40 #define FDMAGIC                 0x04463138
41     int         nfps;
42     FDSTACK_t   fps[8];
43     int         urlType;        /* ufdio: */
44
45     int         syserrno;       /* last system errno encountered */
46     const char *errcookie;      /* gzdio/bzdio/ufdio/xzdio: */
47
48     char        *descr;         /* file name (or other description) */
49     FDSTAT_t    stats;          /* I/O statistics */
50
51     rpmDigestBundle digests;
52 };
53
54 #define DBG(_f, _m, _x) \
55     \
56     if ((_rpmio_debug | ((_f) ? ((FD_t)(_f))->flags : 0)) & (_m)) fprintf _x \
57
58 #define DBGIO(_f, _x)   DBG((_f), RPMIO_DEBUG_IO, _x)
59
60 static FDIO_t fdGetIo(FD_t fd)
61 {
62     return (fd != NULL) ? fd->fps[fd->nfps].io : NULL;
63 }
64
65 static void fdSetIo(FD_t fd, FDIO_t io)
66 {
67     if (fd)
68         fd->fps[fd->nfps].io = io;
69 }
70
71 static void * fdGetFp(FD_t fd)
72 {
73     return (fd != NULL) ? fd->fps[fd->nfps].fp : NULL;
74 }
75
76 static void fdSetFp(FD_t fd, void * fp)
77 {
78     if (fd)
79         fd->fps[fd->nfps].fp = fp;
80 }
81
82 static void fdSetFdno(FD_t fd, int fdno)
83 {
84     if (fd) 
85         fd->fps[fd->nfps].fdno = fdno;
86 }
87
88 static void fdPush(FD_t fd, FDIO_t io, void * fp, int fdno)
89 {
90     if (fd == NULL || fd->nfps >= (sizeof(fd->fps)/sizeof(fd->fps[0]) - 1))
91         return;
92     fd->nfps++;
93     fdSetIo(fd, io);
94     fdSetFp(fd, fp);
95     fdSetFdno(fd, fdno);
96 }
97
98 static void fdPop(FD_t fd)
99 {
100     if (fd == NULL || fd->nfps < 0) return;
101     fdSetIo(fd, NULL);
102     fdSetFp(fd, NULL);
103     fdSetFdno(fd, -1);
104     fd->nfps--;
105 }
106
107 void fdSetBundle(FD_t fd, rpmDigestBundle bundle)
108 {
109     if (fd)
110         fd->digests = bundle;
111 }
112
113 rpmDigestBundle fdGetBundle(FD_t fd)
114 {
115     return (fd != NULL) ? fd->digests : NULL;
116 }
117
118 static void * iotFileno(FD_t fd, FDIO_t iot)
119 {
120     void * rc = NULL;
121
122     if (fd == NULL)
123         return NULL;
124
125     for (int i = fd->nfps; i >= 0; i--) {
126         FDSTACK_t * fps = &fd->fps[i];
127         if (fps->io != iot)
128             continue;
129         rc = fps->fp;
130         break;
131     }
132     
133     return rc;
134 }
135
136 /** \ingroup rpmio
137  * \name RPMIO Vectors.
138  */
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);
152
153 struct FDIO_s {
154   fdio_read_function_t          read;
155   fdio_write_function_t         write;
156   fdio_seek_function_t          seek;
157   fdio_close_function_t         close;
158
159   fdio_ref_function_t           _fdref;
160   fdio_deref_function_t         _fdderef;
161   fdio_new_function_t           _fdnew;
162   fdio_fileno_function_t        _fileno;
163
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;
169 };
170
171 /* forward refs */
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;
178
179 /** \ingroup rpmio
180  * Update digest(s) attached to fd.
181  */
182 static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen);
183 static FD_t fdNew(const char *descr);
184 /**
185  */
186 int _rpmio_debug = 0;
187
188 /* =============================================================== */
189
190 static const char * fdbg(FD_t fd)
191 {
192     static char buf[BUFSIZ];
193     char *be = buf;
194     int i;
195
196     buf[0] = '\0';
197     if (fd == NULL)
198         return buf;
199
200     *be++ = '\t';
201     for (i = fd->nfps; i >= 0; i--) {
202         FDSTACK_t * fps = &fd->fps[i];
203         if (i != fd->nfps)
204             *be++ = ' ';
205         *be++ = '|';
206         *be++ = ' ';
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);
213 #if HAVE_BZLIB_H
214         } else if (fps->io == bzdio) {
215             sprintf(be, "BZD %p fdno %d", fps->fp, fps->fdno);
216 #endif
217 #if HAVE_LZMA_H
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);
222 #endif
223         } else {
224             sprintf(be, "??? io %p fp %p fdno %d ???",
225                 fps->io, fps->fp, fps->fdno);
226         }
227         be += strlen(be);
228         *be = '\0';
229     }
230     return buf;
231 }
232
233 static void fdstat_enter(FD_t fd, fdOpX opx)
234 {
235     if (fd->stats != NULL)
236         (void) rpmswEnter(fdOp(fd, opx), (ssize_t) 0);
237 }
238
239 static void fdstat_exit(FD_t fd, fdOpX opx, ssize_t rc)
240 {
241     if (rc == -1)
242         fd->syserrno = errno;
243     if (fd->stats != NULL)
244         (void) rpmswExit(fdOp(fd, opx), rc);
245 }
246
247 static void fdstat_print(FD_t fd, const char * msg, FILE * fp)
248 {
249     static const int usec_scale = (1000*1000);
250     int opx;
251
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;
256         switch (opx) {
257         case FDSTAT_READ:
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));
262             break;
263         case FDSTAT_WRITE:
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));
268             break;
269         case FDSTAT_SEEK:
270             break;
271         case FDSTAT_CLOSE:
272             break;
273         }
274     }
275 }
276
277 off_t fdSize(FD_t fd)
278 {
279     struct stat sb;
280     off_t rc = -1; 
281
282     if (fd != NULL && fstat(Fileno(fd), &sb) == 0)
283         rc = sb.st_size;
284     return rc;
285 }
286
287 FD_t fdDup(int fdno)
288 {
289     FD_t fd;
290     int nfdno;
291
292     if ((nfdno = dup(fdno)) < 0)
293         return NULL;
294     fd = fdNew(NULL);
295     fdSetFdno(fd, nfdno);
296 DBGIO(fd, (stderr, "==> fdDup(%d) fd %p %s\n", fdno, (fd ? fd : NULL), fdbg(fd)));
297     return fd;
298 }
299
300 /* Regular fd doesn't have fflush() equivalent but its not an error either */
301 static int fdFlush(FD_t fd)
302 {
303     return 0;
304 }
305
306 static int fdFileno(FD_t fd)
307 {
308     return (fd != NULL) ? fd->fps[0].fdno : -2;
309 }
310
311 const char * Fdescr(FD_t fd)
312 {
313     if (fd == NULL)
314         return _("[none]");
315
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;
322         char buf[PATH_MAX];
323         ssize_t llen;
324
325         rasprintf(&procpath, "/proc/self/fd/%d", fdno);
326         llen = readlink(procpath, buf, sizeof(buf)-1);
327         free(procpath);
328
329         if (llen >= 1) {
330             buf[llen] = '\0';
331             /* Real paths in /proc are always absolute */
332             if (buf[0] == '/')
333                 fd->descr = xstrdup(buf);
334             else
335                 fd->descr = rstrscat(NULL, "[", buf, "]", NULL);
336         }
337 #endif
338         /* Still no description, base it on fdno which is always there */
339         if (fd->descr == NULL)
340             rasprintf(&(fd->descr), "[fd %d]", fdno);
341     }
342     return fd->descr;
343 }
344
345 FD_t fdLink(FD_t fd)
346 {
347     if (fd)
348         fd->nrefs++;
349     return fd;
350 }
351
352 FD_t fdFree( FD_t fd)
353 {
354     if (fd) {
355         if (--fd->nrefs > 0)
356             return fd;
357         fd->stats = _free(fd->stats);
358         if (fd->digests) {
359             fd->digests = rpmDigestBundleFree(fd->digests);
360         }
361         free(fd->descr);
362         free(fd);
363     }
364     return NULL;
365 }
366
367 FD_t fdNew(const char *descr)
368 {
369     FD_t fd = xcalloc(1, sizeof(*fd));
370     if (fd == NULL) /* XXX xmalloc never returns NULL */
371         return NULL;
372     fd->nrefs = 0;
373     fd->flags = 0;
374     fd->magic = FDMAGIC;
375     fd->urlType = URL_IS_UNKNOWN;
376
377     fd->nfps = 0;
378     memset(fd->fps, 0, sizeof(fd->fps));
379
380     fd->fps[0].io = fdio;
381     fd->fps[0].fp = NULL;
382     fd->fps[0].fdno = -1;
383
384     fd->syserrno = 0;
385     fd->errcookie = NULL;
386     fd->stats = xcalloc(1, sizeof(*fd->stats));
387     fd->digests = NULL;
388     fd->descr = descr ? xstrdup(descr) : NULL;
389
390     return fdLink(fd);
391 }
392
393 static ssize_t fdRead(FD_t fd, void * buf, size_t count)
394 {
395     return read(fdFileno(fd), buf, count);
396 }
397
398 static ssize_t fdWrite(FD_t fd, const void * buf, size_t count)
399 {
400     if (count == 0)
401         return 0;
402
403     return write(fdFileno(fd), buf, count);
404 }
405
406 static int fdSeek(FD_t fd, off_t pos, int whence)
407 {
408     return lseek(fdFileno(fd), pos, whence);
409 }
410
411 static int fdClose(FD_t fd)
412 {
413     int fdno;
414     int rc;
415
416     if (fd == NULL) return -2;
417     fdno = fdFileno(fd);
418
419     fdSetFdno(fd, -1);
420
421     rc = ((fdno >= 0) ? close(fdno) : -2);
422
423     fdFree(fd);
424     return rc;
425 }
426
427 static FD_t fdOpen(const char *path, int flags, mode_t mode)
428 {
429     FD_t fd;
430     int fdno;
431
432     fdno = open(path, flags, mode);
433     if (fdno < 0) return NULL;
434     if (fcntl(fdno, F_SETFD, FD_CLOEXEC)) {
435         (void) close(fdno);
436         return NULL;
437     }
438     fd = fdNew(path);
439     fdSetFdno(fd, fdno);
440     fd->flags = flags;
441     return fd;
442 }
443
444 static long fdTell(FD_t fd)
445 {
446     return lseek(Fileno(fd), 0, SEEK_CUR);
447 }
448
449 static const struct FDIO_s fdio_s = {
450   fdRead, fdWrite, fdSeek, fdClose, fdLink, fdFree, fdNew, fdFileno,
451   fdOpen, NULL, fdGetFp, fdFlush, fdTell
452 };
453 static const FDIO_t fdio = &fdio_s ;
454
455 off_t ufdCopy(FD_t sfd, FD_t tfd)
456 {
457     char buf[BUFSIZ];
458     ssize_t rdbytes, wrbytes;
459     off_t total = 0;
460
461     while (1) {
462         rdbytes = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd);
463
464         if (rdbytes > 0) {
465             wrbytes = Fwrite(buf, sizeof(buf[0]), rdbytes, tfd);
466             if (wrbytes != rdbytes) {
467                 total = -1;
468                 break;
469             }
470             total += wrbytes;
471         } else {
472             if (rdbytes < 0)
473                 total = -1;
474             break;
475         }
476     }
477
478     return total;
479 }
480
481 /*
482  * Deal with remote url's by fetching them with a helper application
483  * and treat as local file afterwards.
484  * TODO:
485  * - better error checking + reporting 
486  * - curl & friends don't know about hkp://, transform to http?
487  */
488
489 static FD_t urlOpen(const char * url, int flags, mode_t mode)
490 {
491     FD_t fd;
492     char *dest = NULL;
493     int rc = 1; /* assume failure */
494
495     fd = rpmMkTempFile(NULL, &dest);
496     if (fd == NULL) {
497         return NULL;
498     }
499     Fclose(fd);
500
501     rc = urlGetFile(url, dest);
502     if (rc == 0) {
503         fd = fdOpen(dest, flags, mode);
504         unlink(dest);
505     } else {
506         fd = NULL;
507     }
508     dest = _free(dest);
509
510     return fd;
511
512 }
513 static FD_t ufdOpen(const char * url, int flags, mode_t mode)
514 {
515     FD_t fd = NULL;
516     const char * path;
517     urltype urlType = urlPath(url, &path);
518
519 if (_rpmio_debug)
520 fprintf(stderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mode);
521
522     switch (urlType) {
523     case URL_IS_FTP:
524     case URL_IS_HTTPS:
525     case URL_IS_HTTP:
526     case URL_IS_HKP:
527         fd = urlOpen(url, flags, mode);
528         /* we're dealing with local file when urlOpen() returns */
529         urlType = URL_IS_UNKNOWN;
530         break;
531     case URL_IS_DASH:
532         if ((flags & O_ACCMODE) == O_RDWR) {
533             fd = NULL;
534         } else {
535             fd = fdDup((flags & O_ACCMODE) == O_WRONLY ?
536                         STDOUT_FILENO : STDIN_FILENO);
537         }
538         break;
539     case URL_IS_PATH:
540     case URL_IS_UNKNOWN:
541     default:
542         fd = fdOpen(path, flags, mode);
543         break;
544     }
545
546     if (fd == NULL) return NULL;
547
548     fdSetIo(fd, ufdio);
549     fd->urlType = urlType;
550
551     if (Fileno(fd) < 0) {
552         (void) fdClose(fd);
553         return NULL;
554     }
555     return fd;
556 }
557
558 static const struct FDIO_s ufdio_s = {
559   fdRead, fdWrite, fdSeek, fdClose, fdLink, fdFree, fdNew, fdFileno,
560   ufdOpen, NULL, fdGetFp, fdFlush, fdTell
561 };
562 static const FDIO_t ufdio = &ufdio_s ;
563
564 /* =============================================================== */
565 /* Support for GZIP library.  */
566 #include <zlib.h>
567
568 static void * gzdFileno(FD_t fd)
569 {
570     return iotFileno(fd, gzdio);
571 }
572
573 static
574 FD_t gzdOpen(const char * path, const char * fmode)
575 {
576     FD_t fd;
577     gzFile gzfile;
578     if ((gzfile = gzopen(path, fmode)) == NULL)
579         return NULL;
580     fd = fdNew(path);
581     fdPop(fd); fdPush(fd, gzdio, gzfile, -1);
582     
583     return fdLink(fd);
584 }
585
586 static FD_t gzdFdopen(FD_t fd, const char *fmode)
587 {
588     int fdno;
589     gzFile gzfile;
590
591     if (fd == NULL || fmode == NULL) return NULL;
592     fdno = fdFileno(fd);
593     fdSetFdno(fd, -1);          /* XXX skip the fdio close */
594     if (fdno < 0) return NULL;
595     gzfile = gzdopen(fdno, fmode);
596     if (gzfile == NULL) return NULL;
597
598     fdPush(fd, gzdio, gzfile, fdno);            /* Push gzdio onto stack */
599
600     return fdLink(fd);
601 }
602
603 static int gzdFlush(FD_t fd)
604 {
605     gzFile gzfile;
606     gzfile = gzdFileno(fd);
607     if (gzfile == NULL) return -2;
608     return gzflush(gzfile, Z_SYNC_FLUSH);       /* XXX W2DO? */
609 }
610
611 static ssize_t gzdRead(FD_t fd, void * buf, size_t count)
612 {
613     gzFile gzfile;
614     ssize_t rc;
615
616     gzfile = gzdFileno(fd);
617     if (gzfile == NULL) return -2;      /* XXX can't happen */
618
619     rc = gzread(gzfile, buf, count);
620     if (rc < 0) {
621         int zerror = 0;
622         fd->errcookie = gzerror(gzfile, &zerror);
623         if (zerror == Z_ERRNO) {
624             fd->syserrno = errno;
625             fd->errcookie = strerror(fd->syserrno);
626         }
627     }
628     return rc;
629 }
630
631 static ssize_t gzdWrite(FD_t fd, const void * buf, size_t count)
632 {
633     gzFile gzfile;
634     ssize_t rc;
635
636     gzfile = gzdFileno(fd);
637     if (gzfile == NULL) return -2;      /* XXX can't happen */
638
639     rc = gzwrite(gzfile, (void *)buf, count);
640     if (rc < 0) {
641         int zerror = 0;
642         fd->errcookie = gzerror(gzfile, &zerror);
643         if (zerror == Z_ERRNO) {
644             fd->syserrno = errno;
645             fd->errcookie = strerror(fd->syserrno);
646         }
647     }
648     return rc;
649 }
650
651 /* XXX zlib-1.0.4 has not */
652 static int gzdSeek(FD_t fd, off_t pos, int whence)
653 {
654     off_t p = pos;
655     int rc;
656 #if HAVE_GZSEEK
657     gzFile gzfile;
658
659     if (fd == NULL) return -2;
660
661     gzfile = gzdFileno(fd);
662     if (gzfile == NULL) return -2;      /* XXX can't happen */
663
664     rc = gzseek(gzfile, p, whence);
665     if (rc < 0) {
666         int zerror = 0;
667         fd->errcookie = gzerror(gzfile, &zerror);
668         if (zerror == Z_ERRNO) {
669             fd->syserrno = errno;
670             fd->errcookie = strerror(fd->syserrno);
671         }
672     }
673 #else
674     rc = -2;
675 #endif
676     return rc;
677 }
678
679 static int gzdClose(FD_t fd)
680 {
681     gzFile gzfile;
682     int rc;
683
684     gzfile = gzdFileno(fd);
685     if (gzfile == NULL) return -2;      /* XXX can't happen */
686
687     rc = gzclose(gzfile);
688
689     /* XXX TODO: preserve fd if errors */
690
691     if (fd) {
692         if (rc < 0) {
693             fd->errcookie = "gzclose error";
694             if (rc == Z_ERRNO) {
695                 fd->syserrno = errno;
696                 fd->errcookie = strerror(fd->syserrno);
697             }
698         }
699     }
700
701     if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "GZDIO", stderr);
702     if (rc == 0)
703         fdFree(fd);
704     return rc;
705 }
706
707 static long gzdTell(FD_t fd)
708 {
709     off_t pos = -1;
710     gzFile gzfile = gzdFileno(fd);
711
712     if (gzfile != NULL) {
713 #if HAVE_GZSEEK
714         pos = gztell(gzfile);
715         if (pos < 0) {
716             int zerror = 0;
717             fd->errcookie = gzerror(gzfile, &zerror);
718             if (zerror == Z_ERRNO) {
719                 fd->syserrno = errno;
720                 fd->errcookie = strerror(fd->syserrno);
721             }
722         }
723 #else
724         pos = -2;
725 #endif    
726     }
727     return pos;
728 }
729 static const struct FDIO_s gzdio_s = {
730   gzdRead, gzdWrite, gzdSeek, gzdClose, fdLink, fdFree, fdNew, fdFileno,
731   NULL, gzdOpen, gzdFileno, gzdFlush, gzdTell
732 };
733 static const FDIO_t gzdio = &gzdio_s ;
734
735 /* =============================================================== */
736 /* Support for BZIP2 library.  */
737 #if HAVE_BZLIB_H
738
739 #include <bzlib.h>
740
741 static void * bzdFileno(FD_t fd)
742 {
743     return iotFileno(fd, bzdio);
744 }
745
746 static FD_t bzdOpen(const char * path, const char * mode)
747 {
748     FD_t fd;
749     BZFILE *bzfile;;
750     if ((bzfile = BZ2_bzopen(path, mode)) == NULL)
751         return NULL;
752     fd = fdNew(path);
753     fdPop(fd); fdPush(fd, bzdio, bzfile, -1);
754     return fdLink(fd);
755 }
756
757 static FD_t bzdFdopen(FD_t fd, const char * fmode)
758 {
759     int fdno;
760     BZFILE *bzfile;
761
762     if (fd == NULL || fmode == NULL) return NULL;
763     fdno = fdFileno(fd);
764     fdSetFdno(fd, -1);          /* XXX skip the fdio close */
765     if (fdno < 0) return NULL;
766     bzfile = BZ2_bzdopen(fdno, fmode);
767     if (bzfile == NULL) return NULL;
768
769     fdPush(fd, bzdio, bzfile, fdno);            /* Push bzdio onto stack */
770
771     return fdLink(fd);
772 }
773
774 static int bzdFlush(FD_t fd)
775 {
776     return BZ2_bzflush(bzdFileno(fd));
777 }
778
779 static ssize_t bzdRead(FD_t fd, void * buf, size_t count)
780 {
781     BZFILE *bzfile;
782     ssize_t rc = 0;
783
784     bzfile = bzdFileno(fd);
785     if (bzfile)
786         rc = BZ2_bzread(bzfile, buf, count);
787     if (rc == -1) {
788         int zerror = 0;
789         if (bzfile)
790             fd->errcookie = BZ2_bzerror(bzfile, &zerror);
791     }
792     return rc;
793 }
794
795 static ssize_t bzdWrite(FD_t fd, const void * buf, size_t count)
796 {
797     BZFILE *bzfile;
798     ssize_t rc;
799
800     bzfile = bzdFileno(fd);
801     rc = BZ2_bzwrite(bzfile, (void *)buf, count);
802     if (rc == -1) {
803         int zerror = 0;
804         fd->errcookie = BZ2_bzerror(bzfile, &zerror);
805     }
806     return rc;
807 }
808
809 static int bzdClose(FD_t fd)
810 {
811     BZFILE *bzfile;
812     int rc;
813
814     bzfile = bzdFileno(fd);
815
816     if (bzfile == NULL) return -2;
817     /* FIX: check rc */
818     BZ2_bzclose(bzfile);
819     rc = 0;     /* XXX FIXME */
820
821     /* XXX TODO: preserve fd if errors */
822
823     if (fd) {
824         if (rc == -1) {
825             int zerror = 0;
826             fd->errcookie = BZ2_bzerror(bzfile, &zerror);
827         }
828     }
829
830     if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "BZDIO", stderr);
831     if (rc == 0)
832         fdFree(fd);
833     return rc;
834 }
835
836 static const struct FDIO_s bzdio_s = {
837   bzdRead, bzdWrite, NULL, bzdClose, fdLink, fdFree, fdNew, fdFileno,
838   NULL, bzdOpen, bzdFileno, bzdFlush, NULL
839 };
840 static const FDIO_t bzdio = &bzdio_s ;
841
842 #endif  /* HAVE_BZLIB_H */
843
844 static const char * getFdErrstr (FD_t fd)
845 {
846     const char *errstr = NULL;
847
848     if (fdGetIo(fd) == gzdio) {
849         errstr = fd->errcookie;
850     } else
851 #ifdef  HAVE_BZLIB_H
852     if (fdGetIo(fd) == bzdio) {
853         errstr = fd->errcookie;
854     } else
855 #endif  /* HAVE_BZLIB_H */
856 #ifdef  HAVE_LZMA_H
857     if (fdGetIo(fd) == xzdio || fdGetIo(fd) == lzdio) {
858         errstr = fd->errcookie;
859     } else
860 #endif  /* HAVE_LZMA_H */
861     {
862         errstr = (fd->syserrno ? strerror(fd->syserrno) : "");
863     }
864
865     return errstr;
866 }
867
868 /* =============================================================== */
869 /* Support for LZMA library.  */
870
871 #ifdef HAVE_LZMA_H
872
873 #include <sys/types.h>
874 #include <inttypes.h>
875 #include <lzma.h>
876
877 #define kBufferSize (1 << 15)
878
879 typedef struct lzfile {
880   /* IO buffer */
881     uint8_t buf[kBufferSize];
882
883     lzma_stream strm;
884
885     FILE *file;
886
887     int encoding;
888     int eof;
889
890 } LZFILE;
891
892 static LZFILE *lzopen_internal(const char *path, const char *mode, int fd, int xz)
893 {
894     int level = LZMA_PRESET_DEFAULT;
895     int encoding = 0;
896     FILE *fp;
897     LZFILE *lzfile;
898     lzma_ret ret;
899     lzma_stream init_strm = LZMA_STREAM_INIT;
900
901     for (; *mode; mode++) {
902         if (*mode == 'w')
903             encoding = 1;
904         else if (*mode == 'r')
905             encoding = 0;
906         else if (*mode >= '0' && *mode <= '9')
907             level = *mode - '0';
908     }
909     if (fd != -1)
910         fp = fdopen(fd, encoding ? "w" : "r");
911     else
912         fp = fopen(path, encoding ? "w" : "r");
913     if (!fp)
914         return 0;
915     lzfile = calloc(1, sizeof(*lzfile));
916     if (!lzfile) {
917         fclose(fp);
918         return 0;
919     }
920     
921     lzfile->file = fp;
922     lzfile->encoding = encoding;
923     lzfile->eof = 0;
924     lzfile->strm = init_strm;
925     if (encoding) {
926         if (xz) {
927             ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
928         } else {
929             lzma_options_lzma options;
930             lzma_lzma_preset(&options, level);
931             ret = lzma_alone_encoder(&lzfile->strm, &options);
932         }
933     } else {    /* lzma_easy_decoder_memusage(level) is not ready yet, use hardcoded limit for now */
934         ret = lzma_auto_decoder(&lzfile->strm, 100<<20, 0);
935     }
936     if (ret != LZMA_OK) {
937         switch (ret) {
938             case LZMA_MEM_ERROR:
939                 rpmlog(RPMLOG_ERR, "liblzma: Memory allocation failed");
940                 break;
941
942             case LZMA_DATA_ERROR:
943                 rpmlog(RPMLOG_ERR, "liblzma: File size limits exceeded");
944                 break;
945
946             default:
947                 rpmlog(RPMLOG_ERR, "liblzma: <Unknown error (%d), possibly a bug", ret);
948                 break;
949         }
950         fclose(fp);
951         free(lzfile);
952         return 0;
953     }
954     return lzfile;
955 }
956
957 static LZFILE *xzopen(const char *path, const char *mode)
958 {
959     return lzopen_internal(path, mode, -1, 1);
960 }
961
962 static LZFILE *xzdopen(int fd, const char *mode)
963 {
964     if (fd < 0)
965         return 0;
966     return lzopen_internal(0, mode, fd, 1);
967 }
968
969 static LZFILE *lzopen(const char *path, const char *mode)
970 {
971     return lzopen_internal(path, mode, -1, 0);
972 }
973
974 static LZFILE *lzdopen(int fd, const char *mode)
975 {
976     if (fd < 0)
977         return 0;
978     return lzopen_internal(0, mode, fd, 0);
979 }
980
981 static int lzflush(LZFILE *lzfile)
982 {
983     return fflush(lzfile->file);
984 }
985
986 static int lzclose(LZFILE *lzfile)
987 {
988     lzma_ret ret;
989     size_t n;
990     int rc;
991
992     if (!lzfile)
993         return -1;
994     if (lzfile->encoding) {
995         for (;;) {
996             lzfile->strm.avail_out = kBufferSize;
997             lzfile->strm.next_out = lzfile->buf;
998             ret = lzma_code(&lzfile->strm, LZMA_FINISH);
999             if (ret != LZMA_OK && ret != LZMA_STREAM_END)
1000                 return -1;
1001             n = kBufferSize - lzfile->strm.avail_out;
1002             if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
1003                 return -1;
1004             if (ret == LZMA_STREAM_END)
1005                 break;
1006         }
1007     }
1008     lzma_end(&lzfile->strm);
1009     rc = fclose(lzfile->file);
1010     free(lzfile);
1011     return rc;
1012 }
1013
1014 static ssize_t lzread(LZFILE *lzfile, void *buf, size_t len)
1015 {
1016     lzma_ret ret;
1017     int eof = 0;
1018
1019     if (!lzfile || lzfile->encoding)
1020       return -1;
1021     if (lzfile->eof)
1022       return 0;
1023     lzfile->strm.next_out = buf;
1024     lzfile->strm.avail_out = len;
1025     for (;;) {
1026         if (!lzfile->strm.avail_in) {
1027             lzfile->strm.next_in = lzfile->buf;
1028             lzfile->strm.avail_in = fread(lzfile->buf, 1, kBufferSize, lzfile->file);
1029             if (!lzfile->strm.avail_in)
1030                 eof = 1;
1031         }
1032         ret = lzma_code(&lzfile->strm, LZMA_RUN);
1033         if (ret == LZMA_STREAM_END) {
1034             lzfile->eof = 1;
1035             return len - lzfile->strm.avail_out;
1036         }
1037         if (ret != LZMA_OK)
1038             return -1;
1039         if (!lzfile->strm.avail_out)
1040             return len;
1041         if (eof)
1042             return -1;
1043       }
1044 }
1045
1046 static ssize_t lzwrite(LZFILE *lzfile, void *buf, size_t len)
1047 {
1048     lzma_ret ret;
1049     size_t n;
1050     if (!lzfile || !lzfile->encoding)
1051         return -1;
1052     if (!len)
1053         return 0;
1054     lzfile->strm.next_in = buf;
1055     lzfile->strm.avail_in = len;
1056     for (;;) {
1057         lzfile->strm.next_out = lzfile->buf;
1058         lzfile->strm.avail_out = kBufferSize;
1059         ret = lzma_code(&lzfile->strm, LZMA_RUN);
1060         if (ret != LZMA_OK)
1061             return -1;
1062         n = kBufferSize - lzfile->strm.avail_out;
1063         if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
1064             return -1;
1065         if (!lzfile->strm.avail_in)
1066             return len;
1067     }
1068 }
1069
1070 static void * lzdFileno(FD_t fd)
1071 {
1072     void * rc = NULL;
1073     
1074     if (fd == NULL)
1075         return NULL;
1076
1077     for (int i = fd->nfps; i >= 0; i--) {
1078         FDSTACK_t * fps = &fd->fps[i];
1079         if (fps->io != xzdio && fps->io != lzdio)
1080             continue;
1081         rc = fps->fp;
1082         break;
1083     }
1084     return rc;
1085 }
1086
1087 static FD_t xzdOpen(const char * path, const char * mode)
1088 {
1089     FD_t fd;
1090     LZFILE *lzfile;
1091     if ((lzfile = xzopen(path, mode)) == NULL)
1092         return NULL;
1093     fd = fdNew(path);
1094     fdPop(fd); fdPush(fd, xzdio, lzfile, -1);
1095     return fdLink(fd);
1096 }
1097
1098 static FD_t xzdFdopen(FD_t fd, const char * fmode)
1099 {
1100     int fdno;
1101     LZFILE *lzfile;
1102
1103     if (fd == NULL || fmode == NULL) return NULL;
1104     fdno = fdFileno(fd);
1105     fdSetFdno(fd, -1);          /* XXX skip the fdio close */
1106     if (fdno < 0) return NULL;
1107     lzfile = xzdopen(fdno, fmode);
1108     if (lzfile == NULL) return NULL;
1109     fdPush(fd, xzdio, lzfile, fdno);
1110     return fdLink(fd);
1111 }
1112
1113 static FD_t lzdOpen(const char * path, const char * mode)
1114 {
1115     FD_t fd;
1116     LZFILE *lzfile;
1117     if ((lzfile = lzopen(path, mode)) == NULL)
1118         return NULL;
1119     fd = fdNew(path);
1120     fdPop(fd); fdPush(fd, xzdio, lzfile, -1);
1121     return fdLink(fd);
1122 }
1123
1124 static FD_t lzdFdopen(FD_t fd, const char * fmode)
1125 {
1126     int fdno;
1127     LZFILE *lzfile;
1128
1129     if (fd == NULL || fmode == NULL) return NULL;
1130     fdno = fdFileno(fd);
1131     fdSetFdno(fd, -1);          /* XXX skip the fdio close */
1132     if (fdno < 0) return NULL;
1133     lzfile = lzdopen(fdno, fmode);
1134     if (lzfile == NULL) return NULL;
1135     fdPush(fd, xzdio, lzfile, fdno);
1136     return fdLink(fd);
1137 }
1138
1139 static int lzdFlush(FD_t fd)
1140 {
1141     return lzflush(lzdFileno(fd));
1142 }
1143
1144 static ssize_t lzdRead(FD_t fd, void * buf, size_t count)
1145 {
1146     LZFILE *lzfile;
1147     ssize_t rc = 0;
1148
1149     lzfile = lzdFileno(fd);
1150     if (lzfile)
1151         rc = lzread(lzfile, buf, count);
1152     if (rc == -1) {
1153         fd->errcookie = "Lzma: decoding error";
1154     }
1155     return rc;
1156 }
1157
1158 static ssize_t lzdWrite(FD_t fd, const void * buf, size_t count)
1159 {
1160     LZFILE *lzfile;
1161     ssize_t rc = 0;
1162
1163     lzfile = lzdFileno(fd);
1164
1165     rc = lzwrite(lzfile, (void *)buf, count);
1166     if (rc < 0) {
1167         fd->errcookie = "Lzma: encoding error";
1168     }
1169     return rc;
1170 }
1171
1172 static int lzdClose(FD_t fd)
1173 {
1174     LZFILE *lzfile;
1175     int rc;
1176
1177     lzfile = lzdFileno(fd);
1178
1179     if (lzfile == NULL) return -2;
1180     rc = lzclose(lzfile);
1181
1182     /* XXX TODO: preserve fd if errors */
1183
1184     if (fd) {
1185         if (rc == -1) {
1186             fd->errcookie = "lzclose error";
1187             fd->syserrno = errno;
1188             fd->errcookie = strerror(fd->syserrno);
1189         }
1190     }
1191
1192     if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "XZDIO", stderr);
1193     if (rc == 0)
1194         fdFree(fd);
1195     return rc;
1196 }
1197
1198 static struct FDIO_s xzdio_s = {
1199   lzdRead, lzdWrite, NULL, lzdClose, NULL, NULL, NULL, fdFileno,
1200   NULL, xzdOpen, lzdFileno, lzdFlush, NULL
1201 };
1202 static const FDIO_t xzdio = &xzdio_s;
1203
1204 static struct FDIO_s lzdio_s = {
1205   lzdRead, lzdWrite, NULL, lzdClose, NULL, NULL, NULL, fdFileno,
1206   NULL, lzdOpen, lzdFileno, lzdFlush, NULL
1207 };
1208 static const FDIO_t lzdio = &lzdio_s;
1209
1210 #endif  /* HAVE_LZMA_H */
1211
1212 /* =============================================================== */
1213
1214 const char *Fstrerror(FD_t fd)
1215 {
1216     if (fd == NULL)
1217         return (errno ? strerror(errno) : "");
1218     return getFdErrstr(fd);
1219 }
1220
1221 #define FDIOVEC(_fd, _vec)      \
1222   ((fdGetIo(_fd) && fdGetIo(_fd)->_vec) ? fdGetIo(_fd)->_vec : NULL)
1223
1224 ssize_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
1225 {
1226     ssize_t rc = -1;
1227
1228     if (fd != NULL) {
1229         fdio_read_function_t _read = FDIOVEC(fd, read);
1230
1231         fdstat_enter(fd, FDSTAT_READ);
1232         do {
1233             rc = (_read ? (*_read) (fd, buf, size * nmemb) : -2);
1234         } while (rc == -1 && errno == EINTR);
1235         fdstat_exit(fd, FDSTAT_READ, rc);
1236
1237         if (fd->digests && rc > 0)
1238             fdUpdateDigests(fd, buf, rc);
1239     }
1240
1241     DBGIO(fd, (stderr, "==>\tFread(%p,%p,%ld) rc %ld %s\n",
1242           fd, buf, (long)size * nmemb, (long)rc, fdbg(fd)));
1243
1244     return rc;
1245 }
1246
1247 ssize_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
1248 {
1249     ssize_t rc = -1;
1250
1251     if (fd != NULL) {
1252         fdio_write_function_t _write = FDIOVEC(fd, write);
1253         
1254         fdstat_enter(fd, FDSTAT_WRITE);
1255         do {
1256             rc = (_write ? _write(fd, buf, size * nmemb) : -2);
1257         } while (rc == -1 && errno == EINTR);
1258         fdstat_exit(fd, FDSTAT_WRITE, rc);
1259
1260         if (fd->digests && rc > 0)
1261             fdUpdateDigests(fd, buf, rc);
1262     }
1263
1264     DBGIO(fd, (stderr, "==>\tFwrite(%p,%p,%ld) rc %ld %s\n",
1265           fd, buf, (long)size * nmemb, (long)rc, fdbg(fd)));
1266
1267     return rc;
1268 }
1269
1270 int Fseek(FD_t fd, off_t offset, int whence)
1271 {
1272     int rc = -1;
1273
1274     if (fd != NULL) {
1275         fdio_seek_function_t _seek = FDIOVEC(fd, seek);
1276
1277         fdstat_enter(fd, FDSTAT_SEEK);
1278         rc = (_seek ? _seek(fd, offset, whence) : -2);
1279         fdstat_exit(fd, FDSTAT_SEEK, rc);
1280     }
1281
1282     DBGIO(fd, (stderr, "==>\tFseek(%p,%ld,%d) rc %lx %s\n",
1283           fd, (long)offset, whence, (unsigned long)rc, fdbg(fd)));
1284
1285     return rc;
1286 }
1287
1288 int Fclose(FD_t fd)
1289 {
1290     int rc = 0, ec = 0;
1291
1292     if (fd == NULL)
1293         return -1;
1294
1295     fd = fdLink(fd);
1296     fdstat_enter(fd, FDSTAT_CLOSE);
1297     while (fd->nfps >= 0) {
1298         fdio_close_function_t _close = FDIOVEC(fd, close);
1299         rc = _close ? _close(fd) : -2;
1300
1301         if (fd->nfps == 0)
1302             break;
1303         if (ec == 0 && rc)
1304             ec = rc;
1305         fdPop(fd);
1306     }
1307     fdstat_exit(fd, FDSTAT_CLOSE, rc);
1308     DBGIO(fd, (stderr, "==>\tFclose(%p) rc %lx %s\n",
1309           (fd ? fd : NULL), (unsigned long)rc, fdbg(fd)));
1310
1311     fdFree(fd);
1312     return ec;
1313 }
1314
1315 /**
1316  * Convert stdio fmode to open(2) mode, filtering out zlib/bzlib flags.
1317  *      returns stdio[0] = NUL on error.
1318  *
1319  * - gzopen:    [0-9] is compression level
1320  * - gzopen:    'f' is filtered (Z_FILTERED)
1321  * - gzopen:    'h' is Huffman encoding (Z_HUFFMAN_ONLY)
1322  * - bzopen:    [1-9] is block size (modulo 100K)
1323  * - bzopen:    's' is smallmode
1324  * - HACK:      '.' terminates, rest is type of I/O
1325  */
1326 static void cvtfmode (const char *m,
1327                                 char *stdio, size_t nstdio,
1328                                 char *other, size_t nother,
1329                                 const char **end, int * f)
1330 {
1331     int flags = 0;
1332     char c;
1333
1334     switch (*m) {
1335     case 'a':
1336         flags |= O_WRONLY | O_CREAT | O_APPEND;
1337         if (--nstdio > 0) *stdio++ = *m;
1338         break;
1339     case 'w':
1340         flags |= O_WRONLY | O_CREAT | O_TRUNC;
1341         if (--nstdio > 0) *stdio++ = *m;
1342         break;
1343     case 'r':
1344         flags |= O_RDONLY;
1345         if (--nstdio > 0) *stdio++ = *m;
1346         break;
1347     default:
1348         *stdio = '\0';
1349         return;
1350         break;
1351     }
1352     m++;
1353
1354     while ((c = *m++) != '\0') {
1355         switch (c) {
1356         case '.':
1357             break;
1358         case '+':
1359             flags &= ~(O_RDONLY|O_WRONLY);
1360             flags |= O_RDWR;
1361             if (--nstdio > 0) *stdio++ = c;
1362             continue;
1363             break;
1364         case 'b':
1365             if (--nstdio > 0) *stdio++ = c;
1366             continue;
1367             break;
1368         case 'x':
1369             flags |= O_EXCL;
1370             if (--nstdio > 0) *stdio++ = c;
1371             continue;
1372             break;
1373         default:
1374             if (--nother > 0) *other++ = c;
1375             continue;
1376             break;
1377         }
1378         break;
1379     }
1380
1381     *stdio = *other = '\0';
1382     if (end != NULL)
1383         *end = (*m != '\0' ? m : NULL);
1384     if (f != NULL)
1385         *f = flags;
1386 }
1387
1388 FD_t Fdopen(FD_t ofd, const char *fmode)
1389 {
1390     char stdio[20], other[20], zstdio[40];
1391     const char *end = NULL;
1392     FDIO_t iof = NULL;
1393     FD_t fd = ofd;
1394
1395 if (_rpmio_debug)
1396 fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
1397
1398     if (fd == NULL || fmode == NULL)
1399         return NULL;
1400
1401     cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL);
1402     if (stdio[0] == '\0')
1403         return NULL;
1404     zstdio[0] = '\0';
1405     strncat(zstdio, stdio, sizeof(zstdio) - strlen(zstdio) - 1);
1406     strncat(zstdio, other, sizeof(zstdio) - strlen(zstdio) - 1);
1407
1408     if (end == NULL && other[0] == '\0')
1409         return fd;
1410
1411     if (end && *end) {
1412         if (rstreq(end, "fdio")) {
1413             iof = fdio;
1414         } else if (rstreq(end, "gzdio") || rstreq(end, "gzip")) {
1415             iof = gzdio;
1416             fd = gzdFdopen(fd, zstdio);
1417 #if HAVE_BZLIB_H
1418         } else if (rstreq(end, "bzdio") || rstreq(end, "bzip2")) {
1419             iof = bzdio;
1420             fd = bzdFdopen(fd, zstdio);
1421 #endif
1422 #if HAVE_LZMA_H
1423         } else if (rstreq(end, "xzdio") || rstreq(end, "xz")) {
1424             iof = xzdio;
1425             fd = xzdFdopen(fd, zstdio);
1426         } else if (rstreq(end, "lzdio") || rstreq(end, "lzma")) {
1427             iof = lzdio;
1428             fd = lzdFdopen(fd, zstdio);
1429 #endif
1430         } else if (rstreq(end, "ufdio")) {
1431             iof = ufdio;
1432         }
1433     } else if (other[0] != '\0') {
1434         for (end = other; *end && strchr("0123456789fh", *end); end++)
1435             {};
1436         if (*end == '\0') {
1437             iof = gzdio;
1438             fd = gzdFdopen(fd, zstdio);
1439         }
1440     }
1441     if (iof == NULL)
1442         return fd;
1443
1444 DBGIO(fd, (stderr, "==> Fdopen(%p,\"%s\") returns fd %p %s\n", ofd, fmode, (fd ? fd : NULL), fdbg(fd)));
1445     return fd;
1446 }
1447
1448 FD_t Fopen(const char *path, const char *fmode)
1449 {
1450     char stdio[20], other[20];
1451     const char *end = NULL;
1452     mode_t perms = 0666;
1453     int flags = 0;
1454     FD_t fd;
1455
1456     if (path == NULL || fmode == NULL)
1457         return NULL;
1458
1459     stdio[0] = '\0';
1460     cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, &flags);
1461     if (stdio[0] == '\0')
1462         return NULL;
1463
1464     if (end == NULL || rstreq(end, "fdio")) {
1465 if (_rpmio_debug)
1466 fprintf(stderr, "*** Fopen fdio path %s fmode %s\n", path, fmode);
1467         fd = fdOpen(path, flags, perms);
1468         if (fdFileno(fd) < 0) {
1469             if (fd) (void) fdClose(fd);
1470             return NULL;
1471         }
1472     } else {
1473         /* XXX gzdio and bzdio here too */
1474
1475         switch (urlIsURL(path)) {
1476         case URL_IS_HTTPS:
1477         case URL_IS_HTTP:
1478         case URL_IS_HKP:
1479         case URL_IS_PATH:
1480         case URL_IS_DASH:
1481         case URL_IS_FTP:
1482         case URL_IS_UNKNOWN:
1483 if (_rpmio_debug)
1484 fprintf(stderr, "*** Fopen ufdio path %s fmode %s\n", path, fmode);
1485             fd = ufdOpen(path, flags, perms);
1486             if (fd == NULL || !(fdFileno(fd) >= 0))
1487                 return fd;
1488             break;
1489         default:
1490 if (_rpmio_debug)
1491 fprintf(stderr, "*** Fopen WTFO path %s fmode %s\n", path, fmode);
1492             return NULL;
1493             break;
1494         }
1495
1496     }
1497
1498     if (fd)
1499         fd = Fdopen(fd, fmode);
1500
1501     DBGIO(fd, (stderr, "==>\tFopen(\"%s\",%x,0%o) %s\n",
1502           path, (unsigned)flags, (unsigned)perms, fdbg(fd)));
1503
1504     return fd;
1505 }
1506
1507 int Fflush(FD_t fd)
1508 {
1509     int rc = -1;
1510     if (fd != NULL) {
1511         fdio_fflush_function_t _fflush = FDIOVEC(fd, _fflush);
1512
1513         rc = (_fflush ? _fflush(fd) : -2);
1514     }
1515     return rc;
1516 }
1517
1518 off_t Ftell(FD_t fd)
1519 {
1520     off_t pos = -1;
1521     if (fd != NULL) {
1522         fdio_ftell_function_t _ftell = FDIOVEC(fd, _ftell);
1523
1524         pos = (_ftell ? _ftell(fd) : -2);
1525     }
1526     return pos;
1527 }
1528
1529 int Ferror(FD_t fd)
1530 {
1531     int i, rc = 0;
1532
1533     if (fd == NULL) return -1;
1534     for (i = fd->nfps; rc == 0 && i >= 0; i--) {
1535         FDSTACK_t * fps = &fd->fps[i];
1536         int ec;
1537         
1538         if (fps->io == gzdio) {
1539             ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
1540             i--;        /* XXX fdio under gzdio always has fdno == -1 */
1541 #if HAVE_BZLIB_H
1542         } else if (fps->io == bzdio) {
1543             ec = (fd->syserrno  || fd->errcookie != NULL) ? -1 : 0;
1544             i--;        /* XXX fdio under bzdio always has fdno == -1 */
1545 #endif
1546 #if HAVE_LZMA_H
1547         } else if (fps->io == xzdio || fps->io == lzdio) {
1548             ec = (fd->syserrno  || fd->errcookie != NULL) ? -1 : 0;
1549             i--;        /* XXX fdio under xzdio/lzdio always has fdno == -1 */
1550 #endif
1551         } else {
1552         /* XXX need to check ufdio/gzdio/bzdio/fdio errors correctly. */
1553             ec = (fdFileno(fd) < 0 ? -1 : 0);
1554         }
1555
1556         if (rc == 0 && ec)
1557             rc = ec;
1558     }
1559 DBGIO(fd, (stderr, "==> Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd)));
1560     return rc;
1561 }
1562
1563 int Fileno(FD_t fd)
1564 {
1565     int i, rc = -1;
1566
1567     if (fd == NULL) return -1;
1568     for (i = fd->nfps ; rc == -1 && i >= 0; i--) {
1569         rc = fd->fps[i].fdno;
1570     }
1571     
1572 DBGIO(fd, (stderr, "==> Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, fdbg(fd)));
1573     return rc;
1574 }
1575
1576 /* XXX this is naive */
1577 int Fcntl(FD_t fd, int op, void *lip)
1578 {
1579     return fcntl(Fileno(fd), op, lip);
1580 }
1581
1582 rpmop fdOp(FD_t fd, fdOpX opx)
1583 {
1584     rpmop op = NULL;
1585
1586     if (fd != NULL && fd->stats != NULL && opx >= 0 && opx < FDSTAT_MAX)
1587         op = fd->stats->ops + opx;
1588     return op;
1589 }
1590
1591 int rpmioSlurp(const char * fn, uint8_t ** bp, ssize_t * blenp)
1592 {
1593     static const ssize_t blenmax = (32 * BUFSIZ);
1594     ssize_t blen = 0;
1595     uint8_t * b = NULL;
1596     ssize_t size;
1597     FD_t fd;
1598     int rc = 0;
1599
1600     fd = Fopen(fn, "r.ufdio");
1601     if (fd == NULL || Ferror(fd)) {
1602         rc = 2;
1603         goto exit;
1604     }
1605
1606     size = fdSize(fd);
1607     blen = (size >= 0 ? size : blenmax);
1608     if (blen) {
1609         int nb;
1610         b = xmalloc(blen+1);
1611         b[0] = '\0';
1612         nb = Fread(b, sizeof(*b), blen, fd);
1613         if (Ferror(fd) || (size > 0 && nb != blen)) {
1614             rc = 1;
1615             goto exit;
1616         }
1617         if (blen == blenmax && nb < blen) {
1618             blen = nb;
1619             b = xrealloc(b, blen+1);
1620         }
1621         b[blen] = '\0';
1622     }
1623
1624 exit:
1625     if (fd) (void) Fclose(fd);
1626         
1627     if (rc) {
1628         if (b) free(b);
1629         b = NULL;
1630         blen = 0;
1631     }
1632
1633     if (bp) *bp = b;
1634     else if (b) free(b);
1635
1636     if (blenp) *blenp = blen;
1637
1638     return rc;
1639 }
1640
1641 void fdInitDigest(FD_t fd, int hashalgo, rpmDigestFlags flags)
1642 {
1643     if (fd->digests == NULL) {
1644         fd->digests = rpmDigestBundleNew();
1645     }
1646     fdstat_enter(fd, FDSTAT_DIGEST);
1647     rpmDigestBundleAdd(fd->digests, hashalgo, flags);
1648     fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);
1649 }
1650
1651 static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen)
1652 {
1653     if (fd && fd->digests) {
1654         fdstat_enter(fd, FDSTAT_DIGEST);
1655         rpmDigestBundleUpdate(fd->digests, buf, buflen);
1656         fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) buflen);
1657     }
1658 }
1659
1660 void fdFiniDigest(FD_t fd, int hashalgo,
1661                 void ** datap, size_t * lenp, int asAscii)
1662 {
1663     if (fd && fd->digests) {
1664         fdstat_enter(fd, FDSTAT_DIGEST);
1665         rpmDigestBundleFinal(fd->digests, hashalgo, datap, lenp, asAscii);
1666         fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);
1667     }
1668 }
1669
1670