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