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