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