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