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