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