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