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