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