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