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