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@*/

Generated on Wed Sep 4 12:49:56 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002