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