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