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