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