Main Page Modules Data Structures File List Data Fields Globals Related Pages

# rpmio/rpmio.c

Go to the documentation of this file.

    00001 /*@-type@*/ /* LCL: function typedefs */
    00006 #include "system.h"
    00007 #include <stdarg.h>
    00008
    00009 #if HAVE_MACHINE_TYPES_H
    00010 # include <machine/types.h>
    00011 #endif
    00012
    00013 #include <netinet/in.h>
    00014 #include <arpa/inet.h>          /* XXX for inet_aton and HP-UX */
    00015
    00016 #if HAVE_NETINET_IN_SYSTM_H
    00017 # include <sys/types.h>
    00018
    00019 #if defined(__LCLINT__)
    00020 /*@-redef@*/ /* FIX: rpmdb/db3.c also declares */
    00021 typedef unsigned int u_int32_t;
    00022 typedef unsigned short u_int16_t;
    00023 typedef unsigned char u_int8_t;
    00024 /*@-incondefs@*/        /* LCLint 3.0.0.15 */
    00025 typedef int int32_t;
    00026 /*@=incondefs@*/
    00027 /*@=redef@*/
    00028 #endif
    00029
    00030 # include <netinet/in_systm.h>
    00031 #endif
    00032
    00033 #if HAVE_LIBIO_H && defined(_G_IO_IO_FILE_VERSION)
    00034 #define _USE_LIBIO      1
    00035 #endif
    00036
    00037 #if !defined(HAVE_HERRNO) && defined(__hpux) /* XXX HP-UX w/o -D_XOPEN_SOURCE needs */
    00038 /*@unchecked@*/
    00039 extern int h_errno;
    00040 #endif
    00041
    00042 #ifndef IPPORT_FTP
    00043 #define IPPORT_FTP      21
    00044 #endif
    00045 #ifndef IPPORT_HTTP
    00046 #define IPPORT_HTTP     80
    00047 #endif
    00048
    00049 #if !defined(HAVE_INET_ATON)
    00050 static int inet_aton(const char *cp, struct in_addr *inp)
    00051         /*@modifies *inp @*/
    00052 {
    00053     long addr;
    00054
    00055     addr = inet_addr(cp);
    00056     if (addr == ((long) -1)) return 0;
    00057
    00058     memcpy(inp, &addr, sizeof(addr));
    00059     return 1;
    00060 }
    00061 #endif
    00062
    00063 #if defined(USE_ALT_DNS) && USE_ALT_DNS
    00064 #include "dns.h"
    00065 #endif
    00066
    00067 #include <rpmio_internal.h>
    00068 #undef  fdFileno
    00069 #undef  fdOpen
    00070 #undef  fdRead
    00071 #undef  fdWrite
    00072 #undef  fdClose
    00073
    00074 #include "ugid.h"
    00075 #include "rpmmessages.h"
    00076
    00077 #include "debug.h"
    00078
    00079 /*@access urlinfo @*/
    00080 /*@access FDSTAT_t @*/
    00081
    00082 #define FDNREFS(fd)     (fd ? ((FD_t)fd)->nrefs : -9)
    00083 #define FDTO(fd)        (fd ? ((FD_t)fd)->rd_timeoutsecs : -99)
    00084 #define FDCPIOPOS(fd)   (fd ? ((FD_t)fd)->fd_cpioPos : -99)
    00085
    00086 #define FDONLY(fd)      assert(fdGetIo(fd) == fdio)
    00087 #define GZDONLY(fd)     assert(fdGetIo(fd) == gzdio)
    00088 #define BZDONLY(fd)     assert(fdGetIo(fd) == bzdio)
    00089
    00090 #define UFDONLY(fd)     /* assert(fdGetIo(fd) == ufdio) */
    00091
    00092 #define fdGetFILE(_fd)  ((FILE *)fdGetFp(_fd))
    00093
    00096 /*@unchecked@*/
    00097 #if _USE_LIBIO
    00098 int noLibio = 0;
    00099 #else
    00100 int noLibio = 1;
    00101 #endif
    00102
    00103 #define TIMEOUT_SECS 60
    00104
    00107 /*@unchecked@*/
    00108 static int ftpTimeoutSecs = TIMEOUT_SECS;
    00109
    00112 /*@unchecked@*/
    00113 static int httpTimeoutSecs = TIMEOUT_SECS;
    00114
    00117 /*@unchecked@*/
    00118 int _ftp_debug = 0;
    00119
    00122 /*@unchecked@*/
    00123 int _rpmio_debug = 0;
    00124
    00130 /*@unused@*/ static inline /*@null@*/ void *
    00131 _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p)
    00132         /*@modifies p@*/
    00133 {
    00134     if (p != NULL)      free((void *)p);
    00135     return NULL;
    00136 }
    00137
    00138 /* =============================================================== */
    00139
    00140 /*@-boundswrite@*/
    00141 /*@-modfilesys@*/
    00142 static /*@observer@*/ const char * fdbg(/*@null@*/ FD_t fd)
    00143         /*@*/
    00144 {
    00145     static char buf[BUFSIZ];
    00146     char *be = buf;
    00147     int i;
    00148
    00149     buf[0] = '\0';
    00150     if (fd == NULL)
    00151         return buf;
    00152
    00153 #if DYING
    00154     sprintf(be, "fd %p", fd);   be += strlen(be);
    00155     if (fd->rd_timeoutsecs >= 0) {
    00156         sprintf(be, " secs %d", fd->rd_timeoutsecs);
    00157         be += strlen(be);
    00158     }
    00159 #endif
    00160     if (fd->bytesRemain != -1) {
    00161         sprintf(be, " clen %d", (int)fd->bytesRemain);
    00162         be += strlen(be);
    00163      }
    00164     if (fd->wr_chunked) {
    00165         strcpy(be, " chunked");
    00166         be += strlen(be);
    00167      }
    00168     *be++ = '\t';
    00169     for (i = fd->nfps; i >= 0; i--) {
    00170         FDSTACK_t * fps = &fd->fps[i];
    00171         if (i != fd->nfps)
    00172             *be++ = ' ';
    00173         *be++ = '|';
    00174         *be++ = ' ';
    00175         if (fps->io == fdio) {
    00176             sprintf(be, "FD %d fp %p", fps->fdno, fps->fp);
    00177         } else if (fps->io == ufdio) {
    00178             sprintf(be, "UFD %d fp %p", fps->fdno, fps->fp);
    00179         } else if (fps->io == fadio) {
    00180             sprintf(be, "FAD %d fp %p", fps->fdno, fps->fp);
    00181         } else if (fps->io == gzdio) {
    00182             sprintf(be, "GZD %p fdno %d", fps->fp, fps->fdno);
    00183 #if HAVE_BZLIB_H
    00184         } else if (fps->io == bzdio) {
    00185             sprintf(be, "BZD %p fdno %d", fps->fp, fps->fdno);
    00186 #endif
    00187         } else if (fps->io == fpio) {
    00188             /*@+voidabstract@*/
    00189             sprintf(be, "%s %p(%d) fdno %d",
    00190                 (fps->fdno < 0 ? "LIBIO" : "FP"),
    00191                 fps->fp, fileno(((FILE *)fps->fp)), fps->fdno);
    00192             /*@=voidabstract@*/
    00193         } else {
    00194             sprintf(be, "??? io %p fp %p fdno %d ???",
    00195                 fps->io, fps->fp, fps->fdno);
    00196         }
    00197         be += strlen(be);
    00198         *be = '\0';
    00199     }
    00200     return buf;
    00201 }
    00202 /*@=modfilesys@*/
    00203 /*@=boundswrite@*/
    00204
    00205 /* =============================================================== */
    00206 off_t fdSize(FD_t fd)
    00207 {
    00208     struct stat sb;
    00209     off_t rc = -1;
    00210
    00211 #ifdef  NOISY
    00212 DBGIO(0, (stderr, "==>\tfdSize(%p) rc %ld\n", fd, (long)rc));
    00213 #endif
    00214     FDSANE(fd);
    00215     if (fd->contentLength >= 0)
    00216         rc = fd->contentLength;
    00217     else switch (fd->urlType) {
    00218     case URL_IS_PATH:
    00219     case URL_IS_UNKNOWN:
    00220         if (fstat(Fileno(fd), &sb) == 0)
    00221             rc = sb.st_size;
    00222         /*@fallthrough@*/
    00223     case URL_IS_FTP:
    00224     case URL_IS_HTTP:
    00225     case URL_IS_DASH:
    00226         break;
    00227     }
    00228     return rc;
    00229 }
    00230
    00231 FD_t fdDup(int fdno)
    00232 {
    00233     FD_t fd;
    00234     int nfdno;
    00235
    00236     if ((nfdno = dup(fdno)) < 0)
    00237         return NULL;
    00238     fd = fdNew("open (fdDup)");
    00239     fdSetFdno(fd, nfdno);
    00240 /*@-modfilesys@*/
    00241 DBGIO(fd, (stderr, "==> fdDup(%d) fd %p %s\n", fdno, (fd ? fd : NULL), fdbg(fd)));
    00242 /*@=modfilesys@*/
    00243     /*@-refcounttrans@*/ return fd; /*@=refcounttrans@*/
    00244 }
    00245
    00246 static inline /*@unused@*/ int fdSeekNot(void * cookie,
    00247                 /*@unused@*/ _libio_pos_t pos,  /*@unused@*/ int whence)
    00248         /*@*/
    00249 {
    00250     FD_t fd = c2f(cookie);
    00251     FDSANE(fd);         /* XXX keep gcc quiet */
    00252     return -2;
    00253 }
    00254
    00255 #ifdef UNUSED
    00256 FILE *fdFdopen(void * cookie, const char *fmode)
    00257 {
    00258     FD_t fd = c2f(cookie);
    00259     int fdno;
    00260     FILE * fp;
    00261
    00262     if (fmode == NULL) return NULL;
    00263     fdno = fdFileno(fd);
    00264     if (fdno < 0) return NULL;
    00265     fp = fdopen(fdno, fmode);
    00266 /*@-modfilesys@*/
    00267 DBGIO(fd, (stderr, "==> fdFdopen(%p,\"%s\") fdno %d -> fp %p fdno %d\n", cookie, fmode, fdno, fp, fileno(fp)));
    00268 /*@=modfilesys@*/
    00269     fd = fdFree(fd, "open (fdFdopen)");
    00270     return fp;
    00271 }
    00272 #endif
    00273
    00274 /* =============================================================== */
    00275 /*@-modfilesys@*/
    00276 /*@-mustmod@*/ /* FIX: cookie is modified */
    00277 static inline /*@null@*/ FD_t XfdLink(void * cookie, const char * msg,
    00278                 const char * file, unsigned line)
    00279         /*@modifies *cookie @*/
    00280 {
    00281     FD_t fd;
    00282 if (cookie == NULL)
    00283     /*@-castexpose@*/
    00284 DBGREFS(0, (stderr, "--> fd  %p ++ %d %s at %s:%u\n", cookie, FDNREFS(cookie)+1, msg, file, line));
    00285     /*@=castexpose@*/
    00286     fd = c2f(cookie);
    00287     if (fd) {
    00288         fd->nrefs++;
    00289 DBGREFS(fd, (stderr, "--> fd  %p ++ %d %s at %s:%u %s\n", fd, fd->nrefs, msg, file, line, fdbg(fd)));
    00290     }
    00291     return fd;
    00292 }
    00293 /*@=mustmod@*/
    00294 /*@=modfilesys@*/
    00295
    00296 /*@-modfilesys@*/
    00297 static inline /*@null@*/ FD_t XfdFree( /*@killref@*/ FD_t fd, const char *msg,
    00298                 const char *file, unsigned line)
    00299         /*@modifies fd @*/
    00300 {
    00301         int i;
    00302
    00303 if (fd == NULL)
    00304 DBGREFS(0, (stderr, "--> fd  %p -- %d %s at %s:%u\n", fd, FDNREFS(fd), msg, file, line));
    00305     FDSANE(fd);
    00306     if (fd) {
    00307 DBGREFS(fd, (stderr, "--> fd  %p -- %d %s at %s:%u %s\n", fd, fd->nrefs, msg, file, line, fdbg(fd)));
    00308         if (--fd->nrefs > 0)
    00309             /*@-refcounttrans -retalias@*/ return fd; /*@=refcounttrans =retalias@*/
    00310         fd->stats = _free(fd->stats);
    00311         for (i = fd->ndigests - 1; i >= 0; i--) {
    00312             FDDIGEST_t fddig = fd->digests + i;
    00313             if (fddig->hashctx == NULL)
    00314                 continue;
    00315             (void) rpmDigestFinal(fddig->hashctx, NULL, NULL, 0);
    00316             fddig->hashctx = NULL;
    00317         }
    00318         fd->ndigests = 0;
    00319         /*@-refcounttrans@*/ free(fd); /*@=refcounttrans@*/
    00320     }
    00321     return NULL;
    00322 }
    00323 /*@=modfilesys@*/
    00324
    00325 static inline /*@null@*/ FD_t XfdNew(const char * msg,
    00326                 const char * file, unsigned line)
    00327         /*@*/
    00328 {
    00329     FD_t fd = xcalloc(1, sizeof(*fd));
    00330     if (fd == NULL) /* XXX xmalloc never returns NULL */
    00331         return NULL;
    00332     fd->nrefs = 0;
    00333     fd->flags = 0;
    00334     fd->magic = FDMAGIC;
    00335     fd->urlType = URL_IS_UNKNOWN;
    00336
    00337     fd->nfps = 0;
    00338     memset(fd->fps, 0, sizeof(fd->fps));
    00339
    00340     /*@-assignexpose@*/
    00341     fd->fps[0].io = fdio;
    00342     /*@=assignexpose@*/
    00343     fd->fps[0].fp = NULL;
    00344     fd->fps[0].fdno = -1;
    00345
    00346     fd->url = NULL;
    00347     fd->rd_timeoutsecs = 1;     /* XXX default value used to be -1 */
    00348     fd->contentLength = fd->bytesRemain = -1;
    00349     fd->wr_chunked = 0;
    00350     fd->syserrno = 0;
    00351     fd->errcookie = NULL;
    00352     fd->stats = xcalloc(1, sizeof(*fd->stats));
    00353
    00354     fd->ndigests = 0;
    00355     memset(fd->digests, 0, sizeof(fd->digests));
    00356
    00357     (void) gettimeofday(&fd->stats->create, NULL);
    00358     fd->stats->begin = fd->stats->create;       /* structure assignment */
    00359
    00360     fd->ftpFileDoneNeeded = 0;
    00361     fd->firstFree = 0;
    00362     fd->fileSize = 0;
    00363     fd->fd_cpioPos = 0;
    00364
    00365     return XfdLink(fd, msg, file, line);
    00366 }
    00367
    00368 /*@-redef@*/    /* FIX: legacy API should be made static */
    00369 ssize_t fdRead(void * cookie, /*@out@*/ char * buf, size_t count)
    00370 /*@=redef@*/
    00371 {
    00372     FD_t fd = c2f(cookie);
    00373     ssize_t rc;
    00374
    00375     if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
    00376
    00377     fdstat_enter(fd, FDSTAT_READ);
    00378 /*@-boundswrite@*/
    00379     rc = read(fdFileno(fd), buf, (count > fd->bytesRemain ? fd->bytesRemain : count));
    00380 /*@=boundswrite@*/
    00381     fdstat_exit(fd, FDSTAT_READ, rc);
    00382
    00383     if (fd->ndigests && rc > 0) fdUpdateDigests(fd, buf, rc);
    00384
    00385 /*@-modfilesys@*/
    00386 DBGIO(fd, (stderr, "==>\tfdRead(%p,%p,%ld) rc %ld %s\n", cookie, buf, (long)count, (long)rc, fdbg(fd)));
    00387 /*@=modfilesys@*/
    00388
    00389     return rc;
    00390 }
    00391
    00392 /*@-redef@*/    /* FIX: legacy API should be made static */
    00393 ssize_t fdWrite(void * cookie, const char * buf, size_t count)
    00394 /*@=redef@*/
    00395 {
    00396     FD_t fd = c2f(cookie);
    00397     int fdno = fdFileno(fd);
    00398     ssize_t rc;
    00399
    00400     if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
    00401
    00402     if (fd->ndigests && count > 0) fdUpdateDigests(fd, buf, count);
    00403
    00404     if (fd->wr_chunked) {
    00405         char chunksize[20];
    00406         sprintf(chunksize, "%x\r\n", (unsigned)count);
    00407         rc = write(fdno, chunksize, strlen(chunksize));
    00408         if (rc == -1)   fd->syserrno = errno;
    00409     }
    00410     if (count == 0) return 0;
    00411
    00412     fdstat_enter(fd, FDSTAT_WRITE);
    00413 /*@-boundsread@*/
    00414     rc = write(fdno, buf, (count > fd->bytesRemain ? fd->bytesRemain : count));
    00415 /*@=boundsread@*/
    00416     fdstat_exit(fd, FDSTAT_WRITE, rc);
    00417
    00418     if (fd->wr_chunked) {
    00419         int ec;
    00420 /*@-boundsread@*/
    00421         ec = write(fdno, "\r\n", sizeof("\r\n")-1);
    00422 /*@=boundsread@*/
    00423         if (ec == -1)   fd->syserrno = errno;
    00424     }
    00425
    00426 /*@-modfilesys@*/
    00427 DBGIO(fd, (stderr, "==>\tfdWrite(%p,%p,%ld) rc %ld %s\n", cookie, buf, (long)count, (long)rc, fdbg(fd)));
    00428 /*@=modfilesys@*/
    00429
    00430     return rc;
    00431 }
    00432
    00433 static inline int fdSeek(void * cookie, _libio_pos_t pos, int whence)
    00434         /*@globals fileSystem, internalState @*/
    00435         /*@modifies fileSystem, internalState @*/
    00436 {
    00437 #ifdef USE_COOKIE_SEEK_POINTER
    00438     _IO_off64_t p = *pos;
    00439 #else
    00440     off_t p = pos;
    00441 #endif
    00442     FD_t fd = c2f(cookie);
    00443     off_t rc;
    00444
    00445     assert(fd->bytesRemain == -1);      /* XXX FIXME fadio only for now */
    00446     fdstat_enter(fd, FDSTAT_SEEK);
    00447     rc = lseek(fdFileno(fd), p, whence);
    00448     fdstat_exit(fd, FDSTAT_SEEK, rc);
    00449
    00450 /*@-modfilesys@*/
    00451 DBGIO(fd, (stderr, "==>\tfdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd)));
    00452 /*@=modfilesys@*/
    00453
    00454     return rc;
    00455 }
    00456
    00457 /*@-redef@*/    /* FIX: legacy API should be made static */
    00458 int fdClose( /*@only@*/ void * cookie)
    00459 /*@=redef@*/
    00460 {
    00461     FD_t fd;
    00462     int fdno;
    00463     int rc;
    00464
    00465     if (cookie == NULL) return -2;
    00466     fd = c2f(cookie);
    00467     fdno = fdFileno(fd);
    00468
    00469     fdSetFdno(fd, -1);
    00470
    00471     fdstat_enter(fd, FDSTAT_CLOSE);
    00472     rc = ((fdno >= 0) ? close(fdno) : -2);
    00473     fdstat_exit(fd, FDSTAT_CLOSE, rc);
    00474
    00475 /*@-modfilesys@*/
    00476 DBGIO(fd, (stderr, "==>\tfdClose(%p) rc %lx %s\n", (fd ? fd : NULL), (unsigned long)rc, fdbg(fd)));
    00477 /*@=modfilesys@*/
    00478
    00479     fd = fdFree(fd, "open (fdClose)");
    00480     return rc;
    00481 }
    00482
    00483 /*@-redef@*/    /* FIX: legacy API should be made static */
    00484 /*@null@*/ FD_t fdOpen(const char *path, int flags, mode_t mode)
    00485 /*@=redef@*/
    00486 {
    00487     FD_t fd;
    00488     int fdno;
    00489
    00490     fdno = open(path, flags, mode);
    00491     if (fdno < 0) return NULL;
    00492     if (fcntl(fdno, F_SETFD, FD_CLOEXEC)) {
    00493         (void) close(fdno);
    00494         return NULL;
    00495     }
    00496     fd = fdNew("open (fdOpen)");
    00497     fdSetFdno(fd, fdno);
    00498     fd->flags = flags;
    00499 /*@-modfilesys@*/
    00500 DBGIO(fd, (stderr, "==>\tfdOpen(\"%s\",%x,0%o) %s\n", path, (unsigned)flags, (unsigned)mode, fdbg(fd)));
    00501 /*@=modfilesys@*/
    00502     /*@-refcounttrans@*/ return fd; /*@=refcounttrans@*/
    00503 }
    00504
    00505 static struct FDIO_s fdio_s = {
    00506   fdRead, fdWrite, fdSeek, fdClose, XfdLink, XfdFree, XfdNew, fdFileno,
    00507   fdOpen, NULL, fdGetFp, NULL,  mkdir, chdir, rmdir, rename, unlink
    00508 };
    00509 FDIO_t fdio = /*@-compmempass@*/ &fdio_s /*@=compmempass@*/ ;
    00510
    00511 /*@-redef@*/    /* see lib/falloc.c */
    00512 FDIO_t fadio;   /* XXX usually NULL, filled in when linked with rpm */
    00513 /*@=redef@*/
    00514
    00515 int fdWritable(FD_t fd, int secs)
    00516 {
    00517     int fdno;
    00518     fd_set wrfds;
    00519     struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL);
    00520     int rc;
    00521
    00522     if ((fdno = fdFileno(fd)) < 0)
    00523         return -1;      /* XXX W2DO? */
    00524
    00525     FD_ZERO(&wrfds);
    00526     do {
    00527         FD_SET(fdno, &wrfds);
    00528
    00529         if (tvp) {
    00530             tvp->tv_sec = secs;
    00531             tvp->tv_usec = 0;
    00532         }
    00533         errno = 0;
    00534         /*@-compdef -nullpass@*/
    00535         rc = select(fdno + 1, NULL, &wrfds, NULL, tvp);
    00536         /*@=compdef =nullpass@*/
    00537
    00538 if (_rpmio_debug && !(rc == 1 && errno == 0))
    00539 fprintf(stderr, "*** fdWritable fdno %d rc %d %s\n", fdno, rc, strerror(errno));
    00540         if (rc < 0) {
    00541             switch (errno) {
    00542             case EINTR:
    00543                 continue;
    00544                 /*@notreached@*/ /*@switchbreak@*/ break;
    00545             default:
    00546                 return rc;
    00547                 /*@notreached@*/ /*@switchbreak@*/ break;
    00548             }
    00549         }
    00550         return rc;
    00551     } while (1);
    00552     /*@notreached@*/
    00553 }
    00554
    00555 int fdReadable(FD_t fd, int secs)
    00556 {
    00557     int fdno;
    00558     fd_set rdfds;
    00559     struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL);
    00560     int rc;
    00561
    00562     if ((fdno = fdFileno(fd)) < 0)
    00563         return -1;      /* XXX W2DO? */
    00564
    00565     FD_ZERO(&rdfds);
    00566     do {
    00567         FD_SET(fdno, &rdfds);
    00568
    00569         if (tvp) {
    00570             tvp->tv_sec = secs;
    00571             tvp->tv_usec = 0;
    00572         }
    00573         errno = 0;
    00574         /*@-compdef -nullpass@*/
    00575         rc = select(fdno + 1, &rdfds, NULL, NULL, tvp);
    00576         /*@=compdef =nullpass@*/
    00577
    00578         if (rc < 0) {
    00579             switch (errno) {
    00580             case EINTR:
    00581                 continue;
    00582                 /*@notreached@*/ /*@switchbreak@*/ break;
    00583             default:
    00584                 return rc;
    00585                 /*@notreached@*/ /*@switchbreak@*/ break;
    00586             }
    00587         }
    00588         return rc;
    00589     } while (1);
    00590     /*@notreached@*/
    00591 }
    00592
    00593 /*@-boundswrite@*/
    00594 int fdFgets(FD_t fd, char * buf, size_t len)
    00595 {
    00596     int fdno;
    00597     int secs = fd->rd_timeoutsecs;
    00598     size_t nb = 0;
    00599     int ec = 0;
    00600     char lastchar = '\0';
    00601
    00602     if ((fdno = fdFileno(fd)) < 0)
    00603         return 0;       /* XXX W2DO? */
    00604
    00605     do {
    00606         int rc;
    00607
    00608         /* Is there data to read? */
    00609         rc = fdReadable(fd, secs);
    00610
    00611         switch (rc) {
    00612         case -1:        /* error */
    00613             ec = -1;
    00614             continue;
    00615             /*@notreached@*/ /*@switchbreak@*/ break;
    00616         case  0:        /* timeout */
    00617             ec = -1;
    00618             continue;
    00619             /*@notreached@*/ /*@switchbreak@*/ break;
    00620         default:        /* data to read */
    00621             /*@switchbreak@*/ break;
    00622         }
    00623
    00624         errno = 0;
    00625 #ifdef  NOISY
    00626         rc = fdRead(fd, buf + nb, 1);
    00627 #else
    00628         rc = read(fdFileno(fd), buf + nb, 1);
    00629 #endif
    00630         if (rc < 0) {
    00631             fd->syserrno = errno;
    00632             switch (errno) {
    00633             case EWOULDBLOCK:
    00634                 continue;
    00635                 /*@notreached@*/ /*@switchbreak@*/ break;
    00636             default:
    00637                 /*@switchbreak@*/ break;
    00638             }
    00639 if (_rpmio_debug)
    00640 fprintf(stderr, "*** read: fd %p rc %d errno %d %s \"%s\"\n", fd, rc, errno, strerror(errno), buf);
    00641             ec = -1;
    00642             break;
    00643         } else if (rc == 0) {
    00644 if (_rpmio_debug)
    00645 fprintf(stderr, "*** read: fd %p rc %d EOF errno %d %s \"%s\"\n", fd, rc, errno, strerror(errno), buf);
    00646             break;
    00647         } else {
    00648             nb += rc;
    00649             buf[nb] = '\0';
    00650             lastchar = buf[nb - 1];
    00651         }
    00652     } while (ec == 0 && nb < len && lastchar != '\n');
    00653
    00654     return (ec >= 0 ? nb : ec);
    00655 }
    00656 /*@=boundswrite@*/
    00657
    00658 /* =============================================================== */
    00659 /* Support for FTP/HTTP I/O.
    00660  */
    00661 const char *const ftpStrerror(int errorNumber) {
    00662   switch (errorNumber) {
    00663     case 0:
    00664         return _("Success");
    00665
    00666     case FTPERR_BAD_SERVER_RESPONSE:
    00667         return _("Bad server response");
    00668
    00669     case FTPERR_SERVER_IO_ERROR:
    00670         return _("Server I/O error");
    00671
    00672     case FTPERR_SERVER_TIMEOUT:
    00673         return _("Server timeout");
    00674
    00675     case FTPERR_BAD_HOST_ADDR:
    00676         return _("Unable to lookup server host address");
    00677
    00678     case FTPERR_BAD_HOSTNAME:
    00679         return _("Unable to lookup server host name");
    00680
    00681     case FTPERR_FAILED_CONNECT:
    00682         return _("Failed to connect to server");
    00683
    00684     case FTPERR_FAILED_DATA_CONNECT:
    00685         return _("Failed to establish data connection to server");
    00686
    00687     case FTPERR_FILE_IO_ERROR:
    00688         return _("I/O error to local file");
    00689
    00690     case FTPERR_PASSIVE_ERROR:
    00691         return _("Error setting remote server to passive mode");
    00692
    00693     case FTPERR_FILE_NOT_FOUND:
    00694         return _("File not found on server");
    00695
    00696     case FTPERR_NIC_ABORT_IN_PROGRESS:
    00697         return _("Abort in progress");
    00698
    00699     case FTPERR_UNKNOWN:
    00700     default:
    00701         return _("Unknown or unexpected error");
    00702   }
    00703 }
    00704
    00705 const char *urlStrerror(const char *url)
    00706 {
    00707     const char *retstr;
    00708     /*@-branchstate@*/
    00709     switch (urlIsURL(url)) {
    00710     case URL_IS_FTP:
    00711     case URL_IS_HTTP:
    00712     {   urlinfo u;
    00713 /* XXX This only works for httpReq/ftpLogin/ftpReq failures */
    00714         if (urlSplit(url, &u) == 0) {
    00715             retstr = ftpStrerror(u->openError);
    00716         } else
    00717             retstr = "Malformed URL";
    00718     }   break;
    00719     default:
    00720         retstr = strerror(errno);
    00721         break;
    00722     }
    00723     /*@=branchstate@*/
    00724     return retstr;
    00725 }
    00726
    00727 #if !defined(USE_ALT_DNS) || !USE_ALT_DNS
    00728 static int mygethostbyname(const char * host,
    00729                 /*@out@*/ struct in_addr * address)
    00730         /*@modifies *address @*/
    00731 {
    00732     struct hostent * hostinfo;
    00733
    00734     /*@-unrecog -multithreaded @*/
    00735     /*@-globs@*/ /* FIX: h_errno access */
    00736     hostinfo = gethostbyname(host);
    00737     /*@=globs@*/
    00738     /*@=unrecog =multithreaded @*/
    00739     if (!hostinfo) return 1;
    00740
    00741 /*@-boundswrite@*/
    00742     /*@-nullderef@*/
    00743     memcpy(address, hostinfo->h_addr_list[0], sizeof(*address));
    00744     /*@=nullderef@*/
    00745 /*@=boundswrite@*/
    00746     return 0;
    00747 }
    00748 #endif
    00749
    00750 /*@-boundsread@*/
    00751 /*@-compdef@*/  /* FIX: address->s_addr undefined. */
    00752 static int getHostAddress(const char * host, /*@out@*/ struct in_addr * address)
    00753         /*@globals errno @*/
    00754         /*@modifies *address, errno @*/
    00755 {
    00756     if (xisdigit(host[0])) {
    00757         /*@-unrecog -moduncon @*/
    00758         if (!inet_aton(host, address))
    00759             return FTPERR_BAD_HOST_ADDR;
    00760         /*@=unrecog =moduncon @*/
    00761     } else {
    00762         /*@-globs@*/ /* FIX: h_errno access */
    00763         if (mygethostbyname(host, address)) {
    00764             errno = /*@-unrecog@*/ h_errno /*@=unrecog@*/;
    00765             return FTPERR_BAD_HOSTNAME;
    00766         }
    00767         /*@=globs@*/
    00768     }
    00769
    00770     return 0;
    00771 }
    00772 /*@=compdef@*/
    00773 /*@=boundsread@*/
    00774
    00775 static int tcpConnect(FD_t ctrl, const char * host, int port)
    00776         /*@globals fileSystem, internalState @*/
    00777         /*@modifies ctrl, fileSystem, internalState @*/
    00778 {
    00779     struct sockaddr_in sin;
    00780     int fdno = -1;
    00781     int rc;
    00782
    00783 /*@-boundswrite@*/
    00784     memset(&sin, 0, sizeof(sin));
    00785 /*@=boundswrite@*/
    00786     sin.sin_family = AF_INET;
    00787     sin.sin_port = htons(port);
    00788     sin.sin_addr.s_addr = INADDR_ANY;
    00789
    00790   do {
    00791     if ((rc = getHostAddress(host, &sin.sin_addr)) < 0)
    00792         break;
    00793
    00794     if ((fdno = socket(sin.sin_family, SOCK_STREAM, IPPROTO_IP)) < 0) {
    00795         rc = FTPERR_FAILED_CONNECT;
    00796         break;
    00797     }
    00798
    00799     /*@-internalglobs@*/
    00800     if (connect(fdno, (struct sockaddr *) &sin, sizeof(sin))) {
    00801         rc = FTPERR_FAILED_CONNECT;
    00802         break;
    00803     }
    00804     /*@=internalglobs@*/
    00805   } while (0);
    00806
    00807     if (rc < 0)
    00808         goto errxit;
    00809
    00810 if (_ftp_debug)
    00811 fprintf(stderr,"++ connect %s:%d on fdno %d\n",
    00812 /*@-unrecog -moduncon -evalorderuncon @*/
    00813 inet_ntoa(sin.sin_addr)
    00814 /*@=unrecog =moduncon =evalorderuncon @*/ ,
    00815 (int)ntohs(sin.sin_port), fdno);
    00816
    00817     fdSetFdno(ctrl, (fdno >= 0 ? fdno : -1));
    00818     return 0;
    00819
    00820 errxit:
    00821     /*@-observertrans@*/
    00822     fdSetSyserrno(ctrl, errno, ftpStrerror(rc));
    00823     /*@=observertrans@*/
    00824     if (fdno >= 0)
    00825         (void) close(fdno);
    00826     return rc;
    00827 }
    00828
    00829 /*@-boundswrite@*/
    00830 static int checkResponse(void * uu, FD_t ctrl,
    00831                 /*@out@*/ int *ecp, /*@out@*/ char ** str)
    00832         /*@globals fileSystem @*/
    00833         /*@modifies ctrl, *ecp, *str, fileSystem @*/
    00834 {
    00835     urlinfo u = uu;
    00836     char *buf;
    00837     size_t bufAlloced;
    00838     int bufLength = 0;
    00839     const char *s;
    00840     char *se;
    00841     int ec = 0;
    00842     int moretodo = 1;
    00843     char errorCode[4];
    00844
    00845     URLSANE(u);
    00846     if (u->bufAlloced == 0 || u->buf == NULL) {
    00847         u->bufAlloced = _url_iobuf_size;
    00848         u->buf = xcalloc(u->bufAlloced, sizeof(u->buf[0]));
    00849     }
    00850     buf = u->buf;
    00851     bufAlloced = u->bufAlloced;
    00852     *buf = '\0';
    00853
    00854     errorCode[0] = '\0';
    00855
    00856     do {
    00857         int rc;
    00858
    00859         /*
    00860          * Read next line from server.
    00861          */
    00862         se = buf + bufLength;
    00863         *se = '\0';
    00864         rc = fdFgets(ctrl, se, (bufAlloced - bufLength));
    00865         if (rc < 0) {
    00866             ec = FTPERR_BAD_SERVER_RESPONSE;
    00867             continue;
    00868         } else if (rc == 0 || fdWritable(ctrl, 0) < 1)
    00869             moretodo = 0;
    00870
    00871         /*
    00872          * Process next line from server.
    00873          */
    00874         for (s = se; *s != '\0'; s = se) {
    00875                 const char *e;
    00876
    00877                 while (*se && *se != '\n') se++;
    00878
    00879                 if (se > s && se[-1] == '\r')
    00880                    se[-1] = '\0';
    00881                 if (*se == '\0')
    00882                     /*@innerbreak@*/ break;
    00883
    00884 if (_ftp_debug)
    00885 fprintf(stderr, "<- %s\n", s);
    00886
    00887                 /* HTTP: header termination on empty line */
    00888                 if (*s == '\0') {
    00889                     moretodo = 0;
    00890                     /*@innerbreak@*/ break;
    00891                 }
    00892                 *se++ = '\0';
    00893
    00894                 /* HTTP: look for "HTTP/1.1 123 ..." */
    00895                 if (!strncmp(s, "HTTP", sizeof("HTTP")-1)) {
    00896                     ctrl->contentLength = -1;
    00897                     if ((e = strchr(s, '.')) != NULL) {
    00898                         e++;
    00899                         u->httpVersion = *e - '0';
    00900                         if (u->httpVersion < 1 || u->httpVersion > 2)
    00901                             ctrl->persist = u->httpVersion = 0;
    00902                         else
    00903                             ctrl->persist = 1;
    00904                     }
    00905                     if ((e = strchr(s, ' ')) != NULL) {
    00906                         e++;
    00907                         if (strchr("0123456789", *e))
    00908                             strncpy(errorCode, e, 3);
    00909                         errorCode[3] = '\0';
    00910                     }
    00911                     /*@innercontinue@*/ continue;
    00912                 }
    00913
    00914                 /* HTTP: look for "token: ..." */
    00915                 for (e = s; *e && !(*e == ' ' || *e == ':'); e++)
    00916                     {};
    00917                 if (e > s && *e++ == ':') {
    00918                     size_t ne = (e - s);
    00919                     while (*e && *e == ' ') e++;
    00920 #if 0
    00921                     if (!strncmp(s, "Date:", ne)) {
    00922                     } else
    00923                     if (!strncmp(s, "Server:", ne)) {
    00924                     } else
    00925                     if (!strncmp(s, "Last-Modified:", ne)) {
    00926                     } else
    00927                     if (!strncmp(s, "ETag:", ne)) {
    00928                     } else
    00929 #endif
    00930                     if (!strncmp(s, "Accept-Ranges:", ne)) {
    00931                         if (!strcmp(e, "bytes"))
    00932                             u->httpHasRange = 1;
    00933                         if (!strcmp(e, "none"))
    00934                             u->httpHasRange = 0;
    00935                     } else
    00936                     if (!strncmp(s, "Content-Length:", ne)) {
    00937                         if (strchr("0123456789", *e))
    00938                             ctrl->contentLength = atoi(e);
    00939                     } else
    00940                     if (!strncmp(s, "Connection:", ne)) {
    00941                         if (!strcmp(e, "close"))
    00942                             ctrl->persist = 0;
    00943                     }
    00944 #if 0
    00945                     else
    00946                     if (!strncmp(s, "Content-Type:", ne)) {
    00947                     } else
    00948                     if (!strncmp(s, "Transfer-Encoding:", ne)) {
    00949                         if (!strcmp(e, "chunked"))
    00950                             ctrl->wr_chunked = 1;
    00951                         else
    00952                             ctrl->wr_chunked = 0;
    00953                     } else
    00954                     if (!strncmp(s, "Allow:", ne)) {
    00955                     }
    00956 #endif
    00957                     /*@innercontinue@*/ continue;
    00958                 }
    00959
    00960                 /* HTTP: look for "<TITLE>501 ... </TITLE>" */
    00961                 if (!strncmp(s, "<TITLE>", sizeof("<TITLE>")-1))
    00962                     s += sizeof("<TITLE>") - 1;
    00963
    00964                 /* FTP: look for "123-" and/or "123 " */
    00965                 if (strchr("0123456789", *s)) {
    00966                     if (errorCode[0] != '\0') {
    00967                         if (!strncmp(s, errorCode, sizeof("123")-1) && s[3] == ' ')
    00968                             moretodo = 0;
    00969                     } else {
    00970                         strncpy(errorCode, s, sizeof("123")-1);
    00971                         errorCode[3] = '\0';
    00972                         if (s[3] != '-')
    00973                             moretodo = 0;
    00974                     }
    00975                 }
    00976         }
    00977
    00978         if (moretodo && se > s) {
    00979             bufLength = se - s - 1;
    00980             if (s != buf)
    00981                 memmove(buf, s, bufLength);
    00982         } else {
    00983             bufLength = 0;
    00984         }
    00985     } while (moretodo && ec == 0);
    00986
    00987     if (str)    *str = buf;
    00988     if (ecp)    *ecp = atoi(errorCode);
    00989
    00990     return ec;
    00991 }
    00992 /*@=boundswrite@*/
    00993
    00994 static int ftpCheckResponse(urlinfo u, /*@out@*/ char ** str)
    00995         /*@globals fileSystem @*/
    00996         /*@modifies u, *str, fileSystem @*/
    00997 {
    00998     int ec = 0;
    00999     int rc;
    01000
    01001     URLSANE(u);
    01002     rc = checkResponse(u, u->ctrl, &ec, str);
    01003
    01004     switch (ec) {
    01005     case 550:
    01006         return FTPERR_FILE_NOT_FOUND;
    01007         /*@notreached@*/ break;
    01008     case 552:
    01009         return FTPERR_NIC_ABORT_IN_PROGRESS;
    01010         /*@notreached@*/ break;
    01011     default:
    01012         if (ec >= 400 && ec <= 599) {
    01013             return FTPERR_BAD_SERVER_RESPONSE;
    01014         }
    01015         break;
    01016     }
    01017     return rc;
    01018 }
    01019
    01020 static int ftpCommand(urlinfo u, char ** str, ...)
    01021         /*@globals fileSystem @*/
    01022         /*@modifies u, *str, fileSystem @*/
    01023 {
    01024     va_list ap;
    01025     int len = 0;
    01026     const char * s, * t;
    01027     char * te;
    01028     int rc;
    01029
    01030     URLSANE(u);
    01031     va_start(ap, str);
    01032     while ((s = va_arg(ap, const char *)) != NULL) {
    01033         if (len) len++;
    01034         len += strlen(s);
    01035     }
    01036     len += sizeof("\r\n")-1;
    01037     va_end(ap);
    01038
    01039 /*@-boundswrite@*/
    01040     t = te = alloca(len + 1);
    01041
    01042     va_start(ap, str);
    01043     while ((s = va_arg(ap, const char *)) != NULL) {
    01044         if (te > t) *te++ = ' ';
    01045         te = stpcpy(te, s);
    01046     }
    01047     te = stpcpy(te, "\r\n");
    01048     va_end(ap);
    01049 /*@=boundswrite@*/
    01050
    01051 if (_ftp_debug)
    01052 fprintf(stderr, "-> %s", t);
    01053     if (fdWrite(u->ctrl, t, (te-t)) != (te-t))
    01054         return FTPERR_SERVER_IO_ERROR;
    01055
    01056     rc = ftpCheckResponse(u, str);
    01057     return rc;
    01058 }
    01059
    01060 static int ftpLogin(urlinfo u)
    01061         /*@globals fileSystem, internalState @*/
    01062         /*@modifies u, fileSystem, internalState @*/
    01063 {
    01064     const char * host;
    01065     const char * user;
    01066     const char * password;
    01067     int port;
    01068     int rc;
    01069
    01070     URLSANE(u);
    01071     u->ctrl = fdLink(u->ctrl, "open ctrl");
    01072
    01073     if (((host = (u->proxyh ? u->proxyh : u->host)) == NULL)) {
    01074         rc = FTPERR_BAD_HOSTNAME;
    01075         goto errxit;
    01076     }
    01077
    01078     if ((port = (u->proxyp > 0 ? u->proxyp : u->port)) < 0) port = IPPORT_FTP;
    01079
    01080     /*@-branchstate@*/
    01081     if ((user = (u->proxyu ? u->proxyu : u->user)) == NULL)
    01082         user = "anonymous";
    01083     /*@=branchstate@*/
    01084
    01085     /*@-branchstate@*/
    01086     if ((password = u->password) == NULL) {
    01087         uid_t uid = getuid();
    01088         struct passwd * pw;
    01089         if (uid && (pw = getpwuid(uid)) != NULL) {
    01090 /*@-boundswrite@*/
    01091             char *myp = alloca(strlen(pw->pw_name) + sizeof("@"));
    01092             strcpy(myp, pw->pw_name);
    01093             strcat(myp, "@");
    01094 /*@=boundswrite@*/
    01095             password = myp;
    01096         } else {
    01097             password = "root@";
    01098         }
    01099     }
    01100     /*@=branchstate@*/
    01101
    01102     /*@-branchstate@*/
    01103     if (fdFileno(u->ctrl) >= 0 && fdWritable(u->ctrl, 0) < 1)
    01104         /*@-refcounttrans@*/ (void) fdClose(u->ctrl); /*@=refcounttrans@*/
    01105     /*@=branchstate@*/
    01106
    01107 /*@-usereleased@*/
    01108     if (fdFileno(u->ctrl) < 0) {
    01109         rc = tcpConnect(u->ctrl, host, port);
    01110         if (rc < 0)
    01111             goto errxit2;
    01112     }
    01113
    01114     if ((rc = ftpCheckResponse(u, NULL)))
    01115         goto errxit;
    01116
    01117     if ((rc = ftpCommand(u, NULL, "USER", user, NULL)))
    01118         goto errxit;
    01119
    01120     if ((rc = ftpCommand(u, NULL, "PASS", password, NULL)))
    01121         goto errxit;
    01122
    01123     if ((rc = ftpCommand(u, NULL, "TYPE", "I", NULL)))
    01124         goto errxit;
    01125
    01126     /*@-compdef@*/
    01127     return 0;
    01128     /*@=compdef@*/
    01129
    01130 errxit:
    01131     /*@-observertrans@*/
    01132     fdSetSyserrno(u->ctrl, errno, ftpStrerror(rc));
    01133     /*@=observertrans@*/
    01134 errxit2:
    01135     /*@-branchstate@*/
    01136     if (fdFileno(u->ctrl) >= 0)
    01137         /*@-refcounttrans@*/ (void) fdClose(u->ctrl); /*@=refcounttrans@*/
    01138     /*@=branchstate@*/
    01139     /*@-compdef@*/
    01140     return rc;
    01141     /*@=compdef@*/
    01142 /*@=usereleased@*/
    01143 }
    01144
    01145 int ftpReq(FD_t data, const char * ftpCmd, const char * ftpArg)
    01146 {
    01147     urlinfo u = data->url;
    01148     struct sockaddr_in dataAddress;
    01149     char * cmd;
    01150     int cmdlen;
    01151     char * passReply;
    01152     char * chptr;
    01153     int rc;
    01154
    01155 /*@-boundswrite@*/
    01156     URLSANE(u);
    01157     if (ftpCmd == NULL)
    01158         return FTPERR_UNKNOWN;  /* XXX W2DO? */
    01159
    01160     cmdlen = strlen(ftpCmd) + (ftpArg ? 1+strlen(ftpArg) : 0) + sizeof("\r\n");
    01161     chptr = cmd = alloca(cmdlen);
    01162     chptr = stpcpy(chptr, ftpCmd);
    01163     if (ftpArg) {
    01164         *chptr++ = ' ';
    01165         chptr = stpcpy(chptr, ftpArg);
    01166     }
    01167     chptr = stpcpy(chptr, "\r\n");
    01168     cmdlen = chptr - cmd;
    01169
    01170 /*
    01171  * Get the ftp version of the Content-Length.
    01172  */
    01173     if (!strncmp(cmd, "RETR", 4)) {
    01174         unsigned cl;
    01175
    01176         passReply = NULL;
    01177         rc = ftpCommand(u, &passReply, "SIZE", ftpArg, NULL);
    01178         if (rc)
    01179             goto errxit;
    01180         if (sscanf(passReply, "%d %u", &rc, &cl) != 2) {
    01181             rc = FTPERR_BAD_SERVER_RESPONSE;
    01182             goto errxit;
    01183         }
    01184         rc = 0;
    01185         data->contentLength = cl;
    01186     }
    01187
    01188     passReply = NULL;
    01189     rc = ftpCommand(u, &passReply, "PASV", NULL);
    01190     if (rc) {
    01191         rc = FTPERR_PASSIVE_ERROR;
    01192         goto errxit;
    01193     }
    01194
    01195     chptr = passReply;
    01196     while (*chptr && *chptr != '(') chptr++;
    01197     if (*chptr != '(') return FTPERR_PASSIVE_ERROR;
    01198     chptr++;
    01199     passReply = chptr;
    01200     while (*chptr && *chptr != ')') chptr++;
    01201     if (*chptr != ')') return FTPERR_PASSIVE_ERROR;
    01202     *chptr-- = '\0';
    01203
    01204     while (*chptr && *chptr != ',') chptr--;
    01205     if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
    01206     chptr--;
    01207     while (*chptr && *chptr != ',') chptr--;
    01208     if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
    01209     *chptr++ = '\0';
    01210
    01211     /* now passReply points to the IP portion, and chptr points to the
    01212        port number portion */
    01213
    01214     {   int i, j;
    01215         memset(&dataAddress, 0, sizeof(dataAddress));
    01216         dataAddress.sin_family = AF_INET;
    01217         if (sscanf(chptr, "%d,%d", &i, &j) != 2) {
    01218             rc = FTPERR_PASSIVE_ERROR;
    01219             goto errxit;
    01220         }
    01221         dataAddress.sin_port = htons((((unsigned)i) << 8) + j);
    01222     }
    01223
    01224     chptr = passReply;
    01225     while (*chptr++ != '\0') {
    01226         if (*chptr == ',') *chptr = '.';
    01227     }
    01228 /*@=boundswrite@*/
    01229
    01230     /*@-moduncon@*/
    01231     if (!inet_aton(passReply, &dataAddress.sin_addr)) {
    01232         rc = FTPERR_PASSIVE_ERROR;
    01233         goto errxit;
    01234     }
    01235     /*@=moduncon@*/
    01236
    01237     rc = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    01238     fdSetFdno(data, (rc >= 0 ? rc : -1));
    01239     if (rc < 0) {
    01240         rc = FTPERR_FAILED_CONNECT;
    01241         goto errxit;
    01242     }
    01243     data = fdLink(data, "open data (ftpReq)");
    01244
    01245     /* XXX setsockopt SO_LINGER */
    01246     /* XXX setsockopt SO_KEEPALIVE */
    01247     /* XXX setsockopt SO_TOS IPTOS_THROUGHPUT */
    01248
    01249     /*@-internalglobs@*/
    01250     while (connect(fdFileno(data), (struct sockaddr *) &dataAddress,
    01251                 sizeof(dataAddress)) < 0)
    01252     {
    01253         if (errno == EINTR)
    01254             continue;
    01255         rc = FTPERR_FAILED_DATA_CONNECT;
    01256         goto errxit;
    01257     }
    01258     /*@=internalglobs@*/
    01259
    01260 if (_ftp_debug)
    01261 fprintf(stderr, "-> %s", cmd);
    01262     if (fdWrite(u->ctrl, cmd, cmdlen) != cmdlen) {
    01263         rc = FTPERR_SERVER_IO_ERROR;
    01264         goto errxit;
    01265     }
    01266
    01267     if ((rc = ftpCheckResponse(u, NULL))) {
    01268         goto errxit;
    01269     }
    01270
    01271     data->ftpFileDoneNeeded = 1;
    01272     u->ctrl = fdLink(u->ctrl, "grab data (ftpReq)");
    01273     u->ctrl = fdLink(u->ctrl, "open data (ftpReq)");
    01274     return 0;
    01275
    01276 errxit:
    01277     /*@-observertrans@*/
    01278     fdSetSyserrno(u->ctrl, errno, ftpStrerror(rc));
    01279     /*@=observertrans@*/
    01280     /*@-branchstate@*/
    01281     if (fdFileno(data) >= 0)
    01282         /*@-refcounttrans@*/ (void) fdClose(data); /*@=refcounttrans@*/
    01283     /*@=branchstate@*/
    01284     return rc;
    01285 }
    01286
    01287 /*@unchecked@*/ /*@null@*/
    01288 static rpmCallbackFunction      urlNotify = NULL;
    01289
    01290 /*@unchecked@*/ /*@null@*/
    01291 static void *                   urlNotifyData = NULL;
    01292
    01293 /*@unchecked@*/
    01294 static int                      urlNotifyCount = -1;
    01295
    01296 void urlSetCallback(rpmCallbackFunction notify, void *notifyData, int notifyCount) {
    01297     urlNotify = notify;
    01298     urlNotifyData = notifyData;
    01299     urlNotifyCount = (notifyCount >= 0) ? notifyCount : 4096;
    01300 }
    01301
    01302 int ufdCopy(FD_t sfd, FD_t tfd)
    01303 {
    01304     char buf[BUFSIZ];
    01305     int itemsRead;
    01306     int itemsCopied = 0;
    01307     int rc = 0;
    01308     int notifier = -1;
    01309
    01310     if (urlNotify) {
    01311 /*@-boundsread@*/
    01312         /*@-noeffectuncon @*/ /* FIX: check rc */
    01313         (void)(*urlNotify) (NULL, RPMCALLBACK_INST_OPEN_FILE,
    01314                 0, 0, NULL, urlNotifyData);
    01315         /*@=noeffectuncon @*/
    01316 /*@=boundsread@*/
    01317     }
    01318
    01319     while (1) {
    01320         rc = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd);
    01321         if (rc < 0)
    01322             break;
    01323         else if (rc == 0) {
    01324             rc = itemsCopied;
    01325             break;
    01326         }
    01327         itemsRead = rc;
    01328         rc = Fwrite(buf, sizeof(buf[0]), itemsRead, tfd);
    01329         if (rc < 0)
    01330             break;
    01331         if (rc != itemsRead) {
    01332             rc = FTPERR_FILE_IO_ERROR;
    01333             break;
    01334         }
    01335
    01336         itemsCopied += itemsRead;
    01337         if (urlNotify && urlNotifyCount > 0) {
    01338             int n = itemsCopied/urlNotifyCount;
    01339             if (n != notifier) {
    01340 /*@-boundsread@*/
    01341                 /*@-noeffectuncon @*/ /* FIX: check rc */
    01342                 (void)(*urlNotify) (NULL, RPMCALLBACK_INST_PROGRESS,
    01343                         itemsCopied, 0, NULL, urlNotifyData);
    01344                 /*@=noeffectuncon @*/
    01345 /*@=boundsread@*/
    01346                 notifier = n;
    01347             }
    01348         }
    01349     }
    01350
    01351 /*@-modfilesys@*/
    01352     DBGIO(sfd, (stderr, "++ copied %d bytes: %s\n", itemsCopied,
    01353         ftpStrerror(rc)));
    01354 /*@=modfilesys@*/
    01355
    01356     if (urlNotify) {
    01357 /*@-boundsread@*/
    01358         /*@-noeffectuncon @*/ /* FIX: check rc */
    01359         (void)(*urlNotify) (NULL, RPMCALLBACK_INST_OPEN_FILE,
    01360                 itemsCopied, itemsCopied, NULL, urlNotifyData);
    01361         /*@=noeffectuncon @*/
    01362 /*@=boundsread@*/
    01363     }
    01364
    01365     return rc;
    01366 }
    01367
    01368 static int urlConnect(const char * url, /*@out@*/ urlinfo * uret)
    01369         /*@globals fileSystem, internalState @*/
    01370         /*@modifies *uret, fileSystem, internalState @*/
    01371 {
    01372     urlinfo u;
    01373     int rc = 0;
    01374
    01375     if (urlSplit(url, &u) < 0)
    01376         return -1;
    01377
    01378     if (u->urltype == URL_IS_FTP) {
    01379         FD_t fd;
    01380
    01381         if ((fd = u->ctrl) == NULL) {
    01382             fd = u->ctrl = fdNew("persist ctrl (urlConnect FTP)");
    01383             fdSetIo(u->ctrl, ufdio);
    01384         }
    01385
    01386         fd->rd_timeoutsecs = ftpTimeoutSecs;
    01387         fd->contentLength = fd->bytesRemain = -1;
    01388         fd->url = NULL;         /* XXX FTP ctrl has not */
    01389         fd->ftpFileDoneNeeded = 0;
    01390         fd = fdLink(fd, "grab ctrl (urlConnect FTP)");
    01391
    01392         if (fdFileno(u->ctrl) < 0) {
    01393             rpmMessage(RPMMESS_DEBUG, _("logging into %s as %s, pw %s\n"),
    01394                         u->host ? u->host : "???",
    01395                         u->user ? u->user : "ftp",
    01396                         u->password ? u->password : "(username)");
    01397
    01398             if ((rc = ftpLogin(u)) < 0) {       /* XXX save ftpLogin error */
    01399                 u->ctrl = fdFree(fd, "grab ctrl (urlConnect FTP)");
    01400                 u->openError = rc;
    01401             }
    01402         }
    01403     }
    01404
    01405 /*@-boundswrite@*/
    01406     if (uret != NULL)
    01407         *uret = urlLink(u, "urlConnect");
    01408 /*@=boundswrite@*/
    01409     u = urlFree(u, "urlSplit (urlConnect)");
    01410
    01411     return rc;
    01412 }
    01413
    01414 int ufdGetFile(FD_t sfd, FD_t tfd)
    01415 {
    01416     int rc;
    01417
    01418     FDSANE(sfd);
    01419     FDSANE(tfd);
    01420     rc = ufdCopy(sfd, tfd);
    01421     (void) Fclose(sfd);
    01422     if (rc > 0)         /* XXX ufdCopy now returns no. bytes copied */
    01423         rc = 0;
    01424     return rc;
    01425 }
    01426
    01427 int ftpCmd(const char * cmd, const char * url, const char * arg2)
    01428 {
    01429     urlinfo u;
    01430     int rc;
    01431     const char * path;
    01432
    01433     if (urlConnect(url, &u) < 0)
    01434         return -1;
    01435
    01436     (void) urlPath(url, &path);
    01437
    01438     rc = ftpCommand(u, NULL, cmd, path, arg2, NULL);
    01439     u->ctrl = fdFree(u->ctrl, "grab ctrl (ftpCmd)");
    01440     return rc;
    01441 }
    01442
    01443 /* XXX these aren't worth the pain of including correctly */
    01444 #if !defined(IAC)
    01445 #define IAC     255             /* interpret as command: */
    01446 #endif
    01447 #if !defined(IP)
    01448 #define IP      244             /* interrupt process--permanently */
    01449 #endif
    01450 #if !defined(DM)
    01451 #define DM      242             /* data mark--for connect. cleaning */
    01452 #endif
    01453 #if !defined(SHUT_RDWR)
    01454 #define SHUT_RDWR       1+1
    01455 #endif
    01456
    01457 static int ftpAbort(urlinfo u, FD_t data)
    01458         /*@globals fileSystem, internalState @*/
    01459         /*@modifies u, data, fileSystem, internalState @*/
    01460 {
    01461     static unsigned char ipbuf[3] = { IAC, IP, IAC };
    01462     FD_t ctrl;
    01463     int rc;
    01464     int tosecs;
    01465
    01466     URLSANE(u);
    01467
    01468     if (data != NULL) {
    01469         data->ftpFileDoneNeeded = 0;
    01470         if (fdFileno(data) >= 0)
    01471             u->ctrl = fdFree(u->ctrl, "open data (ftpAbort)");
    01472         u->ctrl = fdFree(u->ctrl, "grab data (ftpAbort)");
    01473     }
    01474     ctrl = u->ctrl;
    01475
    01476 /*@-modfilesys@*/
    01477     DBGIO(0, (stderr, "-> ABOR\n"));
    01478 /*@=modfilesys@*/
    01479
    01480 /*@-usereleased -compdef@*/
    01481     if (send(fdFileno(ctrl), ipbuf, sizeof(ipbuf), MSG_OOB) != sizeof(ipbuf)) {
    01482         /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
    01483         return FTPERR_SERVER_IO_ERROR;
    01484     }
    01485
    01486     sprintf(u->buf, "%cABOR\r\n",(char) DM);
    01487     if (fdWrite(ctrl, u->buf, 7) != 7) {
    01488         /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
    01489         return FTPERR_SERVER_IO_ERROR;
    01490     }
    01491
    01492     if (data && fdFileno(data) >= 0) {
    01493         /* XXX shorten data drain time wait */
    01494         tosecs = data->rd_timeoutsecs;
    01495         data->rd_timeoutsecs = 10;
    01496         if (fdReadable(data, data->rd_timeoutsecs) > 0) {
    01497 /*@-boundswrite@*/
    01498             while (timedRead(data, u->buf, u->bufAlloced) > 0)
    01499                 u->buf[0] = '\0';
    01500 /*@=boundswrite@*/
    01501         }
    01502         data->rd_timeoutsecs = tosecs;
    01503         /* XXX ftp abort needs to close the data channel to receive status */
    01504         (void) shutdown(fdFileno(data), SHUT_RDWR);
    01505         (void) close(fdFileno(data));
    01506         data->fps[0].fdno = -1; /* XXX WRONG but expedient */
    01507     }
    01508
    01509     /* XXX shorten ctrl drain time wait */
    01510     tosecs = u->ctrl->rd_timeoutsecs;
    01511     u->ctrl->rd_timeoutsecs = 10;
    01512     if ((rc = ftpCheckResponse(u, NULL)) == FTPERR_NIC_ABORT_IN_PROGRESS) {
    01513         rc = ftpCheckResponse(u, NULL);
    01514     }
    01515     rc = ftpCheckResponse(u, NULL);
    01516     u->ctrl->rd_timeoutsecs = tosecs;
    01517
    01518     return rc;
    01519 /*@=usereleased =compdef@*/
    01520 }
    01521
    01522 static int ftpFileDone(urlinfo u, FD_t data)
    01523         /*@globals fileSystem @*/
    01524         /*@modifies u, data, fileSystem @*/
    01525 {
    01526     int rc = 0;
    01527
    01528     URLSANE(u);
    01529     assert(data->ftpFileDoneNeeded);
    01530
    01531     if (data->ftpFileDoneNeeded) {
    01532         data->ftpFileDoneNeeded = 0;
    01533         u->ctrl = fdFree(u->ctrl, "open data (ftpFileDone)");
    01534         u->ctrl = fdFree(u->ctrl, "grab data (ftpFileDone)");
    01535         rc = ftpCheckResponse(u, NULL);
    01536     }
    01537     return rc;
    01538 }
    01539
    01540 static int httpResp(urlinfo u, FD_t ctrl, /*@out@*/ char ** str)
    01541         /*@globals fileSystem @*/
    01542         /*@modifies ctrl, *str, fileSystem @*/
    01543 {
    01544     int ec = 0;
    01545     int rc;
    01546
    01547     URLSANE(u);
    01548     rc = checkResponse(u, ctrl, &ec, str);
    01549
    01550 if (_ftp_debug && !(rc == 0 && ec == 200))
    01551 fprintf(stderr, "*** httpResp: rc %d ec %d\n", rc, ec);
    01552
    01553     switch (ec) {
    01554     case 200:
    01555         break;
    01556     default:
    01557         rc = FTPERR_FILE_NOT_FOUND;
    01558         break;
    01559     }
    01560
    01561     return rc;
    01562 }
    01563
    01564 static int httpReq(FD_t ctrl, const char * httpCmd, const char * httpArg)
    01565         /*@globals fileSystem, internalState @*/
    01566         /*@modifies ctrl, fileSystem, internalState @*/
    01567 {
    01568     urlinfo u = ctrl->url;
    01569     const char * host;
    01570     const char * path;
    01571     int port;
    01572     int rc;
    01573     char * req;
    01574     size_t len;
    01575     int retrying = 0;
    01576
    01577     URLSANE(u);
    01578     assert(ctrl != NULL);
    01579
    01580     if (((host = (u->proxyh ? u->proxyh : u->host)) == NULL))
    01581         return FTPERR_BAD_HOSTNAME;
    01582
    01583     if ((port = (u->proxyp > 0 ? u->proxyp : u->port)) < 0) port = 80;
    01584     path = (u->proxyh || u->proxyp > 0) ? u->url : httpArg;
    01585     /*@-branchstate@*/
    01586     if (path == NULL) path = "";
    01587     /*@=branchstate@*/
    01588
    01589 reopen:
    01590     /*@-branchstate@*/
    01591     if (fdFileno(ctrl) >= 0 && (rc = fdWritable(ctrl, 0)) < 1) {
    01592         /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
    01593     }
    01594     /*@=branchstate@*/
    01595
    01596 /*@-usereleased@*/
    01597     if (fdFileno(ctrl) < 0) {
    01598         rc = tcpConnect(ctrl, host, port);
    01599         if (rc < 0)
    01600             goto errxit2;
    01601         ctrl = fdLink(ctrl, "open ctrl (httpReq)");
    01602     }
    01603
    01604     len = sizeof("\
    01605 req x HTTP/1.0\r\n\
    01606 User-Agent: rpm/3.0.4\r\n\
    01607 Host: y:z\r\n\
    01608 Accept: text/plain\r\n\
    01609 Transfer-Encoding: chunked\r\n\
    01610 \r\n\
    01611 ") + strlen(httpCmd) + strlen(path) + sizeof(VERSION) + strlen(host) + 20;
    01612
    01613 /*@-boundswrite@*/
    01614     req = alloca(len);
    01615     *req = '\0';
    01616
    01617   if (!strcmp(httpCmd, "PUT")) {
    01618     sprintf(req, "\
    01619 %s %s HTTP/1.%d\r\n\
    01620 User-Agent: rpm/%s\r\n\
    01621 Host: %s:%d\r\n\
    01622 Accept: text/plain\r\n\
    01623 Transfer-Encoding: chunked\r\n\
    01624 \r\n\
    01625 ",      httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, host, port);
    01626 } else {
    01627     sprintf(req, "\
    01628 %s %s HTTP/1.%d\r\n\
    01629 User-Agent: rpm/%s\r\n\
    01630 Host: %s:%d\r\n\
    01631 Accept: text/plain\r\n\
    01632 \r\n\
    01633 ",      httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, host, port);
    01634 }
    01635 /*@=boundswrite@*/
    01636
    01637 if (_ftp_debug)
    01638 fprintf(stderr, "-> %s", req);
    01639
    01640     len = strlen(req);
    01641     if (fdWrite(ctrl, req, len) != len) {
    01642         rc = FTPERR_SERVER_IO_ERROR;
    01643         goto errxit;
    01644     }
    01645
    01646     /*@-branchstate@*/
    01647     if (!strcmp(httpCmd, "PUT")) {
    01648         ctrl->wr_chunked = 1;
    01649     } else {
    01650
    01651         rc = httpResp(u, ctrl, NULL);
    01652
    01653         if (rc) {
    01654             if (!retrying) {    /* not HTTP_OK */
    01655                 retrying = 1;
    01656                 /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
    01657                 goto reopen;
    01658             }
    01659             goto errxit;
    01660         }
    01661     }
    01662     /*@=branchstate@*/
    01663
    01664     ctrl = fdLink(ctrl, "open data (httpReq)");
    01665     return 0;
    01666
    01667 errxit:
    01668     /*@-observertrans@*/
    01669     fdSetSyserrno(ctrl, errno, ftpStrerror(rc));
    01670     /*@=observertrans@*/
    01671 errxit2:
    01672     /*@-branchstate@*/
    01673     if (fdFileno(ctrl) >= 0)
    01674         /*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
    01675     /*@=branchstate@*/
    01676     return rc;
    01677 /*@=usereleased@*/
    01678 }
    01679
    01680 /* XXX DYING: unused */
    01681 void * ufdGetUrlinfo(FD_t fd)
    01682 {
    01683     FDSANE(fd);
    01684     if (fd->url == NULL)
    01685         return NULL;
    01686     return urlLink(fd->url, "ufdGetUrlinfo");
    01687 }
    01688
    01689 /* =============================================================== */
    01690 static ssize_t ufdRead(void * cookie, /*@out@*/ char * buf, size_t count)
    01691         /*@globals fileSystem, internalState @*/
    01692         /*@modifies *buf, fileSystem, internalState @*/
    01693         /*@requires maxSet(buf) >= (count - 1) @*/
    01694         /*@ensures maxRead(buf) == result @*/
    01695 {
    01696     FD_t fd = c2f(cookie);
    01697     int bytesRead;
    01698     int total;
    01699
    01700     /* XXX preserve timedRead() behavior */
    01701     if (fdGetIo(fd) == fdio) {
    01702         struct stat sb;
    01703         int fdno = fdFileno(fd);
    01704         (void) fstat(fdno, &sb);
    01705         if (S_ISREG(sb.st_mode))
    01706             return fdRead(fd, buf, count);
    01707     }
    01708
    01709     UFDONLY(fd);
    01710     assert(fd->rd_timeoutsecs >= 0);
    01711
    01712     for (total = 0; total < count; total += bytesRead) {
    01713
    01714         int rc;
    01715
    01716         bytesRead = 0;
    01717
    01718         /* Is there data to read? */
    01719         if (fd->bytesRemain == 0) return total; /* XXX simulate EOF */
    01720         rc = fdReadable(fd, fd->rd_timeoutsecs);
    01721
    01722         switch (rc) {
    01723         case -1:        /* error */
    01724         case  0:        /* timeout */
    01725             return total;
    01726             /*@notreached@*/ /*@switchbreak@*/ break;
    01727         default:        /* data to read */
    01728             /*@switchbreak@*/ break;
    01729         }
    01730
    01731 /*@-boundswrite@*/
    01732         rc = fdRead(fd, buf + total, count - total);
    01733 /*@=boundswrite@*/
    01734
    01735         if (rc < 0) {
    01736             switch (errno) {
    01737             case EWOULDBLOCK:
    01738                 continue;
    01739                 /*@notreached@*/ /*@switchbreak@*/ break;
    01740             default:
    01741                 /*@switchbreak@*/ break;
    01742             }
    01743 if (_rpmio_debug)
    01744 fprintf(stderr, "*** read: rc %d errno %d %s \"%s\"\n", rc, errno, strerror(errno), buf);
    01745             return rc;
    01746             /*@notreached@*/ break;
    01747         } else if (rc == 0) {
    01748             return total;
    01749             /*@notreached@*/ break;
    01750         }
    01751         bytesRead = rc;
    01752     }
    01753
    01754     return count;
    01755 }
    01756
    01757 static ssize_t ufdWrite(void * cookie, const char * buf, size_t count)
    01758         /*@globals fileSystem, internalState @*/
    01759         /*@modifies fileSystem, internalState @*/
    01760 {
    01761     FD_t fd = c2f(cookie);
    01762     int bytesWritten;
    01763     int total = 0;
    01764
    01765 #ifdef  NOTYET
    01766     if (fdGetIo(fd) == fdio) {
    01767         struct stat sb;
    01768         (void) fstat(fdGetFdno(fd), &sb);
    01769         if (S_ISREG(sb.st_mode))
    01770             return fdWrite(fd, buf, count);
    01771     }
    01772 #endif
    01773
    01774     UFDONLY(fd);
    01775
    01776     for (total = 0; total < count; total += bytesWritten) {
    01777
    01778         int rc;
    01779
    01780         bytesWritten = 0;
    01781
    01782         /* Is there room to write data? */
    01783         if (fd->bytesRemain == 0) {
    01784 fprintf(stderr, "*** ufdWrite fd %p WRITE PAST END OF CONTENT\n", fd);
    01785             return total;       /* XXX simulate EOF */
    01786         }
    01787         rc = fdWritable(fd, 2);         /* XXX configurable? */
    01788
    01789         switch (rc) {
    01790         case -1:        /* error */
    01791         case  0:        /* timeout */
    01792             return total;
    01793             /*@notreached@*/ /*@switchbreak@*/ break;
    01794         default:        /* data to write */
    01795             /*@switchbreak@*/ break;
    01796         }
    01797
    01798         rc = fdWrite(fd, buf + total, count - total);
    01799
    01800         if (rc < 0) {
    01801             switch (errno) {
    01802             case EWOULDBLOCK:
    01803                 continue;
    01804                 /*@notreached@*/ /*@switchbreak@*/ break;
    01805             default:
    01806                 /*@switchbreak@*/ break;
    01807             }
    01808 if (_rpmio_debug)
    01809 fprintf(stderr, "*** write: rc %d errno %d %s \"%s\"\n", rc, errno, strerror(errno), buf);
    01810             return rc;
    01811             /*@notreached@*/ break;
    01812         } else if (rc == 0) {
    01813             return total;
    01814             /*@notreached@*/ break;
    01815         }
    01816         bytesWritten = rc;
    01817     }
    01818
    01819     return count;
    01820 }
    01821
    01822 static inline int ufdSeek(void * cookie, _libio_pos_t pos, int whence)
    01823         /*@globals fileSystem, internalState @*/
    01824         /*@modifies fileSystem, internalState @*/
    01825 {
    01826     FD_t fd = c2f(cookie);
    01827
    01828     switch (fd->urlType) {
    01829     case URL_IS_UNKNOWN:
    01830     case URL_IS_PATH:
    01831         break;
    01832     case URL_IS_DASH:
    01833     case URL_IS_FTP:
    01834     case URL_IS_HTTP:
    01835     default:
    01836         return -2;
    01837         /*@notreached@*/ break;
    01838     }
    01839     return fdSeek(cookie, pos, whence);
    01840 }
    01841
    01842 /*@-branchstate@*/
    01843 /*@-usereleased@*/      /* LCL: fd handling is tricky here. */
    01844 int ufdClose( /*@only@*/ void * cookie)
    01845 {
    01846     FD_t fd = c2f(cookie);
    01847
    01848     UFDONLY(fd);
    01849
    01850     /*@-branchstate@*/
    01851     if (fd->url) {
    01852         urlinfo u = fd->url;
    01853
    01854         if (fd == u->data)
    01855                 fd = u->data = fdFree(fd, "grab data (ufdClose persist)");
    01856         else
    01857                 fd = fdFree(fd, "grab data (ufdClose)");
    01858         (void) urlFree(fd->url, "url (ufdClose)");
    01859         fd->url = NULL;
    01860         u->ctrl = fdFree(u->ctrl, "grab ctrl (ufdClose)");
    01861
    01862         if (u->urltype == URL_IS_FTP) {
    01863
    01864             /* XXX if not using libio, lose the fp from fpio */
    01865             {   FILE * fp;
    01866                 /*@+voidabstract -nullpass@*/
    01867                 fp = fdGetFILE(fd);
    01868                 if (noLibio && fp)
    01869                     fdSetFp(fd, NULL);
    01870                 /*@=voidabstract =nullpass@*/
    01871             }
    01872
    01873             /*
    01874              * Normal FTP has 4 refs on the data fd:
    01875              *  "persist data (ufdOpen FTP)"            rpmio.c:888
    01876              *  "grab data (ufdOpen FTP)"               rpmio.c:892
    01877              *  "open data (ftpReq)"                    ftp.c:633
    01878              *  "fopencookie"                           rpmio.c:1507
    01879              *
    01880              * Normal FTP has 5 refs on the ctrl fd:
    01881              *  "persist ctrl"                          url.c:176
    01882              *  "grab ctrl (urlConnect FTP)"            rpmio.c:404
    01883              *  "open ctrl"                             ftp.c:504
    01884              *  "grab data (ftpReq)"                    ftp.c:661
    01885              *  "open data (ftpReq)"                    ftp.c:662
    01886              */
    01887             if (fd->bytesRemain > 0) {
    01888                 if (fd->ftpFileDoneNeeded) {
    01889                     if (fdReadable(u->ctrl, 0) > 0)
    01890                         (void) ftpFileDone(u, fd);
    01891                     else
    01892                         (void) ftpAbort(u, fd);
    01893                 }
    01894             } else {
    01895                 int rc;
    01896                 /* XXX STOR et al require close before ftpFileDone */
    01897                 /*@-refcounttrans@*/
    01898                 rc = fdClose(fd);
    01899                 /*@=refcounttrans@*/
    01900 #if 0   /* XXX error exit from ufdOpen does not have this set */
    01901                 assert(fd->ftpFileDoneNeeded != 0);
    01902 #endif
    01903                 /*@-compdef@*/ /* FIX: u->data undefined */
    01904                 if (fd->ftpFileDoneNeeded)
    01905                     (void) ftpFileDone(u, fd);
    01906                 /*@=compdef@*/
    01907                 return rc;
    01908             }
    01909         }
    01910
    01911         /* XXX Why not (u->urltype == URL_IS_HTTP) ??? */
    01912         if (u->service != NULL && !strcmp(u->service, "http")) {
    01913             if (fd->wr_chunked) {
    01914                 int rc;
    01915             /* XXX HTTP PUT requires terminating 0 length chunk. */
    01916                 (void) fdWrite(fd, NULL, 0);
    01917                 fd->wr_chunked = 0;
    01918             /* XXX HTTP PUT requires terminating entity-header. */
    01919 if (_ftp_debug)
    01920 fprintf(stderr, "-> \r\n");
    01921                 (void) fdWrite(fd, "\r\n", sizeof("\r\n")-1);
    01922                 rc = httpResp(u, fd, NULL);
    01923             }
    01924
    01925             if (fd == u->ctrl)
    01926                 fd = u->ctrl = fdFree(fd, "open data (ufdClose HTTP persist ctrl)");
    01927             else if (fd == u->data)
    01928                 fd = u->data = fdFree(fd, "open data (ufdClose HTTP persist data)");
    01929             else
    01930                 fd = fdFree(fd, "open data (ufdClose HTTP)");
    01931
    01932             /*
    01933              * HTTP has 4 (or 5 if persistent malloc) refs on the fd:
    01934              *  "persist ctrl"                          url.c:177
    01935              *  "grab ctrl (ufdOpen HTTP)"              rpmio.c:924
    01936              *  "grab data (ufdOpen HTTP)"              rpmio.c:928
    01937              *  "open ctrl (httpReq)"                   ftp.c:382
    01938              *  "open data (httpReq)"                   ftp.c:435
    01939              */
    01940
    01941             /* XXX if not using libio, lose the fp from fpio */
    01942             {   FILE * fp;
    01943                 /*@+voidabstract -nullpass@*/
    01944                 fp = fdGetFILE(fd);
    01945                 if (noLibio && fp)
    01946                     fdSetFp(fd, NULL);
    01947                 /*@=voidabstract =nullpass@*/
    01948             }
    01949
    01950             if (fd->persist && u->httpVersion &&
    01951                 (fd == u->ctrl || fd == u->data) && fd->bytesRemain == 0) {
    01952                 fd->contentLength = fd->bytesRemain = -1;
    01953                 return 0;
    01954             } else {
    01955                 fd->contentLength = fd->bytesRemain = -1;
    01956             }
    01957         }
    01958     }
    01959     return fdClose(fd);
    01960 }
    01961 /*@=usereleased@*/
    01962 /*@=branchstate@*/
    01963
    01964 /*@-nullstate@*/        /* FIX: u->{ctrl,data}->url undef after XurlLink. */
    01965 /*@null@*/ FD_t ftpOpen(const char *url, /*@unused@*/ int flags,
    01966                 /*@unused@*/ mode_t mode, /*@out@*/ urlinfo *uret)
    01967         /*@modifies *uret @*/
    01968 {
    01969     urlinfo u = NULL;
    01970     FD_t fd = NULL;
    01971
    01972 #if 0   /* XXX makeTempFile() heartburn */
    01973     assert(!(flags & O_RDWR));
    01974 #endif
    01975     if (urlConnect(url, &u) < 0)
    01976         goto exit;
    01977
    01978     if (u->data == NULL)
    01979         u->data = fdNew("persist data (ftpOpen)");
    01980
    01981     if (u->data->url == NULL)
    01982         fd = fdLink(u->data, "grab data (ftpOpen persist data)");
    01983     else
    01984         fd = fdNew("grab data (ftpOpen)");
    01985
    01986     if (fd) {
    01987         fdSetIo(fd, ufdio);
    01988         fd->ftpFileDoneNeeded = 0;
    01989         fd->rd_timeoutsecs = ftpTimeoutSecs;
    01990         fd->contentLength = fd->bytesRemain = -1;
    01991         fd->url = urlLink(u, "url (ufdOpen FTP)");
    01992         fd->urlType = URL_IS_FTP;
    01993     }
    01994
    01995 exit:
    01996 /*@-boundswrite@*/
    01997     if (uret)
    01998         *uret = u;
    01999 /*@=boundswrite@*/
    02000     /*@-refcounttrans@*/
    02001     return fd;
    02002     /*@=refcounttrans@*/
    02003 }
    02004 /*@=nullstate@*/
    02005
    02006 /*@-nullstate@*/        /* FIX: u->{ctrl,data}->url undef after XurlLink. */
    02007 static /*@null@*/ FD_t httpOpen(const char * url, /*@unused@*/ int flags,
    02008                 /*@unused@*/ mode_t mode, /*@out@*/ urlinfo * uret)
    02009         /*@globals internalState @*/
    02010         /*@modifies *uret, internalState @*/
    02011 {
    02012     urlinfo u = NULL;
    02013     FD_t fd = NULL;
    02014
    02015 #if 0   /* XXX makeTempFile() heartburn */
    02016     assert(!(flags & O_RDWR));
    02017 #endif
    02018     if (urlSplit(url, &u))
    02019         goto exit;
    02020
    02021     if (u->ctrl == NULL)
    02022         u->ctrl = fdNew("persist ctrl (httpOpen)");
    02023     if (u->ctrl->nrefs > 2 && u->data == NULL)
    02024         u->data = fdNew("persist data (httpOpen)");
    02025
    02026     if (u->ctrl->url == NULL)
    02027         fd = fdLink(u->ctrl, "grab ctrl (httpOpen persist ctrl)");
    02028     else if (u->data->url == NULL)
    02029         fd = fdLink(u->data, "grab ctrl (httpOpen persist data)");
    02030     else
    02031         fd = fdNew("grab ctrl (httpOpen)");
    02032
    02033     if (fd) {
    02034         fdSetIo(fd, ufdio);
    02035         fd->ftpFileDoneNeeded = 0;
    02036         fd->rd_timeoutsecs = httpTimeoutSecs;
    02037         fd->contentLength = fd->bytesRemain = -1;
    02038         fd->url = urlLink(u, "url (httpOpen)");
    02039         fd = fdLink(fd, "grab data (httpOpen)");
    02040         fd->urlType = URL_IS_HTTP;
    02041     }
    02042
    02043 exit:
    02044 /*@-boundswrite@*/
    02045     if (uret)
    02046         *uret = u;
    02047 /*@=boundswrite@*/
    02048     /*@-refcounttrans@*/
    02049     return fd;
    02050     /*@=refcounttrans@*/
    02051 }
    02052 /*@=nullstate@*/
    02053
    02054 static /*@null@*/ FD_t ufdOpen(const char * url, int flags, mode_t mode)
    02055         /*@globals fileSystem, internalState @*/
    02056         /*@modifies fileSystem, internalState @*/
    02057 {
    02058     FD_t fd = NULL;
    02059     const char * cmd;
    02060     urlinfo u;
    02061     const char * path;
    02062     urltype urlType = urlPath(url, &path);
    02063
    02064 if (_rpmio_debug)
    02065 fprintf(stderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mode);
    02066
    02067     /*@-branchstate@*/
    02068     switch (urlType) {
    02069     case URL_IS_FTP:
    02070         fd = ftpOpen(url, flags, mode, &u);
    02071         if (fd == NULL || u == NULL)
    02072             break;
    02073
    02074         /* XXX W2DO? use STOU rather than STOR to prevent clobbering */
    02075         cmd = ((flags & O_WRONLY)
    02076                 ?  ((flags & O_APPEND) ? "APPE" :
    02077                    ((flags & O_CREAT) ? "STOR" : "STOR"))
    02078                 :  ((flags & O_CREAT) ? "STOR" : "RETR"));
    02079         u->openError = ftpReq(fd, cmd, path);
    02080         if (u->openError < 0) {
    02081             /* XXX make sure that we can exit through ufdClose */
    02082             fd = fdLink(fd, "error data (ufdOpen FTP)");
    02083         } else {
    02084             fd->bytesRemain = ((!strcmp(cmd, "RETR"))
    02085                 ?  fd->contentLength : -1);
    02086             fd->wr_chunked = 0;
    02087         }
    02088         break;
    02089     case URL_IS_HTTP:
    02090         fd = httpOpen(url, flags, mode, &u);
    02091         if (fd == NULL || u == NULL)
    02092             break;
    02093
    02094         cmd = ((flags & O_WRONLY)
    02095                 ?  ((flags & O_APPEND) ? "PUT" :
    02096                    ((flags & O_CREAT) ? "PUT" : "PUT"))
    02097                 : "GET");
    02098         u->openError = httpReq(fd, cmd, path);
    02099         if (u->openError < 0) {
    02100             /* XXX make sure that we can exit through ufdClose */
    02101             fd = fdLink(fd, "error ctrl (ufdOpen HTTP)");
    02102             fd = fdLink(fd, "error data (ufdOpen HTTP)");
    02103         } else {
    02104             fd->bytesRemain = ((!strcmp(cmd, "GET"))
    02105                 ?  fd->contentLength : -1);
    02106             fd->wr_chunked = ((!strcmp(cmd, "PUT"))
    02107                 ?  fd->wr_chunked : 0);
    02108         }
    02109         break;
    02110     case URL_IS_DASH:
    02111         assert(!(flags & O_RDWR));
    02112         fd = fdDup( ((flags & O_WRONLY) ? STDOUT_FILENO : STDIN_FILENO) );
    02113         if (fd) {
    02114             fdSetIo(fd, ufdio);
    02115             fd->rd_timeoutsecs = 600;   /* XXX W2DO? 10 mins? */
    02116             fd->contentLength = fd->bytesRemain = -1;
    02117         }
    02118         break;
    02119     case URL_IS_PATH:
    02120     case URL_IS_UNKNOWN:
    02121     default:
    02122         fd = fdOpen(path, flags, mode);
    02123         if (fd) {
    02124             fdSetIo(fd, ufdio);
    02125             fd->rd_timeoutsecs = 1;
    02126             fd->contentLength = fd->bytesRemain = -1;
    02127         }
    02128         break;
    02129     }
    02130     /*@=branchstate@*/
    02131
    02132     if (fd == NULL) return NULL;
    02133     fd->urlType = urlType;
    02134     if (Fileno(fd) < 0) {
    02135         (void) ufdClose(fd);
    02136         return NULL;
    02137     }
    02138 /*@-modfilesys@*/
    02139 DBGIO(fd, (stderr, "==>\tufdOpen(\"%s\",%x,0%o) %s\n", url, (unsigned)flags, (unsigned)mode, fdbg(fd)));
    02140 /*@=modfilesys@*/
    02141     return fd;
    02142 }
    02143
    02144 static struct FDIO_s ufdio_s = {
    02145   ufdRead, ufdWrite, ufdSeek, ufdClose, XfdLink, XfdFree, XfdNew, fdFileno,
    02146   ufdOpen, NULL, fdGetFp, NULL, Mkdir, Chdir, Rmdir, Rename, Unlink
    02147 };
    02148 FDIO_t ufdio = /*@-compmempass@*/ &ufdio_s /*@=compmempass@*/ ;
    02149
    02150 /* =============================================================== */
    02151 /* Support for GZIP library.
    02152  */
    02153 #ifdef  HAVE_ZLIB_H
    02154 /*@-moduncon@*/
    02155
    02156 /*@-noparams@*/
    02157 #include <zlib.h>
    02158 /*@=noparams@*/
    02159
    02160 static inline /*@dependent@*/ /*@null@*/ void * gzdFileno(FD_t fd)
    02161         /*@*/
    02162 {
    02163     void * rc = NULL;
    02164     int i;
    02165
    02166     FDSANE(fd);
    02167     for (i = fd->nfps; i >= 0; i--) {
    02168 /*@-boundsread@*/
    02169         FDSTACK_t * fps = &fd->fps[i];
    02170 /*@=boundsread@*/
    02171         if (fps->io != gzdio)
    02172             continue;
    02173         rc = fps->fp;
    02174         break;
    02175     }
    02176
    02177     return rc;
    02178 }
    02179
    02180 static /*@null@*/ FD_t gzdOpen(const char * path, const char * fmode)
    02181         /*@globals fileSystem @*/
    02182         /*@modifies fileSystem @*/
    02183 {
    02184     FD_t fd;
    02185     gzFile *gzfile;
    02186     if ((gzfile = gzopen(path, fmode)) == NULL)
    02187         return NULL;
    02188     fd = fdNew("open (gzdOpen)");
    02189     fdPop(fd); fdPush(fd, gzdio, gzfile, -1);
    02190
    02191 /*@-modfilesys@*/
    02192 DBGIO(fd, (stderr, "==>\tgzdOpen(\"%s\", \"%s\") fd %p %s\n", path, fmode, (fd ? fd : NULL), fdbg(fd)));
    02193 /*@=modfilesys@*/
    02194     return fdLink(fd, "gzdOpen");
    02195 }
    02196
    02197 /*@-globuse@*/
    02198 static /*@null@*/ FD_t gzdFdopen(void * cookie, const char *fmode)
    02199         /*@globals fileSystem, internalState @*/
    02200         /*@modifies fileSystem, internalState @*/
    02201 {
    02202     FD_t fd = c2f(cookie);
    02203     int fdno;
    02204     gzFile *gzfile;
    02205
    02206     if (fmode == NULL) return NULL;
    02207     fdno = fdFileno(fd);
    02208     fdSetFdno(fd, -1);          /* XXX skip the fdio close */
    02209     if (fdno < 0) return NULL;
    02210     gzfile = gzdopen(fdno, fmode);
    02211     if (gzfile == NULL) return NULL;
    02212
    02213     fdPush(fd, gzdio, gzfile, fdno);            /* Push gzdio onto stack */
    02214
    02215     return fdLink(fd, "gzdFdopen");
    02216 }
    02217 /*@=globuse@*/
    02218
    02219 /*@-globuse@*/
    02220 static int gzdFlush(FD_t fd)
    02221         /*@globals fileSystem @*/
    02222         /*@modifies fileSystem @*/
    02223 {
    02224     gzFile *gzfile;
    02225     gzfile = gzdFileno(fd);
    02226     if (gzfile == NULL) return -2;
    02227     return gzflush(gzfile, Z_SYNC_FLUSH);       /* XXX W2DO? */
    02228 }
    02229 /*@=globuse@*/
    02230
    02231 /* =============================================================== */
    02232 /*@-mustmod@*/          /* LCL: *buf is modified */
    02233 static ssize_t gzdRead(void * cookie, /*@out@*/ char * buf, size_t count)
    02234         /*@globals fileSystem, internalState @*/
    02235         /*@modifies *buf, fileSystem, internalState @*/
    02236 {
    02237     FD_t fd = c2f(cookie);
    02238     gzFile *gzfile;
    02239     ssize_t rc;
    02240
    02241     if (fd == NULL || fd->bytesRemain == 0) return 0;   /* XXX simulate EOF */
    02242
    02243     gzfile = gzdFileno(fd);
    02244     if (gzfile == NULL) return -2;      /* XXX can't happen */
    02245
    02246     fdstat_enter(fd, FDSTAT_READ);
    02247     /*@-compdef@*/ /* LCL: *buf is undefined */
    02248     rc = gzread(gzfile, buf, count);
    02249 /*@-modfilesys@*/
    02250 DBGIO(fd, (stderr, "==>\tgzdRead(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
    02251 /*@=modfilesys@*/
    02252     /*@=compdef@*/
    02253     if (rc < 0) {
    02254         int zerror = 0;
    02255         fd->errcookie = gzerror(gzfile, &zerror);
    02256         if (zerror == Z_ERRNO) {
    02257             fd->syserrno = errno;
    02258             fd->errcookie = strerror(fd->syserrno);
    02259         }
    02260     } else if (rc >= 0) {
    02261         fdstat_exit(fd, FDSTAT_READ, rc);
    02262         /*@-compdef@*/
    02263         if (fd->ndigests && rc > 0) fdUpdateDigests(fd, buf, rc);
    02264         /*@=compdef@*/
    02265     }
    02266     return rc;
    02267 }
    02268 /*@=mustmod@*/
    02269
    02270 static ssize_t gzdWrite(void * cookie, const char * buf, size_t count)
    02271         /*@globals fileSystem, internalState @*/
    02272         /*@modifies fileSystem, internalState @*/
    02273 {
    02274     FD_t fd = c2f(cookie);
    02275     gzFile *gzfile;
    02276     ssize_t rc;
    02277
    02278     if (fd == NULL || fd->bytesRemain == 0) return 0;   /* XXX simulate EOF */
    02279
    02280     if (fd->ndigests && count > 0) fdUpdateDigests(fd, buf, count);
    02281
    02282     gzfile = gzdFileno(fd);
    02283     if (gzfile == NULL) return -2;      /* XXX can't happen */
    02284
    02285     fdstat_enter(fd, FDSTAT_WRITE);
    02286     rc = gzwrite(gzfile, (void *)buf, count);
    02287 /*@-modfilesys@*/
    02288 DBGIO(fd, (stderr, "==>\tgzdWrite(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
    02289 /*@=modfilesys@*/
    02290     if (rc < 0) {
    02291         int zerror = 0;
    02292         fd->errcookie = gzerror(gzfile, &zerror);
    02293         if (zerror == Z_ERRNO) {
    02294             fd->syserrno = errno;
    02295             fd->errcookie = strerror(fd->syserrno);
    02296         }
    02297     } else if (rc > 0) {
    02298         fdstat_exit(fd, FDSTAT_WRITE, rc);
    02299     }
    02300     return rc;
    02301 }
    02302
    02303 /* XXX zlib-1.0.4 has not */
    02304 static inline int gzdSeek(void * cookie, _libio_pos_t pos, int whence)
    02305         /*@globals fileSystem, internalState @*/
    02306         /*@modifies fileSystem, internalState @*/
    02307 {
    02308 #ifdef USE_COOKIE_SEEK_POINTER
    02309     _IO_off64_t p = *pos;
    02310 #else
    02311     off_t p = pos;
    02312 #endif
    02313     int rc;
    02314 #if HAVE_GZSEEK
    02315     FD_t fd = c2f(cookie);
    02316     gzFile *gzfile;
    02317
    02318     if (fd == NULL) return -2;
    02319     assert(fd->bytesRemain == -1);      /* XXX FIXME */
    02320
    02321     gzfile = gzdFileno(fd);
    02322     if (gzfile == NULL) return -2;      /* XXX can't happen */
    02323
    02324     fdstat_enter(fd, FDSTAT_SEEK);
    02325     rc = gzseek(gzfile, p, whence);
    02326 /*@-modfilesys@*/
    02327 DBGIO(fd, (stderr, "==>\tgzdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd)));
    02328 /*@=modfilesys@*/
    02329     if (rc < 0) {
    02330         int zerror = 0;
    02331         fd->errcookie = gzerror(gzfile, &zerror);
    02332         if (zerror == Z_ERRNO) {
    02333             fd->syserrno = errno;
    02334             fd->errcookie = strerror(fd->syserrno);
    02335         }
    02336     } else if (rc >= 0) {
    02337         fdstat_exit(fd, FDSTAT_SEEK, rc);
    02338     }
    02339 #else
    02340     rc = -2;
    02341 #endif
    02342     return rc;
    02343 }
    02344
    02345 static int gzdClose( /*@only@*/ void * cookie)
    02346         /*@globals fileSystem, internalState @*/
    02347         /*@modifies fileSystem, internalState @*/
    02348 {
    02349     FD_t fd = c2f(cookie);
    02350     gzFile *gzfile;
    02351     int rc;
    02352
    02353     gzfile = gzdFileno(fd);
    02354     if (gzfile == NULL) return -2;      /* XXX can't happen */
    02355
    02356     fdstat_enter(fd, FDSTAT_CLOSE);
    02357     /*@-dependenttrans@*/
    02358     rc = gzclose(gzfile);
    02359     /*@=dependenttrans@*/
    02360
    02361     /* XXX TODO: preserve fd if errors */
    02362
    02363     if (fd) {
    02364 /*@-modfilesys@*/
    02365 DBGIO(fd, (stderr, "==>\tgzdClose(%p) zerror %d %s\n", cookie, rc, fdbg(fd)));
    02366 /*@=modfilesys@*/
    02367         if (rc < 0) {
    02368             /*@-usereleased@*/
    02369             fd->errcookie = gzerror(gzfile, &rc);
    02370             /*@=usereleased@*/
    02371             if (rc == Z_ERRNO) {
    02372                 fd->syserrno = errno;
    02373                 fd->errcookie = strerror(fd->syserrno);
    02374             }
    02375         } else if (rc >= 0) {
    02376             fdstat_exit(fd, FDSTAT_CLOSE, rc);
    02377         }
    02378     }
    02379
    02380 /*@-modfilesys@*/
    02381 DBGIO(fd, (stderr, "==>\tgzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
    02382 /*@=modfilesys@*/
    02383
    02384     if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "GZDIO", stderr);
    02385     /*@-branchstate@*/
    02386     if (rc == 0)
    02387         fd = fdFree(fd, "open (gzdClose)");
    02388     /*@=branchstate@*/
    02389     return rc;
    02390 }
    02391
    02392 static struct FDIO_s gzdio_s = {
    02393   gzdRead, gzdWrite, gzdSeek, gzdClose, XfdLink, XfdFree, XfdNew, fdFileno,
    02394   NULL, gzdOpen, gzdFileno, gzdFlush,   NULL, NULL, NULL, NULL, NULL
    02395 };
    02396 FDIO_t gzdio = /*@-compmempass@*/ &gzdio_s /*@=compmempass@*/ ;
    02397
    02398 /*@=moduncon@*/
    02399 #endif  /* HAVE_ZLIB_H */
    02400
    02401 /* =============================================================== */
    02402 /* Support for BZIP2 library.
    02403  */
    02404 #if HAVE_BZLIB_H
    02405 /*@-moduncon@*/
    02406
    02407 #include <bzlib.h>
    02408
    02409 #ifdef HAVE_BZ2_1_0
    02410 # define bzopen  BZ2_bzopen
    02411 # define bzclose BZ2_bzclose
    02412 # define bzdopen BZ2_bzdopen
    02413 # define bzerror BZ2_bzerror
    02414 # define bzflush BZ2_bzflush
    02415 # define bzread  BZ2_bzread
    02416 # define bzwrite BZ2_bzwrite
    02417 #endif /* HAVE_BZ2_1_0 */
    02418
    02419 static inline /*@dependent@*/ void * bzdFileno(FD_t fd)
    02420         /*@*/
    02421 {
    02422     void * rc = NULL;
    02423     int i;
    02424
    02425     FDSANE(fd);
    02426     for (i = fd->nfps; i >= 0; i--) {
    02427 /*@-boundsread@*/
    02428         FDSTACK_t * fps = &fd->fps[i];
    02429 /*@=boundsread@*/
    02430         if (fps->io != bzdio)
    02431             continue;
    02432         rc = fps->fp;
    02433         break;
    02434     }
    02435
    02436     return rc;
    02437 }
    02438
    02439 /*@-globuse@*/
    02440 static /*@null@*/ FD_t bzdOpen(const char * path, const char * mode)
    02441         /*@globals fileSystem @*/
    02442         /*@modifies fileSystem @*/
    02443 {
    02444     FD_t fd;
    02445     BZFILE *bzfile;;
    02446     if ((bzfile = bzopen(path, mode)) == NULL)
    02447         return NULL;
    02448     fd = fdNew("open (bzdOpen)");
    02449     fdPop(fd); fdPush(fd, bzdio, bzfile, -1);
    02450     return fdLink(fd, "bzdOpen");
    02451 }
    02452 /*@=globuse@*/
    02453
    02454 /*@-globuse@*/
    02455 static /*@null@*/ FD_t bzdFdopen(void * cookie, const char * fmode)
    02456         /*@globals fileSystem, internalState @*/
    02457         /*@modifies fileSystem, internalState @*/
    02458 {
    02459     FD_t fd = c2f(cookie);
    02460     int fdno;
    02461     BZFILE *bzfile;
    02462
    02463     if (fmode == NULL) return NULL;
    02464     fdno = fdFileno(fd);
    02465     fdSetFdno(fd, -1);          /* XXX skip the fdio close */
    02466     if (fdno < 0) return NULL;
    02467     bzfile = bzdopen(fdno, fmode);
    02468     if (bzfile == NULL) return NULL;
    02469
    02470     fdPush(fd, bzdio, bzfile, fdno);            /* Push bzdio onto stack */
    02471
    02472     return fdLink(fd, "bzdFdopen");
    02473 }
    02474 /*@=globuse@*/
    02475
    02476 /*@-globuse@*/
    02477 static int bzdFlush(FD_t fd)
    02478         /*@globals fileSystem @*/
    02479         /*@modifies fileSystem @*/
    02480 {
    02481     return bzflush(bzdFileno(fd));
    02482 }
    02483 /*@=globuse@*/
    02484
    02485 /* =============================================================== */
    02486 /*@-globuse@*/
    02487 /*@-mustmod@*/          /* LCL: *buf is modified */
    02488 static ssize_t bzdRead(void * cookie, /*@out@*/ char * buf, size_t count)
    02489         /*@globals fileSystem, internalState @*/
    02490         /*@modifies *buf, fileSystem, internalState @*/
    02491 {
    02492     FD_t fd = c2f(cookie);
    02493     BZFILE *bzfile;
    02494     ssize_t rc = 0;
    02495
    02496     if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
    02497     bzfile = bzdFileno(fd);
    02498     fdstat_enter(fd, FDSTAT_READ);
    02499     if (bzfile)
    02500         /*@-compdef@*/
    02501         rc = bzread(bzfile, buf, count);
    02502         /*@=compdef@*/
    02503     if (rc == -1) {
    02504         int zerror = 0;
    02505         if (bzfile)
    02506             fd->errcookie = bzerror(bzfile, &zerror);
    02507     } else if (rc >= 0) {
    02508         fdstat_exit(fd, FDSTAT_READ, rc);
    02509         /*@-compdef@*/
    02510         if (fd->ndigests && rc > 0) fdUpdateDigests(fd, buf, rc);
    02511         /*@=compdef@*/
    02512     }
    02513     return rc;
    02514 }
    02515 /*@=mustmod@*/
    02516 /*@=globuse@*/
    02517
    02518 /*@-globuse@*/
    02519 static ssize_t bzdWrite(void * cookie, const char * buf, size_t count)
    02520         /*@globals fileSystem, internalState @*/
    02521         /*@modifies fileSystem, internalState @*/
    02522 {
    02523     FD_t fd = c2f(cookie);
    02524     BZFILE *bzfile;
    02525     ssize_t rc;
    02526
    02527     if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
    02528
    02529     if (fd->ndigests && count > 0) fdUpdateDigests(fd, buf, count);
    02530
    02531     bzfile = bzdFileno(fd);
    02532     fdstat_enter(fd, FDSTAT_WRITE);
    02533     rc = bzwrite(bzfile, (void *)buf, count);
    02534     if (rc == -1) {
    02535         int zerror = 0;
    02536         fd->errcookie = bzerror(bzfile, &zerror);
    02537     } else if (rc > 0) {
    02538         fdstat_exit(fd, FDSTAT_WRITE, rc);
    02539     }
    02540     return rc;
    02541 }
    02542 /*@=globuse@*/
    02543
    02544 static inline int bzdSeek(void * cookie, /*@unused@*/ _libio_pos_t pos,
    02545                         /*@unused@*/ int whence)
    02546         /*@*/
    02547 {
    02548     FD_t fd = c2f(cookie);
    02549
    02550     BZDONLY(fd);
    02551     return -2;
    02552 }
    02553
    02554 static int bzdClose( /*@only@*/ void * cookie)
    02555         /*@globals fileSystem, internalState @*/
    02556         /*@modifies fileSystem, internalState @*/
    02557 {
    02558     FD_t fd = c2f(cookie);
    02559     BZFILE *bzfile;
    02560     int rc;
    02561
    02562     bzfile = bzdFileno(fd);
    02563
    02564     if (bzfile == NULL) return -2;
    02565     fdstat_enter(fd, FDSTAT_CLOSE);
    02566     /*@-noeffectuncon@*/ /* FIX: check rc */
    02567     bzclose(bzfile);
    02568     /*@=noeffectuncon@*/
    02569     rc = 0;     /* XXX FIXME */
    02570
    02571     /* XXX TODO: preserve fd if errors */
    02572
    02573     if (fd) {
    02574         if (rc == -1) {
    02575             int zerror = 0;
    02576             fd->errcookie = bzerror(bzfile, &zerror);
    02577         } else if (rc >= 0) {
    02578             fdstat_exit(fd, FDSTAT_CLOSE, rc);
    02579         }
    02580     }
    02581
    02582 /*@-modfilesys@*/
    02583 DBGIO(fd, (stderr, "==>\tbzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
    02584 /*@=modfilesys@*/
    02585
    02586     if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "BZDIO", stderr);
    02587     /*@-branchstate@*/
    02588     if (rc == 0)
    02589         fd = fdFree(fd, "open (bzdClose)");
    02590     /*@=branchstate@*/
    02591     return rc;
    02592 }
    02593
    02594 static struct FDIO_s bzdio_s = {
    02595   bzdRead, bzdWrite, bzdSeek, bzdClose, XfdLink, XfdFree, XfdNew, fdFileno,
    02596   NULL, bzdOpen, bzdFileno, bzdFlush,   NULL, NULL, NULL, NULL, NULL
    02597 };
    02598 FDIO_t bzdio = /*@-compmempass@*/ &bzdio_s /*@=compmempass@*/ ;
    02599
    02600 /*@=moduncon@*/
    02601 #endif  /* HAVE_BZLIB_H */
    02602
    02603 /* =============================================================== */
    02604 /*@observer@*/
    02605 static const char * getFdErrstr (FD_t fd)
    02606         /*@*/
    02607 {
    02608     const char *errstr = NULL;
    02609
    02610 #ifdef  HAVE_ZLIB_H
    02611     if (fdGetIo(fd) == gzdio) {
    02612         errstr = fd->errcookie;
    02613     } else
    02614 #endif  /* HAVE_ZLIB_H */
    02615
    02616 #ifdef  HAVE_BZLIB_H
    02617     if (fdGetIo(fd) == bzdio) {
    02618         errstr = fd->errcookie;
    02619     } else
    02620 #endif  /* HAVE_BZLIB_H */
    02621
    02622     {
    02623         errstr = (fd->syserrno ? strerror(fd->syserrno) : "");
    02624     }
    02625
    02626     return errstr;
    02627 }
    02628
    02629 /* =============================================================== */
    02630
    02631 const char *Fstrerror(FD_t fd)
    02632 {
    02633     if (fd == NULL)
    02634         return (errno ? strerror(errno) : "");
    02635     FDSANE(fd);
    02636     return getFdErrstr(fd);
    02637 }
    02638
    02639 #define FDIOVEC(_fd, _vec)      \
    02640   ((fdGetIo(_fd) && fdGetIo(_fd)->_vec) ? fdGetIo(_fd)->_vec : NULL)
    02641
    02642 size_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd) {
    02643     fdio_read_function_t _read;
    02644     int rc;
    02645
    02646     FDSANE(fd);
    02647 /*@-modfilesys@*/
    02648 DBGIO(fd, (stderr, "==> Fread(%p,%u,%u,%p) %s\n", buf, (unsigned)size, (unsigned)nmemb, (fd ? fd : NULL), fdbg(fd)));
    02649 /*@=modfilesys@*/
    02650
    02651     if (fdGetIo(fd) == fpio) {
    02652         /*@+voidabstract -nullpass@*/
    02653         rc = fread(buf, size, nmemb, fdGetFILE(fd));
    02654         /*@=voidabstract =nullpass@*/
    02655         return rc;
    02656     }
    02657
    02658     /*@-nullderef@*/
    02659     _read = FDIOVEC(fd, read);
    02660     /*@=nullderef@*/
    02661
    02662     rc = (_read ? (*_read) (fd, buf, size * nmemb) : -2);
    02663     return rc;
    02664 }
    02665
    02666 size_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
    02667 {
    02668     fdio_write_function_t _write;
    02669     int rc;
    02670
    02671     FDSANE(fd);
    02672 /*@-modfilesys@*/
    02673 DBGIO(fd, (stderr, "==> Fwrite(%p,%u,%u,%p) %s\n", buf, (unsigned)size, (unsigned)nmemb, (fd ? fd : NULL), fdbg(fd)));
    02674 /*@=modfilesys@*/
    02675
    02676     if (fdGetIo(fd) == fpio) {
    02677 /*@-boundsread@*/
    02678         /*@+voidabstract -nullpass@*/
    02679         rc = fwrite(buf, size, nmemb, fdGetFILE(fd));
    02680         /*@=voidabstract =nullpass@*/
    02681 /*@=boundsread@*/
    02682         return rc;
    02683     }
    02684
    02685     /*@-nullderef@*/
    02686     _write = FDIOVEC(fd, write);
    02687     /*@=nullderef@*/
    02688
    02689     rc = (_write ? _write(fd, buf, size * nmemb) : -2);
    02690     return rc;
    02691 }
    02692
    02693 int Fseek(FD_t fd, _libio_off_t offset, int whence) {
    02694     fdio_seek_function_t _seek;
    02695 #ifdef USE_COOKIE_SEEK_POINTER
    02696     _IO_off64_t o64 = offset;
    02697     _libio_pos_t pos = &o64;
    02698 #else
    02699     _libio_pos_t pos = offset;
    02700 #endif
    02701
    02702     long int rc;
    02703
    02704     FDSANE(fd);
    02705 /*@-modfilesys@*/
    02706 DBGIO(fd, (stderr, "==> Fseek(%p,%ld,%d) %s\n", fd, (long)offset, whence, fdbg(fd)));
    02707 /*@=modfilesys@*/
    02708
    02709     if (fdGetIo(fd) == fpio) {
    02710         FILE *fp;
    02711
    02712         /*@+voidabstract -nullpass@*/
    02713         fp = fdGetFILE(fd);
    02714         rc = fseek(fp, offset, whence);
    02715         /*@=voidabstract =nullpass@*/
    02716         return rc;
    02717     }
    02718
    02719     /*@-nullderef@*/
    02720     _seek = FDIOVEC(fd, seek);
    02721     /*@=nullderef@*/
    02722
    02723     rc = (_seek ? _seek(fd, pos, whence) : -2);
    02724     return rc;
    02725 }
    02726
    02727 int Fclose(FD_t fd)
    02728 {
    02729     int rc = 0, ec = 0;
    02730
    02731     FDSANE(fd);
    02732 /*@-modfilesys@*/
    02733 DBGIO(fd, (stderr, "==> Fclose(%p) %s\n", (fd ? fd : NULL), fdbg(fd)));
    02734 /*@=modfilesys@*/
    02735
    02736     fd = fdLink(fd, "Fclose");
    02737     /*@-branchstate@*/
    02738     while (fd->nfps >= 0) {
    02739 /*@-boundsread@*/
    02740         FDSTACK_t * fps = &fd->fps[fd->nfps];
    02741 /*@=boundsread@*/
    02742
    02743         if (fps->io == fpio) {
    02744             FILE *fp;
    02745             int fpno;
    02746
    02747             /*@+voidabstract -nullpass@*/
    02748             fp = fdGetFILE(fd);
    02749             fpno = fileno(fp);
    02750             /*@=voidabstract =nullpass@*/
    02751         /* XXX persistent HTTP/1.1 returns the previously opened fp */
    02752             if (fd->nfps > 0 && fpno == -1 &&
    02753                 fd->fps[fd->nfps-1].io == ufdio &&
    02754                 fd->fps[fd->nfps-1].fp == fp &&
    02755                 fd->fps[fd->nfps-1].fdno >= 0)
    02756             {
    02757                 if (fp)
    02758                     rc = fflush(fp);
    02759                 fd->nfps--;
    02760                 /*@-refcounttrans@*/
    02761                 rc = ufdClose(fd);
    02762                 /*@=refcounttrans@*/
    02763 /*@-usereleased@*/
    02764                 if (fdGetFdno(fd) >= 0)
    02765                     break;
    02766                 fdSetFp(fd, NULL);
    02767                 fd->nfps++;
    02768                 if (fp)
    02769                     rc = fclose(fp);
    02770                 fdPop(fd);
    02771                 if (noLibio)
    02772                     fdSetFp(fd, NULL);
    02773             } else {
    02774                 if (fp)
    02775                     rc = fclose(fp);
    02776                 if (fpno == -1) {
    02777                     fd = fdFree(fd, "fopencookie (Fclose)");
    02778                     fdPop(fd);
    02779                 }
    02780             }
    02781         } else {
    02782             /*@-nullderef@*/
    02783             fdio_close_function_t _close = FDIOVEC(fd, close);
    02784             /*@=nullderef@*/
    02785             rc = _close(fd);
    02786         }
    02787         if (fd->nfps == 0)
    02788             break;
    02789         if (ec == 0 && rc)
    02790             ec = rc;
    02791         fdPop(fd);
    02792     }
    02793     /*@=branchstate@*/
    02794     fd = fdFree(fd, "Fclose");
    02795     return ec;
    02796 /*@=usereleased@*/
    02797 }
    02798
    02810 /*@-boundswrite@*/
    02811 static inline void cvtfmode (const char *m,
    02812                                 /*@out@*/ char *stdio, size_t nstdio,
    02813                                 /*@out@*/ char *other, size_t nother,
    02814                                 /*@out@*/ const char **end, /*@out@*/ int * f)
    02815         /*@modifies *stdio, *other, *end, *f @*/
    02816 {
    02817     int flags = 0;
    02818     char c;
    02819
    02820     switch (*m) {
    02821     case 'a':
    02822         flags |= O_WRONLY | O_CREAT | O_APPEND;
    02823         if (--nstdio > 0) *stdio++ = *m;
    02824         break;
    02825     case 'w':
    02826         flags |= O_WRONLY | O_CREAT | O_TRUNC;
    02827         if (--nstdio > 0) *stdio++ = *m;
    02828         break;
    02829     case 'r':
    02830         flags |= O_RDONLY;
    02831         if (--nstdio > 0) *stdio++ = *m;
    02832         break;
    02833     default:
    02834         *stdio = '\0';
    02835         return;
    02836         /*@notreached@*/ break;
    02837     }
    02838     m++;
    02839
    02840     while ((c = *m++) != '\0') {
    02841         switch (c) {
    02842         case '.':
    02843             /*@switchbreak@*/ break;
    02844         case '+':
    02845             flags &= ~(O_RDONLY|O_WRONLY);
    02846             flags |= O_RDWR;
    02847             if (--nstdio > 0) *stdio++ = c;
    02848             continue;
    02849             /*@notreached@*/ /*@switchbreak@*/ break;
    02850         case 'b':
    02851             if (--nstdio > 0) *stdio++ = c;
    02852             continue;
    02853             /*@notreached@*/ /*@switchbreak@*/ break;
    02854         case 'x':
    02855             flags |= O_EXCL;
    02856             if (--nstdio > 0) *stdio++ = c;
    02857             continue;
    02858             /*@notreached@*/ /*@switchbreak@*/ break;
    02859         default:
    02860             if (--nother > 0) *other++ = c;
    02861             continue;
    02862             /*@notreached@*/ /*@switchbreak@*/ break;
    02863         }
    02864         break;
    02865     }
    02866
    02867     *stdio = *other = '\0';
    02868     if (end != NULL)
    02869         *end = (*m != '\0' ? m : NULL);
    02870     if (f != NULL)
    02871         *f = flags;
    02872 }
    02873 /*@=boundswrite@*/
    02874
    02875 #if _USE_LIBIO
    02876 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0
    02877 /* XXX retrofit glibc-2.1.x typedef on glibc-2.0.x systems */
    02878 typedef _IO_cookie_io_functions_t cookie_io_functions_t;
    02879 #endif
    02880 #endif
    02881
    02882 /*@-boundswrite@*/
    02883 FD_t Fdopen(FD_t ofd, const char *fmode)
    02884 {
    02885     char stdio[20], other[20], zstdio[20];
    02886     const char *end = NULL;
    02887     FDIO_t iof = NULL;
    02888     FD_t fd = ofd;
    02889
    02890 if (_rpmio_debug)
    02891 fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
    02892     FDSANE(fd);
    02893
    02894     if (fmode == NULL)
    02895         return NULL;
    02896
    02897     cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL);
    02898     if (stdio[0] == '\0')
    02899         return NULL;
    02900     zstdio[0] = '\0';
    02901     strncat(zstdio, stdio, sizeof(zstdio) - strlen(zstdio));
    02902     strncat(zstdio, other, sizeof(zstdio) - strlen(zstdio));
    02903
    02904     if (end == NULL && other[0] == '\0')
    02905         /*@-refcounttrans -retalias@*/ return fd; /*@=refcounttrans =retalias@*/
    02906
    02907     /*@-branchstate@*/
    02908     if (end && *end) {
    02909         if (!strcmp(end, "fdio")) {
    02910             iof = fdio;
    02911         } else if (!strcmp(end, "gzdio")) {
    02912             iof = gzdio;
    02913             /*@-internalglobs@*/
    02914             fd = gzdFdopen(fd, zstdio);
    02915             /*@=internalglobs@*/
    02916 #if HAVE_BZLIB_H
    02917         } else if (!strcmp(end, "bzdio")) {
    02918             iof = bzdio;
    02919             /*@-internalglobs@*/
    02920             fd = bzdFdopen(fd, zstdio);
    02921             /*@=internalglobs@*/
    02922 #endif
    02923         } else if (!strcmp(end, "ufdio")) {
    02924             iof = ufdio;
    02925         } else if (!strcmp(end, "fadio")) {
    02926             iof = fadio;
    02927         } else if (!strcmp(end, "fpio")) {
    02928             iof = fpio;
    02929             if (noLibio) {
    02930                 int fdno = Fileno(fd);
    02931                 FILE * fp = fdopen(fdno, stdio);
    02932 /*@+voidabstract -nullpass@*/
    02933 if (_rpmio_debug)
    02934 fprintf(stderr, "*** Fdopen fpio fp %p\n", (void *)fp);
    02935 /*@=voidabstract =nullpass@*/
    02936                 if (fp == NULL)
    02937                     return NULL;
    02938                 /* XXX gzdio/bzdio use fp for private data */
    02939                 /*@+voidabstract@*/
    02940                 if (fdGetFp(fd) == NULL)
    02941                     fdSetFp(fd, fp);
    02942                 fdPush(fd, fpio, fp, fdno);     /* Push fpio onto stack */
    02943                 /*@=voidabstract@*/
    02944             }
    02945         }
    02946     } else if (other[0] != '\0') {
    02947         for (end = other; *end && strchr("0123456789fh", *end); end++)
    02948             {};
    02949         if (*end == '\0') {
    02950             iof = gzdio;
    02951             /*@-internalglobs@*/
    02952             fd = gzdFdopen(fd, zstdio);
    02953             /*@=internalglobs@*/
    02954         }
    02955     }
    02956     /*@=branchstate@*/
    02957     if (iof == NULL)
    02958         /*@-refcounttrans -retalias@*/ return fd; /*@=refcounttrans =retalias@*/
    02959
    02960     if (!noLibio) {
    02961         FILE * fp = NULL;
    02962
    02963 #if _USE_LIBIO
    02964         {   cookie_io_functions_t ciof;
    02965             ciof.read = iof->read;
    02966             ciof.write = iof->write;
    02967             ciof.seek = iof->seek;
    02968             ciof.close = iof->close;
    02969             fp = fopencookie(fd, stdio, ciof);
    02970 /*@-modfilesys@*/
    02971 DBGIO(fd, (stderr, "==> fopencookie(%p,\"%s\",*%p) returns fp %p\n", fd, stdio, iof, fp));
    02972 /*@=modfilesys@*/
    02973         }
    02974 #endif
    02975
    02976         /*@-branchstate@*/
    02977         if (fp) {
    02978             /* XXX gzdio/bzdio use fp for private data */
    02979             /*@+voidabstract -nullpass@*/
    02980             if (fdGetFp(fd) == NULL)
    02981                 fdSetFp(fd, fp);
    02982             fdPush(fd, fpio, fp, fileno(fp));   /* Push fpio onto stack */
    02983             /*@=voidabstract =nullpass@*/
    02984             fd = fdLink(fd, "fopencookie");
    02985         }
    02986         /*@=branchstate@*/
    02987     }
    02988
    02989 /*@-modfilesys@*/
    02990 DBGIO(fd, (stderr, "==> Fdopen(%p,\"%s\") returns fd %p %s\n", ofd, fmode, (fd ? fd : NULL), fdbg(fd)));
    02991 /*@=modfilesys@*/
    02992     /*@-refcounttrans -retalias@*/ return fd; /*@=refcounttrans =retalias@*/
    02993 }
    02994 /*@=boundswrite@*/
    02995
    02996 FD_t Fopen(const char *path, const char *fmode)
    02997 {
    02998     char stdio[20], other[20];
    02999     const char *end = NULL;
    03000     mode_t perms = 0666;
    03001     int flags;
    03002     FD_t fd;
    03003
    03004     if (path == NULL || fmode == NULL)
    03005         return NULL;
    03006
    03007     stdio[0] = '\0';
    03008     cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, &flags);
    03009     if (stdio[0] == '\0')
    03010         return NULL;
    03011
    03012     /*@-branchstate@*/
    03013     if (end == NULL || !strcmp(end, "fdio")) {
    03014 if (_rpmio_debug)
    03015 fprintf(stderr, "*** Fopen fdio path %s fmode %s\n", path, fmode);
    03016         fd = fdOpen(path, flags, perms);
    03017         if (fdFileno(fd) < 0) {
    03018             if (fd) (void) fdClose(fd);
    03019             return NULL;
    03020         }
    03021     } else if (!strcmp(end, "fadio")) {
    03022 if (_rpmio_debug)
    03023 fprintf(stderr, "*** Fopen fadio path %s fmode %s\n", path, fmode);
    03024         fd = fadio->_open(path, flags, perms);
    03025         if (fdFileno(fd) < 0) {
    03026             /*@-refcounttrans@*/ (void) fdClose(fd); /*@=refcounttrans@*/
    03027             return NULL;
    03028         }
    03029     } else {
    03030         FILE *fp;
    03031         int fdno;
    03032         int isHTTP = 0;
    03033
    03034         /* XXX gzdio and bzdio here too */
    03035
    03036         switch (urlIsURL(path)) {
    03037         case URL_IS_HTTP:
    03038             isHTTP = 1;
    03039             /*@fallthrough@*/
    03040         case URL_IS_PATH:
    03041         case URL_IS_DASH:
    03042         case URL_IS_FTP:
    03043         case URL_IS_UNKNOWN:
    03044 if (_rpmio_debug)
    03045 fprintf(stderr, "*** Fopen ufdio path %s fmode %s\n", path, fmode);
    03046             fd = ufdOpen(path, flags, perms);
    03047             if (fd == NULL || fdFileno(fd) < 0)
    03048                 return fd;
    03049             break;
    03050         default:
    03051 if (_rpmio_debug)
    03052 fprintf(stderr, "*** Fopen WTFO path %s fmode %s\n", path, fmode);
    03053             return NULL;
    03054             /*@notreached@*/ break;
    03055         }
    03056
    03057         /* XXX persistent HTTP/1.1 returns the previously opened fp */
    03058         if (isHTTP && ((fp = fdGetFp(fd)) != NULL) && ((fdno = fdGetFdno(fd)) >= 0)) {
    03059             /*@+voidabstract@*/
    03060             fdPush(fd, fpio, fp, fileno(fp));   /* Push fpio onto stack */
    03061             /*@=voidabstract@*/
    03062             return fd;
    03063         }
    03064     }
    03065     /*@=branchstate@*/
    03066
    03067     /*@-branchstate@*/
    03068     if (fd)
    03069         fd = Fdopen(fd, fmode);
    03070     /*@=branchstate@*/
    03071     return fd;
    03072 }
    03073
    03074 int Fflush(FD_t fd)
    03075 {
    03076     void * vh;
    03077     if (fd == NULL) return -1;
    03078     if (fdGetIo(fd) == fpio)
    03079         /*@+voidabstract -nullpass@*/
    03080         return fflush(fdGetFILE(fd));
    03081         /*@=voidabstract =nullpass@*/
    03082
    03083     vh = fdGetFp(fd);
    03084     if (vh && fdGetIo(fd) == gzdio)
    03085         return gzdFlush(vh);
    03086 #if HAVE_BZLIB_H
    03087     if (vh && fdGetIo(fd) == bzdio)
    03088         return bzdFlush(vh);
    03089 #endif
    03090
    03091     return 0;
    03092 }
    03093
    03094 int Ferror(FD_t fd)
    03095 {
    03096     int i, rc = 0;
    03097
    03098     if (fd == NULL) return -1;
    03099     for (i = fd->nfps; rc == 0 && i >= 0; i--) {
    03100 /*@-boundsread@*/
    03101         FDSTACK_t * fps = &fd->fps[i];
    03102 /*@=boundsread@*/
    03103         int ec;
    03104
    03105         if (fps->io == fpio) {
    03106             /*@+voidabstract -nullpass@*/
    03107             ec = ferror(fdGetFILE(fd));
    03108             /*@=voidabstract =nullpass@*/
    03109         } else if (fps->io == gzdio) {
    03110             ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
    03111             i--;        /* XXX fdio under gzdio always has fdno == -1 */
    03112 #if HAVE_BZLIB_H
    03113         } else if (fps->io == bzdio) {
    03114             ec = (fd->syserrno  || fd->errcookie != NULL) ? -1 : 0;
    03115             i--;        /* XXX fdio under bzdio always has fdno == -1 */
    03116 #endif
    03117         } else {
    03118         /* XXX need to check ufdio/gzdio/bzdio/fdio errors correctly. */
    03119             ec = (fdFileno(fd) < 0 ? -1 : 0);
    03120         }
    03121
    03122         if (rc == 0 && ec)
    03123             rc = ec;
    03124     }
    03125 /*@-modfilesys@*/
    03126 DBGIO(fd, (stderr, "==> Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd)));
    03127 /*@=modfilesys@*/
    03128     return rc;
    03129 }
    03130
    03131 int Fileno(FD_t fd)
    03132 {
    03133     int i, rc = -1;
    03134
    03135     for (i = fd->nfps ; rc == -1 && i >= 0; i--) {
    03136 /*@-boundsread@*/
    03137         rc = fd->fps[i].fdno;
    03138 /*@=boundsread@*/
    03139     }
    03140 /*@-modfilesys@*/
    03141 DBGIO(fd, (stderr, "==> Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, fdbg(fd)));
    03142 /*@=modfilesys@*/
    03143     return rc;
    03144 }
    03145
    03146 /* XXX this is naive */
    03147 int Fcntl(FD_t fd, int op, void *lip)
    03148 {
    03149     return fcntl(Fileno(fd), op, lip);
    03150 }
    03151
    03152 /* =============================================================== */
    03153 /* Helper routines that may be generally useful.
    03154  */
    03155 /*@-bounds@*/
    03156 int rpmioMkpath(const char * path, mode_t mode, uid_t uid, gid_t gid)
    03157 {
    03158     char * d, * de;
    03159     int created = 0;
    03160     int rc;
    03161
    03162     if (path == NULL)
    03163         return -1;
    03164     d = alloca(strlen(path)+2);
    03165     de = stpcpy(d, path);
    03166     de[1] = '\0';
    03167     for (de = d; *de != '\0'; de++) {
    03168         struct stat st;
    03169         char savec;
    03170
    03171         while (*de && *de != '/') de++;
    03172         savec = de[1];
    03173         de[1] = '\0';
    03174
    03175         rc = Stat(d, &st);
    03176         if (rc) {
    03177             switch(errno) {
    03178             default:
    03179                 return errno;
    03180                 /*@notreached@*/ /*@switchbreak@*/ break;
    03181             case ENOENT:
    03182                 /*@switchbreak@*/ break;
    03183             }
    03184             rc = Mkdir(d, mode);
    03185             if (rc)
    03186                 return errno;
    03187             created = 1;
    03188             if (!(uid == (uid_t) -1 && gid == (gid_t) -1)) {
    03189                 rc = chown(d, uid, gid);
    03190                 if (rc)
    03191                     return errno;
    03192             }
    03193         } else if (!S_ISDIR(st.st_mode)) {
    03194             return ENOTDIR;
    03195         }
    03196         de[1] = savec;
    03197     }
    03198     rc = 0;
    03199     if (created)
    03200         rpmMessage(RPMMESS_DEBUG, "created directory(s) %s mode 0%o\n",
    03201                         path, mode);
    03202     return rc;
    03203 }
    03204 /*@=bounds@*/
    03205
    03206 /*@-boundswrite@*/
    03207 int rpmioSlurp(const char * fn, const byte ** bp, ssize_t * blenp)
    03208 {
    03209     static ssize_t blenmax = (8 * BUFSIZ);
    03210     ssize_t blen = 0;
    03211     byte * b = NULL;
    03212     ssize_t size;
    03213     FD_t fd;
    03214     int rc = 0;
    03215
    03216     fd = Fopen(fn, "r.ufdio");
    03217     if (fd == NULL || Ferror(fd)) {
    03218         rc = 2;
    03219         goto exit;
    03220     }
    03221
    03222     size = fdSize(fd);
    03223     blen = (size >= 0 ? size : blenmax);
    03224     /*@-branchstate@*/
    03225     if (blen) {
    03226         int nb;
    03227         b = xmalloc(blen+1);
    03228         b[0] = '\0';
    03229         nb = Fread(b, sizeof(*b), blen, fd);
    03230         if (Ferror(fd) || (size > 0 && nb != blen)) {
    03231             rc = 1;
    03232             goto exit;
    03233         }
    03234         if (blen == blenmax && nb < blen) {
    03235             blen = nb;
    03236             b = xrealloc(b, blen+1);
    03237         }
    03238         b[blen] = '\0';
    03239     }
    03240     /*@=branchstate@*/
    03241
    03242 exit:
    03243     if (fd) (void) Fclose(fd);
    03244
    03245     if (rc) {
    03246         if (b) free(b);
    03247         b = NULL;
    03248         blen = 0;
    03249     }
    03250
    03251     if (bp) *bp = b;
    03252     else if (b) free(b);
    03253
    03254     if (blenp) *blenp = blen;
    03255
    03256     return rc;
    03257 }
    03258 /*@=boundswrite@*/
    03259
    03260 static struct FDIO_s fpio_s = {
    03261   ufdRead, ufdWrite, fdSeek, ufdClose, XfdLink, XfdFree, XfdNew, fdFileno,
    03262   ufdOpen, NULL, fdGetFp, NULL, Mkdir, Chdir, Rmdir, Rename, Unlink
    03263 };
    03264 FDIO_t fpio = /*@-compmempass@*/ &fpio_s /*@=compmempass@*/ ;
    03265 /*@=type@*/