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