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