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