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