rpmio/rpmio.c

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

Generated on Tue Feb 19 22:26:20 2008 for rpm by  doxygen 1.5.1