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