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