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