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