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("@"));
01091 strcpy(myp, pw->pw_name);
01092 strcat(myp, "@");
01093 password = myp;
01094 } else {
01095 password = "root@";
01096 }
01097 }
01098
01099
01100
01101 if (fdFileno(u->ctrl) >= 0 && fdWritable(u->ctrl, 0) < 1)
01102 (void) fdClose(u->ctrl);
01103
01104
01105
01106 if (fdFileno(u->ctrl) < 0) {
01107 rc = tcpConnect(u->ctrl, host, port);
01108 if (rc < 0)
01109 goto errxit2;
01110 }
01111
01112 if ((rc = ftpCheckResponse(u, NULL)))
01113 goto errxit;
01114
01115 if ((rc = ftpCommand(u, NULL, "USER", user, NULL)))
01116 goto errxit;
01117
01118 if ((rc = ftpCommand(u, NULL, "PASS", password, NULL)))
01119 goto errxit;
01120
01121 if ((rc = ftpCommand(u, NULL, "TYPE", "I", NULL)))
01122 goto errxit;
01123
01124
01125 return 0;
01126
01127
01128 errxit:
01129
01130 fdSetSyserrno(u->ctrl, errno, ftpStrerror(rc));
01131
01132 errxit2:
01133
01134 if (fdFileno(u->ctrl) >= 0)
01135 (void) fdClose(u->ctrl);
01136
01137
01138 return rc;
01139
01140
01141 }
01142
01143 int ftpReq(FD_t data, const char * ftpCmd, const char * ftpArg)
01144 {
01145 urlinfo u = data->url;
01146 struct sockaddr_in dataAddress;
01147 char * cmd;
01148 int cmdlen;
01149 char * passReply;
01150 char * chptr;
01151 int rc;
01152
01153 URLSANE(u);
01154 if (ftpCmd == NULL)
01155 return FTPERR_UNKNOWN;
01156
01157 cmdlen = strlen(ftpCmd) + (ftpArg ? 1+strlen(ftpArg) : 0) + sizeof("\r\n");
01158 chptr = cmd = alloca(cmdlen);
01159 chptr = stpcpy(chptr, ftpCmd);
01160 if (ftpArg) {
01161 *chptr++ = ' ';
01162 chptr = stpcpy(chptr, ftpArg);
01163 }
01164 chptr = stpcpy(chptr, "\r\n");
01165 cmdlen = chptr - cmd;
01166
01167
01168
01169
01170 if (!strncmp(cmd, "RETR", 4)) {
01171 unsigned cl;
01172
01173 passReply = NULL;
01174 rc = ftpCommand(u, &passReply, "SIZE", ftpArg, NULL);
01175 if (rc)
01176 goto errxit;
01177 if (sscanf(passReply, "%d %u", &rc, &cl) != 2) {
01178 rc = FTPERR_BAD_SERVER_RESPONSE;
01179 goto errxit;
01180 }
01181 rc = 0;
01182 data->contentLength = cl;
01183 }
01184
01185 passReply = NULL;
01186 rc = ftpCommand(u, &passReply, "PASV", NULL);
01187 if (rc) {
01188 rc = FTPERR_PASSIVE_ERROR;
01189 goto errxit;
01190 }
01191
01192 chptr = passReply;
01193 while (*chptr && *chptr != '(') chptr++;
01194 if (*chptr != '(') return FTPERR_PASSIVE_ERROR;
01195 chptr++;
01196 passReply = chptr;
01197 while (*chptr && *chptr != ')') chptr++;
01198 if (*chptr != ')') return FTPERR_PASSIVE_ERROR;
01199 *chptr-- = '\0';
01200
01201 while (*chptr && *chptr != ',') chptr--;
01202 if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
01203 chptr--;
01204 while (*chptr && *chptr != ',') chptr--;
01205 if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
01206 *chptr++ = '\0';
01207
01208
01209
01210
01211 { int i, j;
01212 memset(&dataAddress, 0, sizeof(dataAddress));
01213 dataAddress.sin_family = AF_INET;
01214 if (sscanf(chptr, "%d,%d", &i, &j) != 2) {
01215 rc = FTPERR_PASSIVE_ERROR;
01216 goto errxit;
01217 }
01218 dataAddress.sin_port = htons((((unsigned)i) << 8) + j);
01219 }
01220
01221 chptr = passReply;
01222 while (*chptr++ != '\0') {
01223 if (*chptr == ',') *chptr = '.';
01224 }
01225
01226
01227 if (!inet_aton(passReply, &dataAddress.sin_addr)) {
01228 rc = FTPERR_PASSIVE_ERROR;
01229 goto errxit;
01230 }
01231
01232
01233 rc = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
01234 fdSetFdno(data, (rc >= 0 ? rc : -1));
01235 if (rc < 0) {
01236 rc = FTPERR_FAILED_CONNECT;
01237 goto errxit;
01238 }
01239 data = fdLink(data, "open data (ftpReq)");
01240
01241
01242
01243
01244
01245
01246 while (connect(fdFileno(data), (struct sockaddr *) &dataAddress,
01247 sizeof(dataAddress)) < 0)
01248 {
01249 if (errno == EINTR)
01250 continue;
01251 rc = FTPERR_FAILED_DATA_CONNECT;
01252 goto errxit;
01253 }
01254
01255
01256 if (_ftp_debug)
01257 fprintf(stderr, "-> %s", cmd);
01258 if (fdWrite(u->ctrl, cmd, cmdlen) != cmdlen) {
01259 rc = FTPERR_SERVER_IO_ERROR;
01260 goto errxit;
01261 }
01262
01263 if ((rc = ftpCheckResponse(u, NULL))) {
01264 goto errxit;
01265 }
01266
01267 data->ftpFileDoneNeeded = 1;
01268 u->ctrl = fdLink(u->ctrl, "grab data (ftpReq)");
01269 u->ctrl = fdLink(u->ctrl, "open data (ftpReq)");
01270 return 0;
01271
01272 errxit:
01273
01274 fdSetSyserrno(u->ctrl, errno, ftpStrerror(rc));
01275
01276
01277 if (fdFileno(data) >= 0)
01278 (void) fdClose(data);
01279
01280 return rc;
01281 }
01282
01283
01284 static rpmCallbackFunction urlNotify = NULL;
01285
01286
01287 static void * urlNotifyData = NULL;
01288
01289
01290 static int urlNotifyCount = -1;
01291
01292 void urlSetCallback(rpmCallbackFunction notify, void *notifyData, int notifyCount) {
01293 urlNotify = notify;
01294 urlNotifyData = notifyData;
01295 urlNotifyCount = (notifyCount >= 0) ? notifyCount : 4096;
01296 }
01297
01298 int ufdCopy(FD_t sfd, FD_t tfd)
01299 {
01300 char buf[BUFSIZ];
01301 int itemsRead;
01302 int itemsCopied = 0;
01303 int rc = 0;
01304 int notifier = -1;
01305
01306 if (urlNotify) {
01307
01308 (void)(*urlNotify) (NULL, RPMCALLBACK_INST_OPEN_FILE,
01309 0, 0, NULL, urlNotifyData);
01310
01311 }
01312
01313 while (1) {
01314 rc = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd);
01315 if (rc < 0)
01316 break;
01317 else if (rc == 0) {
01318 rc = itemsCopied;
01319 break;
01320 }
01321 itemsRead = rc;
01322 rc = Fwrite(buf, sizeof(buf[0]), itemsRead, tfd);
01323 if (rc < 0)
01324 break;
01325 if (rc != itemsRead) {
01326 rc = FTPERR_FILE_IO_ERROR;
01327 break;
01328 }
01329
01330 itemsCopied += itemsRead;
01331 if (urlNotify && urlNotifyCount > 0) {
01332 int n = itemsCopied/urlNotifyCount;
01333 if (n != notifier) {
01334
01335 (void)(*urlNotify) (NULL, RPMCALLBACK_INST_PROGRESS,
01336 itemsCopied, 0, NULL, urlNotifyData);
01337
01338 notifier = n;
01339 }
01340 }
01341 }
01342
01343
01344 DBGIO(sfd, (stderr, "++ copied %d bytes: %s\n", itemsCopied,
01345 ftpStrerror(rc)));
01346
01347
01348 if (urlNotify) {
01349
01350 (void)(*urlNotify) (NULL, RPMCALLBACK_INST_OPEN_FILE,
01351 itemsCopied, itemsCopied, NULL, urlNotifyData);
01352
01353 }
01354
01355 return rc;
01356 }
01357
01358 static int urlConnect(const char * url, urlinfo * uret)
01359
01360
01361 {
01362 urlinfo u;
01363 int rc = 0;
01364
01365 if (urlSplit(url, &u) < 0)
01366 return -1;
01367
01368 if (u->urltype == URL_IS_FTP) {
01369 FD_t fd;
01370
01371 if ((fd = u->ctrl) == NULL) {
01372 fd = u->ctrl = fdNew("persist ctrl (urlConnect FTP)");
01373 fdSetIo(u->ctrl, ufdio);
01374 }
01375
01376 fd->rd_timeoutsecs = ftpTimeoutSecs;
01377 fd->contentLength = fd->bytesRemain = -1;
01378 fd->url = NULL;
01379 fd->ftpFileDoneNeeded = 0;
01380 fd = fdLink(fd, "grab ctrl (urlConnect FTP)");
01381
01382 if (fdFileno(u->ctrl) < 0) {
01383 rpmMessage(RPMMESS_DEBUG, _("logging into %s as %s, pw %s\n"),
01384 u->host ? u->host : "???",
01385 u->user ? u->user : "ftp",
01386 u->password ? u->password : "(username)");
01387
01388 if ((rc = ftpLogin(u)) < 0) {
01389 u->ctrl = fdFree(fd, "grab ctrl (urlConnect FTP)");
01390 u->openError = rc;
01391 }
01392 }
01393 }
01394
01395 if (uret != NULL)
01396 *uret = urlLink(u, "urlConnect");
01397 u = urlFree(u, "urlSplit (urlConnect)");
01398
01399 return rc;
01400 }
01401
01402 int ufdGetFile(FD_t sfd, FD_t tfd)
01403 {
01404 int rc;
01405
01406 FDSANE(sfd);
01407 FDSANE(tfd);
01408 rc = ufdCopy(sfd, tfd);
01409 (void) Fclose(sfd);
01410 if (rc > 0)
01411 rc = 0;
01412 return rc;
01413 }
01414
01415 int ftpCmd(const char * cmd, const char * url, const char * arg2)
01416 {
01417 urlinfo u;
01418 int rc;
01419 const char * path;
01420
01421 if (urlConnect(url, &u) < 0)
01422 return -1;
01423
01424 (void) urlPath(url, &path);
01425
01426 rc = ftpCommand(u, NULL, cmd, path, arg2, NULL);
01427 u->ctrl = fdFree(u->ctrl, "grab ctrl (ftpCmd)");
01428 return rc;
01429 }
01430
01431
01432 #if !defined(IAC)
01433 #define IAC 255
01434 #endif
01435 #if !defined(IP)
01436 #define IP 244
01437 #endif
01438 #if !defined(DM)
01439 #define DM 242
01440 #endif
01441 #if !defined(SHUT_RDWR)
01442 #define SHUT_RDWR 1+1
01443 #endif
01444
01445 static int ftpAbort(urlinfo u, FD_t data)
01446
01447
01448 {
01449 static unsigned char ipbuf[3] = { IAC, IP, IAC };
01450 FD_t ctrl;
01451 int rc;
01452 int tosecs;
01453
01454 URLSANE(u);
01455
01456 if (data != NULL) {
01457 data->ftpFileDoneNeeded = 0;
01458 if (fdFileno(data) >= 0)
01459 u->ctrl = fdFree(u->ctrl, "open data (ftpAbort)");
01460 u->ctrl = fdFree(u->ctrl, "grab data (ftpAbort)");
01461 }
01462 ctrl = u->ctrl;
01463
01464
01465 DBGIO(0, (stderr, "-> ABOR\n"));
01466
01467
01468
01469 if (send(fdFileno(ctrl), ipbuf, sizeof(ipbuf), MSG_OOB) != sizeof(ipbuf)) {
01470 (void) fdClose(ctrl);
01471 return FTPERR_SERVER_IO_ERROR;
01472 }
01473
01474 sprintf(u->buf, "%cABOR\r\n",(char) DM);
01475 if (fdWrite(ctrl, u->buf, 7) != 7) {
01476 (void) fdClose(ctrl);
01477 return FTPERR_SERVER_IO_ERROR;
01478 }
01479
01480 if (data && fdFileno(data) >= 0) {
01481
01482 tosecs = data->rd_timeoutsecs;
01483 data->rd_timeoutsecs = 10;
01484 if (fdReadable(data, data->rd_timeoutsecs) > 0) {
01485 while (timedRead(data, u->buf, u->bufAlloced) > 0)
01486 u->buf[0] = '\0';
01487 }
01488 data->rd_timeoutsecs = tosecs;
01489
01490 (void) shutdown(fdFileno(data), SHUT_RDWR);
01491 (void) close(fdFileno(data));
01492 data->fps[0].fdno = -1;
01493 }
01494
01495
01496 tosecs = u->ctrl->rd_timeoutsecs;
01497 u->ctrl->rd_timeoutsecs = 10;
01498 if ((rc = ftpCheckResponse(u, NULL)) == FTPERR_NIC_ABORT_IN_PROGRESS) {
01499 rc = ftpCheckResponse(u, NULL);
01500 }
01501 rc = ftpCheckResponse(u, NULL);
01502 u->ctrl->rd_timeoutsecs = tosecs;
01503
01504 return rc;
01505
01506 }
01507
01508 static int ftpFileDone(urlinfo u, FD_t data)
01509
01510
01511 {
01512 int rc = 0;
01513
01514 URLSANE(u);
01515 assert(data->ftpFileDoneNeeded);
01516
01517 if (data->ftpFileDoneNeeded) {
01518 data->ftpFileDoneNeeded = 0;
01519 u->ctrl = fdFree(u->ctrl, "open data (ftpFileDone)");
01520 u->ctrl = fdFree(u->ctrl, "grab data (ftpFileDone)");
01521 rc = ftpCheckResponse(u, NULL);
01522 }
01523 return rc;
01524 }
01525
01526 static int httpResp(urlinfo u, FD_t ctrl, char ** str)
01527
01528
01529 {
01530 int ec = 0;
01531 int rc;
01532
01533 URLSANE(u);
01534 rc = checkResponse(u, ctrl, &ec, str);
01535
01536 if (_ftp_debug && !(rc == 0 && ec == 200))
01537 fprintf(stderr, "*** httpResp: rc %d ec %d\n", rc, ec);
01538
01539 switch (ec) {
01540 case 200:
01541 break;
01542 default:
01543 rc = FTPERR_FILE_NOT_FOUND;
01544 break;
01545 }
01546
01547 return rc;
01548 }
01549
01550 static int httpReq(FD_t ctrl, const char * httpCmd, const char * httpArg)
01551
01552
01553 {
01554 urlinfo u = ctrl->url;
01555 const char * host;
01556 const char * path;
01557 int port;
01558 int rc;
01559 char * req;
01560 size_t len;
01561 int retrying = 0;
01562
01563 URLSANE(u);
01564 assert(ctrl != NULL);
01565
01566 if (((host = (u->proxyh ? u->proxyh : u->host)) == NULL))
01567 return FTPERR_BAD_HOSTNAME;
01568
01569 if ((port = (u->proxyp > 0 ? u->proxyp : u->port)) < 0) port = 80;
01570 path = (u->proxyh || u->proxyp > 0) ? u->url : httpArg;
01571
01572 if (path == NULL) path = "";
01573
01574
01575 reopen:
01576
01577 if (fdFileno(ctrl) >= 0 && (rc = fdWritable(ctrl, 0)) < 1) {
01578 (void) fdClose(ctrl);
01579 }
01580
01581
01582
01583 if (fdFileno(ctrl) < 0) {
01584 rc = tcpConnect(ctrl, host, port);
01585 if (rc < 0)
01586 goto errxit2;
01587 ctrl = fdLink(ctrl, "open ctrl (httpReq)");
01588 }
01589
01590 len = sizeof("\
01591 req x HTTP/1.0\r\n\
01592 User-Agent: rpm/3.0.4\r\n\
01593 Host: y:z\r\n\
01594 Accept: text/plain\r\n\
01595 Transfer-Encoding: chunked\r\n\
01596 \r\n\
01597 ") + strlen(httpCmd) + strlen(path) + sizeof(VERSION) + strlen(host) + 20;
01598
01599 req = alloca(len);
01600 *req = '\0';
01601
01602 if (!strcmp(httpCmd, "PUT")) {
01603 sprintf(req, "\
01604 %s %s HTTP/1.%d\r\n\
01605 User-Agent: rpm/%s\r\n\
01606 Host: %s:%d\r\n\
01607 Accept: text/plain\r\n\
01608 Transfer-Encoding: chunked\r\n\
01609 \r\n\
01610 ", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, host, port);
01611 } else {
01612 sprintf(req, "\
01613 %s %s HTTP/1.%d\r\n\
01614 User-Agent: rpm/%s\r\n\
01615 Host: %s:%d\r\n\
01616 Accept: text/plain\r\n\
01617 \r\n\
01618 ", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, host, port);
01619 }
01620
01621 if (_ftp_debug)
01622 fprintf(stderr, "-> %s", req);
01623
01624 len = strlen(req);
01625 if (fdWrite(ctrl, req, len) != len) {
01626 rc = FTPERR_SERVER_IO_ERROR;
01627 goto errxit;
01628 }
01629
01630
01631 if (!strcmp(httpCmd, "PUT")) {
01632 ctrl->wr_chunked = 1;
01633 } else {
01634
01635 rc = httpResp(u, ctrl, NULL);
01636
01637 if (rc) {
01638 if (!retrying) {
01639 retrying = 1;
01640 (void) fdClose(ctrl);
01641 goto reopen;
01642 }
01643 goto errxit;
01644 }
01645 }
01646
01647
01648 ctrl = fdLink(ctrl, "open data (httpReq)");
01649 return 0;
01650
01651 errxit:
01652
01653 fdSetSyserrno(ctrl, errno, ftpStrerror(rc));
01654
01655 errxit2:
01656
01657 if (fdFileno(ctrl) >= 0)
01658 (void) fdClose(ctrl);
01659
01660 return rc;
01661
01662 }
01663
01664
01665 void * ufdGetUrlinfo(FD_t fd)
01666 {
01667 FDSANE(fd);
01668 if (fd->url == NULL)
01669 return NULL;
01670 return urlLink(fd->url, "ufdGetUrlinfo");
01671 }
01672
01673
01674 static ssize_t ufdRead(void * cookie, char * buf, size_t count)
01675
01676
01677 {
01678 FD_t fd = c2f(cookie);
01679 int bytesRead;
01680 int total;
01681
01682 *buf = '\0';
01683
01684 if (fdGetIo(fd) == fdio) {
01685 struct stat sb;
01686 int fdno = fdFileno(fd);
01687 (void) fstat(fdno, &sb);
01688 if (S_ISREG(sb.st_mode))
01689 return fdRead(fd, buf, count);
01690 }
01691
01692 UFDONLY(fd);
01693 assert(fd->rd_timeoutsecs >= 0);
01694
01695 for (total = 0; total < count; total += bytesRead) {
01696
01697 int rc;
01698
01699 bytesRead = 0;
01700
01701
01702 if (fd->bytesRemain == 0) return total;
01703 rc = fdReadable(fd, fd->rd_timeoutsecs);
01704
01705 switch (rc) {
01706 case -1:
01707 case 0:
01708 return total;
01709 break;
01710 default:
01711 break;
01712 }
01713
01714 rc = fdRead(fd, buf + total, count - total);
01715
01716 if (rc < 0) {
01717 switch (errno) {
01718 case EWOULDBLOCK:
01719 continue;
01720 break;
01721 default:
01722 break;
01723 }
01724 if (_rpmio_debug)
01725 fprintf(stderr, "*** read: rc %d errno %d %s \"%s\"\n", rc, errno, strerror(errno), buf);
01726 return rc;
01727 break;
01728 } else if (rc == 0) {
01729 return total;
01730 break;
01731 }
01732 bytesRead = rc;
01733 }
01734
01735 return count;
01736 }
01737
01738 static ssize_t ufdWrite(void * cookie, const char * buf, size_t count)
01739
01740
01741 {
01742 FD_t fd = c2f(cookie);
01743 int bytesWritten;
01744 int total = 0;
01745
01746 #ifdef NOTYET
01747 if (fdGetIo(fd) == fdio) {
01748 struct stat sb;
01749 (void) fstat(fdGetFdno(fd), &sb);
01750 if (S_ISREG(sb.st_mode))
01751 return fdWrite(fd, buf, count);
01752 }
01753 #endif
01754
01755 UFDONLY(fd);
01756
01757 for (total = 0; total < count; total += bytesWritten) {
01758
01759 int rc;
01760
01761 bytesWritten = 0;
01762
01763
01764 if (fd->bytesRemain == 0) {
01765 fprintf(stderr, "*** ufdWrite fd %p WRITE PAST END OF CONTENT\n", fd);
01766 return total;
01767 }
01768 rc = fdWritable(fd, 2);
01769
01770 switch (rc) {
01771 case -1:
01772 case 0:
01773 return total;
01774 break;
01775 default:
01776 break;
01777 }
01778
01779 rc = fdWrite(fd, buf + total, count - total);
01780
01781 if (rc < 0) {
01782 switch (errno) {
01783 case EWOULDBLOCK:
01784 continue;
01785 break;
01786 default:
01787 break;
01788 }
01789 if (_rpmio_debug)
01790 fprintf(stderr, "*** write: rc %d errno %d %s \"%s\"\n", rc, errno, strerror(errno), buf);
01791 return rc;
01792 break;
01793 } else if (rc == 0) {
01794 return total;
01795 break;
01796 }
01797 bytesWritten = rc;
01798 }
01799
01800 return count;
01801 }
01802
01803 static inline int ufdSeek(void * cookie, _libio_pos_t pos, int whence)
01804
01805
01806 {
01807 FD_t fd = c2f(cookie);
01808
01809 switch (fd->urlType) {
01810 case URL_IS_UNKNOWN:
01811 case URL_IS_PATH:
01812 break;
01813 case URL_IS_DASH:
01814 case URL_IS_FTP:
01815 case URL_IS_HTTP:
01816 default:
01817 return -2;
01818 break;
01819 }
01820 return fdSeek(cookie, pos, whence);
01821 }
01822
01823
01824
01825 int ufdClose( void * cookie)
01826 {
01827 FD_t fd = c2f(cookie);
01828
01829 UFDONLY(fd);
01830
01831
01832 if (fd->url) {
01833 urlinfo u = fd->url;
01834
01835 if (fd == u->data)
01836 fd = u->data = fdFree(fd, "grab data (ufdClose persist)");
01837 else
01838 fd = fdFree(fd, "grab data (ufdClose)");
01839 (void) urlFree(fd->url, "url (ufdClose)");
01840 fd->url = NULL;
01841 u->ctrl = fdFree(u->ctrl, "grab ctrl (ufdClose)");
01842
01843 if (u->urltype == URL_IS_FTP) {
01844
01845
01846 { FILE * fp;
01847
01848 fp = fdGetFILE(fd);
01849 if (noLibio && fp)
01850 fdSetFp(fd, NULL);
01851
01852 }
01853
01854
01855
01856
01857
01858
01859
01860
01861
01862
01863
01864
01865
01866
01867
01868 if (fd->bytesRemain > 0) {
01869 if (fd->ftpFileDoneNeeded) {
01870 if (fdReadable(u->ctrl, 0) > 0)
01871 (void) ftpFileDone(u, fd);
01872 else
01873 (void) ftpAbort(u, fd);
01874 }
01875 } else {
01876 int rc;
01877
01878
01879 rc = fdClose(fd);
01880
01881 #if 0
01882 assert(fd->ftpFileDoneNeeded != 0);
01883 #endif
01884
01885 if (fd->ftpFileDoneNeeded)
01886 (void) ftpFileDone(u, fd);
01887
01888 return rc;
01889 }
01890 }
01891
01892
01893 if (u->service != NULL && !strcmp(u->service, "http")) {
01894 if (fd->wr_chunked) {
01895 int rc;
01896
01897 (void) fdWrite(fd, NULL, 0);
01898 fd->wr_chunked = 0;
01899
01900 if (_ftp_debug)
01901 fprintf(stderr, "-> \r\n");
01902 (void) fdWrite(fd, "\r\n", sizeof("\r\n")-1);
01903 rc = httpResp(u, fd, NULL);
01904 }
01905
01906 if (fd == u->ctrl)
01907 fd = u->ctrl = fdFree(fd, "open data (ufdClose HTTP persist ctrl)");
01908 else if (fd == u->data)
01909 fd = u->data = fdFree(fd, "open data (ufdClose HTTP persist data)");
01910 else
01911 fd = fdFree(fd, "open data (ufdClose HTTP)");
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923 { FILE * fp;
01924
01925 fp = fdGetFILE(fd);
01926 if (noLibio && fp)
01927 fdSetFp(fd, NULL);
01928
01929 }
01930
01931 if (fd->persist && u->httpVersion &&
01932 (fd == u->ctrl || fd == u->data) && fd->bytesRemain == 0) {
01933 fd->contentLength = fd->bytesRemain = -1;
01934 return 0;
01935 } else {
01936 fd->contentLength = fd->bytesRemain = -1;
01937 }
01938 }
01939 }
01940 return fdClose(fd);
01941 }
01942
01943
01944
01945
01946 FD_t ftpOpen(const char *url, int flags,
01947 mode_t mode, urlinfo *uret)
01948
01949 {
01950 urlinfo u = NULL;
01951 FD_t fd = NULL;
01952
01953 #if 0
01954 assert(!(flags & O_RDWR));
01955 #endif
01956 if (urlConnect(url, &u) < 0)
01957 goto exit;
01958
01959 if (u->data == NULL)
01960 u->data = fdNew("persist data (ftpOpen)");
01961
01962 if (u->data->url == NULL)
01963 fd = fdLink(u->data, "grab data (ftpOpen persist data)");
01964 else
01965 fd = fdNew("grab data (ftpOpen)");
01966
01967 if (fd) {
01968 fdSetIo(fd, ufdio);
01969 fd->ftpFileDoneNeeded = 0;
01970 fd->rd_timeoutsecs = ftpTimeoutSecs;
01971 fd->contentLength = fd->bytesRemain = -1;
01972 fd->url = urlLink(u, "url (ufdOpen FTP)");
01973 fd->urlType = URL_IS_FTP;
01974 }
01975
01976 exit:
01977 if (uret)
01978 *uret = u;
01979
01980 return fd;
01981
01982 }
01983
01984
01985
01986 static FD_t httpOpen(const char * url, int flags,
01987 mode_t mode, urlinfo * uret)
01988
01989 {
01990 urlinfo u = NULL;
01991 FD_t fd = NULL;
01992
01993 #if 0
01994 assert(!(flags & O_RDWR));
01995 #endif
01996 if (urlSplit(url, &u))
01997 goto exit;
01998
01999 if (u->ctrl == NULL)
02000 u->ctrl = fdNew("persist ctrl (httpOpen)");
02001 if (u->ctrl->nrefs > 2 && u->data == NULL)
02002 u->data = fdNew("persist data (httpOpen)");
02003
02004 if (u->ctrl->url == NULL)
02005 fd = fdLink(u->ctrl, "grab ctrl (httpOpen persist ctrl)");
02006 else if (u->data->url == NULL)
02007 fd = fdLink(u->data, "grab ctrl (httpOpen persist data)");
02008 else
02009 fd = fdNew("grab ctrl (httpOpen)");
02010
02011 if (fd) {
02012 fdSetIo(fd, ufdio);
02013 fd->ftpFileDoneNeeded = 0;
02014 fd->rd_timeoutsecs = httpTimeoutSecs;
02015 fd->contentLength = fd->bytesRemain = -1;
02016 fd->url = urlLink(u, "url (httpOpen)");
02017 fd = fdLink(fd, "grab data (httpOpen)");
02018 fd->urlType = URL_IS_HTTP;
02019 }
02020
02021 exit:
02022 if (uret)
02023 *uret = u;
02024
02025 return fd;
02026
02027 }
02028
02029
02030 static FD_t ufdOpen(const char * url, int flags, mode_t mode)
02031
02032
02033 {
02034 FD_t fd = NULL;
02035 const char * cmd;
02036 urlinfo u;
02037 const char * path;
02038 urltype urlType = urlPath(url, &path);
02039
02040 if (_rpmio_debug)
02041 fprintf(stderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mode);
02042
02043
02044 switch (urlType) {
02045 case URL_IS_FTP:
02046 fd = ftpOpen(url, flags, mode, &u);
02047 if (fd == NULL || u == NULL)
02048 break;
02049
02050
02051 cmd = ((flags & O_WRONLY)
02052 ? ((flags & O_APPEND) ? "APPE" :
02053 ((flags & O_CREAT) ? "STOR" : "STOR"))
02054 : ((flags & O_CREAT) ? "STOR" : "RETR"));
02055 u->openError = ftpReq(fd, cmd, path);
02056 if (u->openError < 0) {
02057
02058 fd = fdLink(fd, "error data (ufdOpen FTP)");
02059 } else {
02060 fd->bytesRemain = ((!strcmp(cmd, "RETR"))
02061 ? fd->contentLength : -1);
02062 fd->wr_chunked = 0;
02063 }
02064 break;
02065 case URL_IS_HTTP:
02066 fd = httpOpen(url, flags, mode, &u);
02067 if (fd == NULL || u == NULL)
02068 break;
02069
02070 cmd = ((flags & O_WRONLY)
02071 ? ((flags & O_APPEND) ? "PUT" :
02072 ((flags & O_CREAT) ? "PUT" : "PUT"))
02073 : "GET");
02074 u->openError = httpReq(fd, cmd, path);
02075 if (u->openError < 0) {
02076
02077 fd = fdLink(fd, "error ctrl (ufdOpen HTTP)");
02078 fd = fdLink(fd, "error data (ufdOpen HTTP)");
02079 } else {
02080 fd->bytesRemain = ((!strcmp(cmd, "GET"))
02081 ? fd->contentLength : -1);
02082 fd->wr_chunked = ((!strcmp(cmd, "PUT"))
02083 ? fd->wr_chunked : 0);
02084 }
02085 break;
02086 case URL_IS_DASH:
02087 assert(!(flags & O_RDWR));
02088 fd = fdDup( ((flags & O_WRONLY) ? STDOUT_FILENO : STDIN_FILENO) );
02089 if (fd) {
02090 fdSetIo(fd, ufdio);
02091 fd->rd_timeoutsecs = 600;
02092 fd->contentLength = fd->bytesRemain = -1;
02093 }
02094 break;
02095 case URL_IS_PATH:
02096 case URL_IS_UNKNOWN:
02097 default:
02098 fd = fdOpen(path, flags, mode);
02099 if (fd) {
02100 fdSetIo(fd, ufdio);
02101 fd->rd_timeoutsecs = 1;
02102 fd->contentLength = fd->bytesRemain = -1;
02103 }
02104 break;
02105 }
02106
02107
02108 if (fd == NULL) return NULL;
02109 fd->urlType = urlType;
02110 if (Fileno(fd) < 0) {
02111 (void) ufdClose(fd);
02112 return NULL;
02113 }
02114
02115 DBGIO(fd, (stderr, "==>\tufdOpen(\"%s\",%x,0%o) %s\n", url, (unsigned)flags, (unsigned)mode, fdbg(fd)));
02116
02117 return fd;
02118 }
02119
02120 static struct FDIO_s ufdio_s = {
02121 ufdRead, ufdWrite, ufdSeek, ufdClose, XfdLink, XfdFree, XfdNew, fdFileno,
02122 ufdOpen, NULL, fdGetFp, NULL, Mkdir, Chdir, Rmdir, Rename, Unlink
02123 };
02124 FDIO_t ufdio = &ufdio_s ;
02125
02126
02127
02128
02129 #ifdef HAVE_ZLIB_H
02130
02131
02132
02133 #include <zlib.h>
02134
02135
02136 static inline void * gzdFileno(FD_t fd)
02137
02138 {
02139 void * rc = NULL;
02140 int i;
02141
02142 FDSANE(fd);
02143 for (i = fd->nfps; i >= 0; i--) {
02144 FDSTACK_t * fps = &fd->fps[i];
02145 if (fps->io != gzdio)
02146 continue;
02147 rc = fps->fp;
02148 break;
02149 }
02150
02151 return rc;
02152 }
02153
02154 static FD_t gzdOpen(const char * path, const char * fmode)
02155
02156
02157 {
02158 FD_t fd;
02159 gzFile *gzfile;
02160 if ((gzfile = gzopen(path, fmode)) == NULL)
02161 return NULL;
02162 fd = fdNew("open (gzdOpen)");
02163 fdPop(fd); fdPush(fd, gzdio, gzfile, -1);
02164
02165
02166 DBGIO(fd, (stderr, "==>\tgzdOpen(\"%s\", \"%s\") fd %p %s\n", path, fmode, (fd ? fd : NULL), fdbg(fd)));
02167
02168 return fdLink(fd, "gzdOpen");
02169 }
02170
02171
02172 static FD_t gzdFdopen(void * cookie, const char *fmode)
02173
02174
02175 {
02176 FD_t fd = c2f(cookie);
02177 int fdno;
02178 gzFile *gzfile;
02179
02180 if (fmode == NULL) return NULL;
02181 fdno = fdFileno(fd);
02182 fdSetFdno(fd, -1);
02183 if (fdno < 0) return NULL;
02184 gzfile = gzdopen(fdno, fmode);
02185 if (gzfile == NULL) return NULL;
02186
02187 fdPush(fd, gzdio, gzfile, fdno);
02188
02189 return fdLink(fd, "gzdFdopen");
02190 }
02191
02192
02193
02194 static int gzdFlush(FD_t fd)
02195
02196
02197 {
02198 gzFile *gzfile;
02199 gzfile = gzdFileno(fd);
02200 if (gzfile == NULL) return -2;
02201 return gzflush(gzfile, Z_SYNC_FLUSH);
02202 }
02203
02204
02205
02206
02207 static ssize_t gzdRead(void * cookie, char * buf, size_t count)
02208
02209
02210 {
02211 FD_t fd = c2f(cookie);
02212 gzFile *gzfile;
02213 ssize_t rc;
02214
02215 if (fd == NULL || fd->bytesRemain == 0) return 0;
02216
02217 gzfile = gzdFileno(fd);
02218 if (gzfile == NULL) return -2;
02219
02220 fdstat_enter(fd, FDSTAT_READ);
02221
02222 rc = gzread(gzfile, buf, count);
02223
02224 DBGIO(fd, (stderr, "==>\tgzdRead(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
02225
02226
02227 if (rc < 0) {
02228 int zerror = 0;
02229 fd->errcookie = gzerror(gzfile, &zerror);
02230 if (zerror == Z_ERRNO) {
02231 fd->syserrno = errno;
02232 fd->errcookie = strerror(fd->syserrno);
02233 }
02234 } else if (rc >= 0) {
02235 fdstat_exit(fd, FDSTAT_READ, rc);
02236
02237 if (fd->ndigests && rc > 0) fdUpdateDigests(fd, buf, rc);
02238
02239 }
02240 return rc;
02241 }
02242
02243
02244 static ssize_t gzdWrite(void * cookie, const char * buf, size_t count)
02245
02246
02247 {
02248 FD_t fd = c2f(cookie);
02249 gzFile *gzfile;
02250 ssize_t rc;
02251
02252 if (fd == NULL || fd->bytesRemain == 0) return 0;
02253
02254 if (fd->ndigests && count > 0) fdUpdateDigests(fd, buf, count);
02255
02256 gzfile = gzdFileno(fd);
02257 if (gzfile == NULL) return -2;
02258
02259 fdstat_enter(fd, FDSTAT_WRITE);
02260 rc = gzwrite(gzfile, (void *)buf, count);
02261
02262 DBGIO(fd, (stderr, "==>\tgzdWrite(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
02263
02264 if (rc < 0) {
02265 int zerror = 0;
02266 fd->errcookie = gzerror(gzfile, &zerror);
02267 if (zerror == Z_ERRNO) {
02268 fd->syserrno = errno;
02269 fd->errcookie = strerror(fd->syserrno);
02270 }
02271 } else if (rc > 0) {
02272 fdstat_exit(fd, FDSTAT_WRITE, rc);
02273 }
02274 return rc;
02275 }
02276
02277
02278 static inline int gzdSeek(void * cookie, _libio_pos_t pos, int whence)
02279
02280
02281 {
02282 #ifdef USE_COOKIE_SEEK_POINTER
02283 _IO_off64_t p = *pos;
02284 #else
02285 off_t p = pos;
02286 #endif
02287 int rc;
02288 #if HAVE_GZSEEK
02289 FD_t fd = c2f(cookie);
02290 gzFile *gzfile;
02291
02292 if (fd == NULL) return -2;
02293 assert(fd->bytesRemain == -1);
02294
02295 gzfile = gzdFileno(fd);
02296 if (gzfile == NULL) return -2;
02297
02298 fdstat_enter(fd, FDSTAT_SEEK);
02299 rc = gzseek(gzfile, p, whence);
02300
02301 DBGIO(fd, (stderr, "==>\tgzdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd)));
02302
02303 if (rc < 0) {
02304 int zerror = 0;
02305 fd->errcookie = gzerror(gzfile, &zerror);
02306 if (zerror == Z_ERRNO) {
02307 fd->syserrno = errno;
02308 fd->errcookie = strerror(fd->syserrno);
02309 }
02310 } else if (rc >= 0) {
02311 fdstat_exit(fd, FDSTAT_SEEK, rc);
02312 }
02313 #else
02314 rc = -2;
02315 #endif
02316 return rc;
02317 }
02318
02319 static int gzdClose( void * cookie)
02320
02321
02322 {
02323 FD_t fd = c2f(cookie);
02324 gzFile *gzfile;
02325 int rc;
02326
02327 gzfile = gzdFileno(fd);
02328 if (gzfile == NULL) return -2;
02329
02330 fdstat_enter(fd, FDSTAT_CLOSE);
02331
02332 rc = gzclose(gzfile);
02333
02334
02335
02336
02337 if (fd) {
02338
02339 DBGIO(fd, (stderr, "==>\tgzdClose(%p) zerror %d %s\n", cookie, rc, fdbg(fd)));
02340
02341 if (rc < 0) {
02342
02343 fd->errcookie = gzerror(gzfile, &rc);
02344
02345 if (rc == Z_ERRNO) {
02346 fd->syserrno = errno;
02347 fd->errcookie = strerror(fd->syserrno);
02348 }
02349 } else if (rc >= 0) {
02350 fdstat_exit(fd, FDSTAT_CLOSE, rc);
02351 }
02352 }
02353
02354
02355 DBGIO(fd, (stderr, "==>\tgzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
02356
02357
02358 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "GZDIO", stderr);
02359
02360 if (rc == 0)
02361 fd = fdFree(fd, "open (gzdClose)");
02362
02363 return rc;
02364 }
02365
02366 static struct FDIO_s gzdio_s = {
02367 gzdRead, gzdWrite, gzdSeek, gzdClose, XfdLink, XfdFree, XfdNew, fdFileno,
02368 NULL, gzdOpen, gzdFileno, gzdFlush, NULL, NULL, NULL, NULL, NULL
02369 };
02370 FDIO_t gzdio = &gzdio_s ;
02371
02372
02373 #endif
02374
02375
02376
02377
02378 #if HAVE_BZLIB_H
02379
02380
02381 #include <bzlib.h>
02382
02383 #ifdef HAVE_BZ2_1_0
02384 # define bzopen BZ2_bzopen
02385 # define bzclose BZ2_bzclose
02386 # define bzdopen BZ2_bzdopen
02387 # define bzerror BZ2_bzerror
02388 # define bzflush BZ2_bzflush
02389 # define bzread BZ2_bzread
02390 # define bzwrite BZ2_bzwrite
02391 #endif
02392
02393 static inline void * bzdFileno(FD_t fd)
02394
02395 {
02396 void * rc = NULL;
02397 int i;
02398
02399 FDSANE(fd);
02400 for (i = fd->nfps; i >= 0; i--) {
02401 FDSTACK_t * fps = &fd->fps[i];
02402 if (fps->io != bzdio)
02403 continue;
02404 rc = fps->fp;
02405 break;
02406 }
02407
02408 return rc;
02409 }
02410
02411
02412 static FD_t bzdOpen(const char * path, const char * mode)
02413
02414
02415 {
02416 FD_t fd;
02417 BZFILE *bzfile;;
02418 if ((bzfile = bzopen(path, mode)) == NULL)
02419 return NULL;
02420 fd = fdNew("open (bzdOpen)");
02421 fdPop(fd); fdPush(fd, bzdio, bzfile, -1);
02422 return fdLink(fd, "bzdOpen");
02423 }
02424
02425
02426
02427 static FD_t bzdFdopen(void * cookie, const char * fmode)
02428
02429
02430 {
02431 FD_t fd = c2f(cookie);
02432 int fdno;
02433 BZFILE *bzfile;
02434
02435 if (fmode == NULL) return NULL;
02436 fdno = fdFileno(fd);
02437 fdSetFdno(fd, -1);
02438 if (fdno < 0) return NULL;
02439 bzfile = bzdopen(fdno, fmode);
02440 if (bzfile == NULL) return NULL;
02441
02442 fdPush(fd, bzdio, bzfile, fdno);
02443
02444 return fdLink(fd, "bzdFdopen");
02445 }
02446
02447
02448
02449 static int bzdFlush(FD_t fd)
02450
02451
02452 {
02453 return bzflush(bzdFileno(fd));
02454 }
02455
02456
02457
02458
02459
02460 static ssize_t bzdRead(void * cookie, char * buf, size_t count)
02461
02462
02463 {
02464 FD_t fd = c2f(cookie);
02465 BZFILE *bzfile;
02466 ssize_t rc = 0;
02467
02468 if (fd->bytesRemain == 0) return 0;
02469 bzfile = bzdFileno(fd);
02470 fdstat_enter(fd, FDSTAT_READ);
02471 if (bzfile)
02472
02473 rc = bzread(bzfile, buf, count);
02474
02475 if (rc == -1) {
02476 int zerror = 0;
02477 if (bzfile)
02478 fd->errcookie = bzerror(bzfile, &zerror);
02479 } else if (rc >= 0) {
02480 fdstat_exit(fd, FDSTAT_READ, rc);
02481
02482 if (fd->ndigests && rc > 0) fdUpdateDigests(fd, buf, rc);
02483
02484 }
02485 return rc;
02486 }
02487
02488
02489
02490
02491 static ssize_t bzdWrite(void * cookie, const char * buf, size_t count)
02492
02493
02494 {
02495 FD_t fd = c2f(cookie);
02496 BZFILE *bzfile;
02497 ssize_t rc;
02498
02499 if (fd->bytesRemain == 0) return 0;
02500
02501 if (fd->ndigests && count > 0) fdUpdateDigests(fd, buf, count);
02502
02503 bzfile = bzdFileno(fd);
02504 fdstat_enter(fd, FDSTAT_WRITE);
02505 rc = bzwrite(bzfile, (void *)buf, count);
02506 if (rc == -1) {
02507 int zerror = 0;
02508 fd->errcookie = bzerror(bzfile, &zerror);
02509 } else if (rc > 0) {
02510 fdstat_exit(fd, FDSTAT_WRITE, rc);
02511 }
02512 return rc;
02513 }
02514
02515
02516 static inline int bzdSeek(void * cookie, _libio_pos_t pos,
02517 int whence)
02518
02519 {
02520 FD_t fd = c2f(cookie);
02521
02522 BZDONLY(fd);
02523 return -2;
02524 }
02525
02526 static int bzdClose( void * cookie)
02527
02528
02529 {
02530 FD_t fd = c2f(cookie);
02531 BZFILE *bzfile;
02532 int rc;
02533
02534 bzfile = bzdFileno(fd);
02535
02536 if (bzfile == NULL) return -2;
02537 fdstat_enter(fd, FDSTAT_CLOSE);
02538
02539 bzclose(bzfile);
02540
02541 rc = 0;
02542
02543
02544
02545 if (fd) {
02546 if (rc == -1) {
02547 int zerror = 0;
02548 fd->errcookie = bzerror(bzfile, &zerror);
02549 } else if (rc >= 0) {
02550 fdstat_exit(fd, FDSTAT_CLOSE, rc);
02551 }
02552 }
02553
02554
02555 DBGIO(fd, (stderr, "==>\tbzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
02556
02557
02558 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "BZDIO", stderr);
02559
02560 if (rc == 0)
02561 fd = fdFree(fd, "open (bzdClose)");
02562
02563 return rc;
02564 }
02565
02566 static struct FDIO_s bzdio_s = {
02567 bzdRead, bzdWrite, bzdSeek, bzdClose, XfdLink, XfdFree, XfdNew, fdFileno,
02568 NULL, bzdOpen, bzdFileno, bzdFlush, NULL, NULL, NULL, NULL, NULL
02569 };
02570 FDIO_t bzdio = &bzdio_s ;
02571
02572
02573 #endif
02574
02575
02576 static const char * getFdErrstr (FD_t fd)
02577
02578 {
02579 const char *errstr = NULL;
02580
02581 #ifdef HAVE_ZLIB_H
02582 if (fdGetIo(fd) == gzdio) {
02583 errstr = fd->errcookie;
02584 } else
02585 #endif
02586
02587 #ifdef HAVE_BZLIB_H
02588 if (fdGetIo(fd) == bzdio) {
02589 errstr = fd->errcookie;
02590 } else
02591 #endif
02592
02593 {
02594 errstr = strerror(fd->syserrno);
02595 }
02596
02597 return errstr;
02598 }
02599
02600
02601
02602 const char *Fstrerror(FD_t fd)
02603 {
02604 if (fd == NULL)
02605 return strerror(errno);
02606 FDSANE(fd);
02607 return getFdErrstr(fd);
02608 }
02609
02610 #define FDIOVEC(_fd, _vec) \
02611 ((fdGetIo(_fd) && fdGetIo(_fd)->_vec) ? fdGetIo(_fd)->_vec : NULL)
02612
02613 size_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd) {
02614 fdio_read_function_t _read;
02615 int rc;
02616
02617 FDSANE(fd);
02618 #ifdef __LCLINT__
02619 *(char *)buf = '\0';
02620 #endif
02621
02622 DBGIO(fd, (stderr, "==> Fread(%p,%u,%u,%p) %s\n", buf, (unsigned)size, (unsigned)nmemb, (fd ? fd : NULL), fdbg(fd)));
02623
02624
02625 if (fdGetIo(fd) == fpio) {
02626
02627 rc = fread(buf, size, nmemb, fdGetFILE(fd));
02628
02629 return rc;
02630 }
02631
02632
02633 _read = FDIOVEC(fd, read);
02634
02635
02636 rc = (_read ? (*_read) (fd, buf, size * nmemb) : -2);
02637 return rc;
02638 }
02639
02640 size_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
02641 {
02642 fdio_write_function_t _write;
02643 int rc;
02644
02645 FDSANE(fd);
02646
02647 DBGIO(fd, (stderr, "==> Fwrite(%p,%u,%u,%p) %s\n", buf, (unsigned)size, (unsigned)nmemb, (fd ? fd : NULL), fdbg(fd)));
02648
02649
02650 if (fdGetIo(fd) == fpio) {
02651
02652 rc = fwrite(buf, size, nmemb, fdGetFILE(fd));
02653
02654 return rc;
02655 }
02656
02657
02658 _write = FDIOVEC(fd, write);
02659
02660
02661 rc = (_write ? _write(fd, buf, size * nmemb) : -2);
02662 return rc;
02663 }
02664
02665 int Fseek(FD_t fd, _libio_off_t offset, int whence) {
02666 fdio_seek_function_t _seek;
02667 #ifdef USE_COOKIE_SEEK_POINTER
02668 _IO_off64_t o64 = offset;
02669 _libio_pos_t pos = &o64;
02670 #else
02671 _libio_pos_t pos = offset;
02672 #endif
02673
02674 long int rc;
02675
02676 FDSANE(fd);
02677
02678 DBGIO(fd, (stderr, "==> Fseek(%p,%ld,%d) %s\n", fd, (long)offset, whence, fdbg(fd)));
02679
02680
02681 if (fdGetIo(fd) == fpio) {
02682 FILE *fp;
02683
02684
02685 fp = fdGetFILE(fd);
02686 rc = fseek(fp, offset, whence);
02687
02688 return rc;
02689 }
02690
02691
02692 _seek = FDIOVEC(fd, seek);
02693
02694
02695 rc = (_seek ? _seek(fd, pos, whence) : -2);
02696 return rc;
02697 }
02698
02699 int Fclose(FD_t fd)
02700 {
02701 int rc = 0, ec = 0;
02702
02703 FDSANE(fd);
02704
02705 DBGIO(fd, (stderr, "==> Fclose(%p) %s\n", (fd ? fd : NULL), fdbg(fd)));
02706
02707
02708 fd = fdLink(fd, "Fclose");
02709
02710 while (fd->nfps >= 0) {
02711 FDSTACK_t * fps = &fd->fps[fd->nfps];
02712
02713 if (fps->io == fpio) {
02714 FILE *fp;
02715 int fpno;
02716
02717
02718 fp = fdGetFILE(fd);
02719 fpno = fileno(fp);
02720
02721
02722 if (fd->nfps > 0 && fpno == -1 &&
02723 fd->fps[fd->nfps-1].io == ufdio &&
02724 fd->fps[fd->nfps-1].fp == fp &&
02725 fd->fps[fd->nfps-1].fdno >= 0)
02726 {
02727 if (fp)
02728 rc = fflush(fp);
02729 fd->nfps--;
02730
02731 rc = ufdClose(fd);
02732
02733
02734 if (fdGetFdno(fd) >= 0)
02735 break;
02736 fdSetFp(fd, NULL);
02737 fd->nfps++;
02738 if (fp)
02739 rc = fclose(fp);
02740 fdPop(fd);
02741 if (noLibio)
02742 fdSetFp(fd, NULL);
02743 } else {
02744 if (fp)
02745 rc = fclose(fp);
02746 if (fpno == -1) {
02747 fd = fdFree(fd, "fopencookie (Fclose)");
02748 fdPop(fd);
02749 }
02750 }
02751 } else {
02752
02753 fdio_close_function_t _close = FDIOVEC(fd, close);
02754
02755 rc = _close(fd);
02756 }
02757 if (fd->nfps == 0)
02758 break;
02759 if (ec == 0 && rc)
02760 ec = rc;
02761 fdPop(fd);
02762 }
02763
02764 fd = fdFree(fd, "Fclose");
02765 return ec;
02766
02767 }
02768
02780 static inline void cvtfmode (const char *m,
02781 char *stdio, size_t nstdio,
02782 char *other, size_t nother,
02783 const char **end, int * f)
02784
02785 {
02786 int flags = 0;
02787 char c;
02788
02789 switch (*m) {
02790 case 'a':
02791 flags |= O_WRONLY | O_CREAT | O_APPEND;
02792 if (--nstdio > 0) *stdio++ = *m;
02793 break;
02794 case 'w':
02795 flags |= O_WRONLY | O_CREAT | O_TRUNC;
02796 if (--nstdio > 0) *stdio++ = *m;
02797 break;
02798 case 'r':
02799 flags |= O_RDONLY;
02800 if (--nstdio > 0) *stdio++ = *m;
02801 break;
02802 default:
02803 *stdio = '\0';
02804 return;
02805 break;
02806 }
02807 m++;
02808
02809 while ((c = *m++) != '\0') {
02810 switch (c) {
02811 case '.':
02812 break;
02813 case '+':
02814 flags &= ~(O_RDONLY|O_WRONLY);
02815 flags |= O_RDWR;
02816 if (--nstdio > 0) *stdio++ = c;
02817 continue;
02818 break;
02819 case 'b':
02820 if (--nstdio > 0) *stdio++ = c;
02821 continue;
02822 break;
02823 case 'x':
02824 flags |= O_EXCL;
02825 if (--nstdio > 0) *stdio++ = c;
02826 continue;
02827 break;
02828 default:
02829 if (--nother > 0) *other++ = c;
02830 continue;
02831 break;
02832 }
02833 break;
02834 }
02835
02836 *stdio = *other = '\0';
02837 if (end != NULL)
02838 *end = (*m != '\0' ? m : NULL);
02839 if (f != NULL)
02840 *f = flags;
02841 }
02842
02843 #if _USE_LIBIO
02844 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0
02845
02846 typedef _IO_cookie_io_functions_t cookie_io_functions_t;
02847 #endif
02848 #endif
02849
02850 FD_t Fdopen(FD_t ofd, const char *fmode)
02851 {
02852 char stdio[20], other[20], zstdio[20];
02853 const char *end = NULL;
02854 FDIO_t iof = NULL;
02855 FD_t fd = ofd;
02856
02857 if (_rpmio_debug)
02858 fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
02859 FDSANE(fd);
02860
02861 if (fmode == NULL)
02862 return NULL;
02863
02864 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL);
02865 if (stdio[0] == '\0')
02866 return NULL;
02867 zstdio[0] = '\0';
02868 strncat(zstdio, stdio, sizeof(zstdio) - strlen(zstdio));
02869 strncat(zstdio, other, sizeof(zstdio) - strlen(zstdio));
02870
02871 if (end == NULL && other[0] == '\0')
02872 return fd;
02873
02874
02875 if (end && *end) {
02876 if (!strcmp(end, "fdio")) {
02877 iof = fdio;
02878 } else if (!strcmp(end, "gzdio")) {
02879 iof = gzdio;
02880
02881 fd = gzdFdopen(fd, zstdio);
02882
02883 #if HAVE_BZLIB_H
02884 } else if (!strcmp(end, "bzdio")) {
02885 iof = bzdio;
02886
02887 fd = bzdFdopen(fd, zstdio);
02888
02889 #endif
02890 } else if (!strcmp(end, "ufdio")) {
02891 iof = ufdio;
02892 } else if (!strcmp(end, "fadio")) {
02893 iof = fadio;
02894 } else if (!strcmp(end, "fpio")) {
02895 iof = fpio;
02896 if (noLibio) {
02897 int fdno = Fileno(fd);
02898 FILE * fp = fdopen(fdno, stdio);
02899
02900 if (_rpmio_debug)
02901 fprintf(stderr, "*** Fdopen fpio fp %p\n", (void *)fp);
02902
02903 if (fp == NULL)
02904 return NULL;
02905
02906
02907 if (fdGetFp(fd) == NULL)
02908 fdSetFp(fd, fp);
02909 fdPush(fd, fpio, fp, fdno);
02910
02911 }
02912 }
02913 } else if (other[0] != '\0') {
02914 for (end = other; *end && strchr("0123456789fh", *end); end++)
02915 {};
02916 if (*end == '\0') {
02917 iof = gzdio;
02918
02919 fd = gzdFdopen(fd, zstdio);
02920
02921 }
02922 }
02923
02924 if (iof == NULL)
02925 return fd;
02926
02927 if (!noLibio) {
02928 FILE * fp = NULL;
02929
02930 #if _USE_LIBIO
02931 { cookie_io_functions_t ciof;
02932 ciof.read = iof->read;
02933 ciof.write = iof->write;
02934 ciof.seek = iof->seek;
02935 ciof.close = iof->close;
02936 fp = fopencookie(fd, stdio, ciof);
02937
02938 DBGIO(fd, (stderr, "==> fopencookie(%p,\"%s\",*%p) returns fp %p\n", fd, stdio, iof, fp));
02939
02940 }
02941 #endif
02942
02943
02944 if (fp) {
02945
02946
02947 if (fdGetFp(fd) == NULL)
02948 fdSetFp(fd, fp);
02949 fdPush(fd, fpio, fp, fileno(fp));
02950
02951 fd = fdLink(fd, "fopencookie");
02952 }
02953
02954 }
02955
02956
02957 DBGIO(fd, (stderr, "==> Fdopen(%p,\"%s\") returns fd %p %s\n", ofd, fmode, (fd ? fd : NULL), fdbg(fd)));
02958
02959 return fd;
02960 }
02961
02962 FD_t Fopen(const char *path, const char *fmode)
02963 {
02964 char stdio[20], other[20];
02965 const char *end = NULL;
02966 mode_t perms = 0666;
02967 int flags;
02968 FD_t fd;
02969
02970 if (path == NULL || fmode == NULL)
02971 return NULL;
02972
02973 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, &flags);
02974 if (stdio[0] == '\0')
02975 return NULL;
02976
02977
02978 if (end == NULL || !strcmp(end, "fdio")) {
02979 if (_rpmio_debug)
02980 fprintf(stderr, "*** Fopen fdio path %s fmode %s\n", path, fmode);
02981 fd = fdOpen(path, flags, perms);
02982 if (fdFileno(fd) < 0) {
02983 if (fd) (void) fdClose(fd);
02984 return NULL;
02985 }
02986 } else if (!strcmp(end, "fadio")) {
02987 if (_rpmio_debug)
02988 fprintf(stderr, "*** Fopen fadio path %s fmode %s\n", path, fmode);
02989 fd = fadio->_open(path, flags, perms);
02990 if (fdFileno(fd) < 0) {
02991 (void) fdClose(fd);
02992 return NULL;
02993 }
02994 } else {
02995 FILE *fp;
02996 int fdno;
02997 int isHTTP = 0;
02998
02999
03000
03001 switch (urlIsURL(path)) {
03002 case URL_IS_HTTP:
03003 isHTTP = 1;
03004
03005 case URL_IS_PATH:
03006 case URL_IS_DASH:
03007 case URL_IS_FTP:
03008 case URL_IS_UNKNOWN:
03009 if (_rpmio_debug)
03010 fprintf(stderr, "*** Fopen ufdio path %s fmode %s\n", path, fmode);
03011 fd = ufdOpen(path, flags, perms);
03012 if (fd == NULL || fdFileno(fd) < 0)
03013 return fd;
03014 break;
03015 default:
03016 if (_rpmio_debug)
03017 fprintf(stderr, "*** Fopen WTFO path %s fmode %s\n", path, fmode);
03018 return NULL;
03019 break;
03020 }
03021
03022
03023 if (isHTTP && ((fp = fdGetFp(fd)) != NULL) && ((fdno = fdGetFdno(fd)) >= 0)) {
03024
03025 fdPush(fd, fpio, fp, fileno(fp));
03026
03027 return fd;
03028 }
03029 }
03030
03031
03032
03033 if (fd)
03034 fd = Fdopen(fd, fmode);
03035
03036 return fd;
03037 }
03038
03039 int Fflush(FD_t fd)
03040 {
03041 void * vh;
03042 if (fd == NULL) return -1;
03043 if (fdGetIo(fd) == fpio)
03044
03045 return fflush(fdGetFILE(fd));
03046
03047
03048 vh = fdGetFp(fd);
03049 if (vh && fdGetIo(fd) == gzdio)
03050 return gzdFlush(vh);
03051 #if HAVE_BZLIB_H
03052 if (vh && fdGetIo(fd) == bzdio)
03053 return bzdFlush(vh);
03054 #endif
03055
03056 return 0;
03057 }
03058
03059 int Ferror(FD_t fd)
03060 {
03061 int i, rc = 0;
03062
03063 if (fd == NULL) return -1;
03064 for (i = fd->nfps; rc == 0 && i >= 0; i--) {
03065 FDSTACK_t * fps = &fd->fps[i];
03066 int ec;
03067
03068 if (fps->io == fpio) {
03069
03070 ec = ferror(fdGetFILE(fd));
03071
03072 } else if (fps->io == gzdio) {
03073 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
03074 i--;
03075 #if HAVE_BZLIB_H
03076 } else if (fps->io == bzdio) {
03077 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
03078 i--;
03079 #endif
03080 } else {
03081
03082 ec = (fdFileno(fd) < 0 ? -1 : 0);
03083 }
03084
03085 if (rc == 0 && ec)
03086 rc = ec;
03087 }
03088
03089 DBGIO(fd, (stderr, "==> Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd)));
03090
03091 return rc;
03092 }
03093
03094 int Fileno(FD_t fd)
03095 {
03096 int i, rc = -1;
03097
03098 for (i = fd->nfps ; rc == -1 && i >= 0; i--) {
03099 rc = fd->fps[i].fdno;
03100 }
03101
03102 DBGIO(fd, (stderr, "==> Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, fdbg(fd)));
03103
03104 return rc;
03105 }
03106
03107
03108 int Fcntl(FD_t fd, int op, void *lip)
03109 {
03110 return fcntl(Fileno(fd), op, lip);
03111 }
03112
03113
03114
03115
03116
03117 int rpmioSlurp(const char * fn, const byte ** bp, ssize_t * blenp)
03118 {
03119 static ssize_t blenmax = (8 * BUFSIZ);
03120 ssize_t blen = 0;
03121 byte * b = NULL;
03122 ssize_t size;
03123 FD_t fd;
03124 int rc = 0;
03125
03126 fd = Fopen(fn, "r.ufdio");
03127 if (fd == NULL || Ferror(fd)) {
03128 rc = 2;
03129 goto exit;
03130 }
03131
03132 size = fdSize(fd);
03133 blen = (size >= 0 ? size : blenmax);
03134
03135 if (blen) {
03136 int nb;
03137 b = xmalloc(blen+1);
03138 b[0] = '\0';
03139 nb = Fread(b, sizeof(*b), blen, fd);
03140 if (Ferror(fd) || (size > 0 && nb != blen)) {
03141 rc = 1;
03142 goto exit;
03143 }
03144 if (blen == blenmax && nb < blen) {
03145 blen = nb;
03146 b = xrealloc(b, blen+1);
03147 }
03148 b[blen] = '\0';
03149 }
03150
03151
03152 exit:
03153 if (fd) (void) Fclose(fd);
03154
03155 if (rc) {
03156 if (b) free(b);
03157 b = NULL;
03158 blen = 0;
03159 }
03160
03161 if (bp) *bp = b;
03162 else if (b) free(b);
03163
03164 if (blenp) *blenp = blen;
03165
03166 return rc;
03167 }
03168
03169 static struct FDIO_s fpio_s = {
03170 ufdRead, ufdWrite, fdSeek, ufdClose, XfdLink, XfdFree, XfdNew, fdFileno,
03171 ufdOpen, NULL, fdGetFp, NULL, Mkdir, Chdir, Rmdir, Rename, Unlink
03172 };
03173 FDIO_t fpio = &fpio_s ;
03174