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