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