8 #if HAVE_MACHINE_TYPES_H
9 # include <machine/types.h>
13 # include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h> /* XXX for inet_aton and HP-UX */
19 #if HAVE_NETINET_IN_SYSTM_H
20 # include <sys/types.h>
21 # include <netinet/in_systm.h>
24 #if HAVE_LIBIO_H && defined(_G_IO_IO_FILE_VERSION)
28 /* XXX HP-UX w/o -D_XOPEN_SOURCE needs */
29 #if !defined(HAVE_HERRNO) && (defined(__hpux))
37 #define IPPORT_HTTP 80
40 #if !defined(HAVE_INET_ATON)
41 static int inet_aton(const char *cp, struct in_addr *inp)
46 if (addr == ((long) -1)) return 0;
48 memcpy(inp, &addr, sizeof(addr));
53 #if defined(USE_ALT_DNS) && USE_ALT_DNS
57 #include <rpmio_internal.h>
60 #define fdOpen __fdOpen
62 #define fdRead __fdRead
64 #define fdWrite __fdWrite
66 #define fdClose __fdClose
70 #include "rpmmessages.h"
74 #define FDNREFS(fd) (fd ? ((FD_t)fd)->nrefs : -9)
75 #define FDTO(fd) (fd ? ((FD_t)fd)->rd_timeoutsecs : -99)
76 #define FDCPIOPOS(fd) (fd ? ((FD_t)fd)->fd_cpioPos : -99)
78 #define FDONLY(fd) assert(fdGetIo(fd) == fdio)
79 #define GZDONLY(fd) assert(fdGetIo(fd) == gzdio)
80 #define BZDONLY(fd) assert(fdGetIo(fd) == bzdio)
82 #define UFDONLY(fd) /* assert(fdGetIo(fd) == ufdio) */
84 #define fdGetFILE(_fd) ((FILE *)fdGetFp(_fd))
94 #define TIMEOUT_SECS 60
98 static int ftpTimeoutSecs = TIMEOUT_SECS;
102 static int httpTimeoutSecs = TIMEOUT_SECS;
106 int _rpmio_debug = 0;
121 * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
122 * @param p memory to free
123 * @retval NULL always
126 _free(const void * p)
128 if (p != NULL) free((void *)p);
132 /* =============================================================== */
134 static const char * fdbg(FD_t fd)
136 static char buf[BUFSIZ];
145 sprintf(be, "fd %p", fd); be += strlen(be);
146 if (fd->rd_timeoutsecs >= 0) {
147 sprintf(be, " secs %d", fd->rd_timeoutsecs);
151 if (fd->bytesRemain != -1) {
152 sprintf(be, " clen %d", (int)fd->bytesRemain);
155 if (fd->wr_chunked) {
156 strcpy(be, " chunked");
160 for (i = fd->nfps; i >= 0; i--) {
161 FDSTACK_t * fps = &fd->fps[i];
166 if (fps->io == fdio) {
167 sprintf(be, "FD %d fp %p", fps->fdno, fps->fp);
168 } else if (fps->io == ufdio) {
169 sprintf(be, "UFD %d fp %p", fps->fdno, fps->fp);
170 } else if (fps->io == gzdio) {
171 sprintf(be, "GZD %p fdno %d", fps->fp, fps->fdno);
173 } else if (fps->io == bzdio) {
174 sprintf(be, "BZD %p fdno %d", fps->fp, fps->fdno);
176 } else if (fps->io == fpio) {
177 sprintf(be, "%s %p(%d) fdno %d",
178 (fps->fdno < 0 ? "LIBIO" : "FP"),
179 fps->fp, fileno(((FILE *)fps->fp)), fps->fdno);
181 sprintf(be, "??? io %p fp %p fdno %d ???",
182 fps->io, fps->fp, fps->fdno);
190 /* =============================================================== */
191 off_t fdSize(FD_t fd)
197 DBGIO(0, (stderr, "==>\tfdSize(%p) rc %ld\n", fd, (long)rc));
200 if (fd->contentLength >= 0)
201 rc = fd->contentLength;
202 else switch (fd->urlType) {
205 if (fstat(Fileno(fd), &sb) == 0)
222 if ((nfdno = dup(fdno)) < 0)
224 fd = fdNew("open (fdDup)");
225 fdSetFdno(fd, nfdno);
226 DBGIO(fd, (stderr, "==> fdDup(%d) fd %p %s\n", fdno, (fd ? fd : NULL), fdbg(fd)));
230 static inline int fdSeekNot(void * cookie,
231 _libio_pos_t pos, int whence)
233 FD_t fd = c2f(cookie);
234 FDSANE(fd); /* XXX keep gcc quiet */
239 FILE *fdFdopen(void * cookie, const char *fmode)
241 FD_t fd = c2f(cookie);
245 if (fmode == NULL) return NULL;
247 if (fdno < 0) return NULL;
248 fp = fdopen(fdno, fmode);
249 DBGIO(fd, (stderr, "==> fdFdopen(%p,\"%s\") fdno %d -> fp %p fdno %d\n", cookie, fmode, fdno, fp, fileno(fp)));
250 fd = fdFree(fd, "open (fdFdopen)");
255 /* =============================================================== */
256 /* FIX: cookie is modified */
257 static inline FD_t XfdLink(void * cookie, const char * msg,
258 const char * file, unsigned line)
262 DBGREFS(0, (stderr, "--> fd %p ++ %d %s at %s:%u\n", cookie, FDNREFS(cookie)+1, msg, file, line));
266 DBGREFS(fd, (stderr, "--> fd %p ++ %d %s at %s:%u %s\n", fd, fd->nrefs, msg, file, line, fdbg(fd)));
272 FD_t XfdFree( FD_t fd, const char *msg,
273 const char *file, unsigned line)
278 DBGREFS(0, (stderr, "--> fd %p -- %d %s at %s:%u\n", fd, FDNREFS(fd), msg, file, line));
281 DBGREFS(fd, (stderr, "--> fd %p -- %d %s at %s:%u %s\n", fd, fd->nrefs, msg, file, line, fdbg(fd)));
284 fd->stats = _free(fd->stats);
285 for (i = fd->ndigests - 1; i >= 0; i--) {
286 FDDIGEST_t fddig = fd->digests + i;
287 if (fddig->hashctx == NULL)
289 (void) rpmDigestFinal(fddig->hashctx, NULL, NULL, 0);
290 fddig->hashctx = NULL;
299 FD_t XfdNew(const char * msg, const char * file, unsigned line)
301 FD_t fd = xcalloc(1, sizeof(*fd));
302 if (fd == NULL) /* XXX xmalloc never returns NULL */
307 fd->urlType = URL_IS_UNKNOWN;
310 memset(fd->fps, 0, sizeof(fd->fps));
312 fd->fps[0].io = fdio;
313 fd->fps[0].fp = NULL;
314 fd->fps[0].fdno = -1;
317 fd->rd_timeoutsecs = 1; /* XXX default value used to be -1 */
318 fd->contentLength = fd->bytesRemain = -1;
321 fd->errcookie = NULL;
322 fd->stats = xcalloc(1, sizeof(*fd->stats));
325 memset(fd->digests, 0, sizeof(fd->digests));
327 fd->ftpFileDoneNeeded = 0;
332 return XfdLink(fd, msg, file, line);
335 static ssize_t fdRead(void * cookie, char * buf, size_t count)
337 FD_t fd = c2f(cookie);
340 if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
342 fdstat_enter(fd, FDSTAT_READ);
343 /* HACK: flimsy wiring for davRead */
344 if (fd->req != NULL) {
346 rc = davRead(fd, buf, (count > fd->bytesRemain ? fd->bytesRemain : count));
350 /* XXX Chunked davRead EOF. */
354 rc = read(fdFileno(fd), buf, (count > fd->bytesRemain ? fd->bytesRemain : count));
355 fdstat_exit(fd, FDSTAT_READ, rc);
357 if (fd->ndigests && rc > 0) fdUpdateDigests(fd, (void *)buf, rc);
359 DBGIO(fd, (stderr, "==>\tfdRead(%p,%p,%ld) rc %ld %s\n", cookie, buf, (long)count, (long)rc, fdbg(fd)));
364 static ssize_t fdWrite(void * cookie, const char * buf, size_t count)
366 FD_t fd = c2f(cookie);
367 int fdno = fdFileno(fd);
370 if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
372 if (fd->ndigests && count > 0) fdUpdateDigests(fd, (void *)buf, count);
374 if (count == 0) return 0;
376 fdstat_enter(fd, FDSTAT_WRITE);
377 /* HACK: flimsy wiring for davWrite */
378 if (fd->req != NULL) {
380 rc = davWrite(fd, buf, (count > fd->bytesRemain ? fd->bytesRemain : count));
385 rc = write(fdno, buf, (count > fd->bytesRemain ? fd->bytesRemain : count));
386 fdstat_exit(fd, FDSTAT_WRITE, rc);
388 DBGIO(fd, (stderr, "==>\tfdWrite(%p,%p,%ld) rc %ld %s\n", cookie, buf, (long)count, (long)rc, fdbg(fd)));
393 static inline int fdSeek(void * cookie, _libio_pos_t pos, int whence)
395 #ifdef USE_COOKIE_SEEK_POINTER
396 _IO_off64_t p = *pos;
400 FD_t fd = c2f(cookie);
403 assert(fd->bytesRemain == -1); /* XXX FIXME fadio only for now */
404 fdstat_enter(fd, FDSTAT_SEEK);
405 rc = lseek(fdFileno(fd), p, whence);
406 fdstat_exit(fd, FDSTAT_SEEK, rc);
408 DBGIO(fd, (stderr, "==>\tfdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd)));
413 static int fdClose( void * cookie)
419 if (cookie == NULL) return -2;
425 fdstat_enter(fd, FDSTAT_CLOSE);
426 /* HACK: flimsy wiring for davClose */
427 if (fd->req != NULL) {
434 rc = ((fdno >= 0) ? close(fdno) : -2);
435 fdstat_exit(fd, FDSTAT_CLOSE, rc);
437 DBGIO(fd, (stderr, "==>\tfdClose(%p) rc %lx %s\n", (fd ? fd : NULL), (unsigned long)rc, fdbg(fd)));
439 fd = fdFree(fd, "open (fdClose)");
443 static FD_t fdOpen(const char *path, int flags, mode_t mode)
448 fdno = open(path, flags, mode);
449 if (fdno < 0) return NULL;
450 if (fcntl(fdno, F_SETFD, FD_CLOEXEC)) {
454 fd = fdNew("open (fdOpen)");
457 DBGIO(fd, (stderr, "==>\tfdOpen(\"%s\",%x,0%o) %s\n", path, (unsigned)flags, (unsigned)mode, fdbg(fd)));
461 /* LCL: function typedefs */
462 static struct FDIO_s fdio_s = {
463 fdRead, fdWrite, fdSeek, fdClose, XfdLink, XfdFree, XfdNew, fdFileno,
464 fdOpen, NULL, fdGetFp, NULL, mkdir, chdir, rmdir, rename, unlink
466 FDIO_t fdio = &fdio_s ;
468 int fdWritable(FD_t fd, int secs)
473 int msecs = (secs >= 0 ? (1000 * secs) : -1);
476 struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL);
481 /* HACK: flimsy wiring for davWrite */
485 if ((fdno = fdFileno(fd)) < 0)
486 return -1; /* XXX W2DO? */
491 wrfds.events = POLLOUT;
493 rc = poll(&wrfds, 1, msecs);
499 FD_SET(fdno, &wrfds);
500 rc = select(fdno + 1, NULL, &wrfds, NULL, tvp);
503 /* HACK: EBADF on PUT chunked termination from ufdClose. */
504 if (_rpmio_debug && !(rc == 1 && errno == 0))
505 fprintf(stderr, "*** fdWritable fdno %d rc %d %s\n", fdno, rc, strerror(errno));
520 int fdReadable(FD_t fd, int secs)
525 int msecs = (secs >= 0 ? (1000 * secs) : -1);
528 struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL);
533 /* HACK: flimsy wiring for davRead */
537 if ((fdno = fdFileno(fd)) < 0)
538 return -1; /* XXX W2DO? */
543 rdfds.events = POLLIN;
545 rc = poll(&rdfds, 1, msecs);
551 FD_SET(fdno, &rdfds);
552 rc = select(fdno + 1, &rdfds, NULL, NULL, tvp);
569 int fdFgets(FD_t fd, char * buf, size_t len)
572 int secs = fd->rd_timeoutsecs;
575 char lastchar = '\0';
577 if ((fdno = fdFileno(fd)) < 0)
578 return 0; /* XXX W2DO? */
583 /* Is there data to read? */
584 rc = fdReadable(fd, secs);
591 case 0: /* timeout */
595 default: /* data to read */
601 rc = fdRead(fd, buf + nb, 1);
603 rc = read(fdFileno(fd), buf + nb, 1);
606 fd->syserrno = errno;
615 fprintf(stderr, "*** read: fd %p rc %d errno %d %s \"%s\"\n", fd, rc, errno, strerror(errno), buf);
618 } else if (rc == 0) {
620 fprintf(stderr, "*** read: fd %p rc %d EOF errno %d %s \"%s\"\n", fd, rc, errno, strerror(errno), buf);
625 lastchar = buf[nb - 1];
627 } while (ec == 0 && nb < len && lastchar != '\n');
629 return (ec >= 0 ? nb : ec);
632 /* =============================================================== */
633 /* Support for FTP/HTTP I/O.
635 const char * ftpStrerror(int errorNumber)
637 switch (errorNumber) {
641 /* HACK error impediance match, coalesce and rename. */
642 case FTPERR_NE_ERROR:
643 return ("NE_ERROR: Generic error.");
644 case FTPERR_NE_LOOKUP:
645 return ("NE_LOOKUP: Hostname lookup failed.");
647 return ("NE_AUTH: Server authentication failed.");
648 case FTPERR_NE_PROXYAUTH:
649 return ("NE_PROXYAUTH: Proxy authentication failed.");
650 case FTPERR_NE_CONNECT:
651 return ("NE_CONNECT: Could not connect to server.");
652 case FTPERR_NE_TIMEOUT:
653 return ("NE_TIMEOUT: Connection timed out.");
654 case FTPERR_NE_FAILED:
655 return ("NE_FAILED: The precondition failed.");
656 case FTPERR_NE_RETRY:
657 return ("NE_RETRY: Retry request.");
658 case FTPERR_NE_REDIRECT:
659 return ("NE_REDIRECT: Redirect received.");
661 case FTPERR_BAD_SERVER_RESPONSE:
662 return _("Bad server response");
663 case FTPERR_SERVER_IO_ERROR:
664 return _("Server I/O error");
665 case FTPERR_SERVER_TIMEOUT:
666 return _("Server timeout");
667 case FTPERR_BAD_HOST_ADDR:
668 return _("Unable to lookup server host address");
669 case FTPERR_BAD_HOSTNAME:
670 return _("Unable to lookup server host name");
671 case FTPERR_FAILED_CONNECT:
672 return _("Failed to connect to server");
673 case FTPERR_FAILED_DATA_CONNECT:
674 return _("Failed to establish data connection to server");
675 case FTPERR_FILE_IO_ERROR:
676 return _("I/O error to local file");
677 case FTPERR_PASSIVE_ERROR:
678 return _("Error setting remote server to passive mode");
679 case FTPERR_FILE_NOT_FOUND:
680 return _("File not found on server");
681 case FTPERR_NIC_ABORT_IN_PROGRESS:
682 return _("Abort in progress");
686 return _("Unknown or unexpected error");
690 const char *urlStrerror(const char *url)
693 switch (urlIsURL(url)) {
699 /* XXX This only works for httpReq/ftpLogin/ftpReq failures */
700 if (urlSplit(url, &u) == 0) {
701 retstr = ftpStrerror(u->openError);
703 retstr = "Malformed URL";
706 retstr = strerror(errno);
712 #if !defined(HAVE_GETADDRINFO)
713 #if !defined(USE_ALT_DNS) || !USE_ALT_DNS
714 static int mygethostbyname(const char * host,
715 struct in_addr * address)
717 struct hostent * hostinfo;
719 hostinfo = gethostbyname(host);
720 if (!hostinfo) return 1;
722 memcpy(address, hostinfo->h_addr_list[0], sizeof(*address));
727 static int getHostAddress(const char * host, struct in_addr * address)
729 #if 0 /* XXX workaround nss_foo module hand-off using valgrind. */
730 if (!strcmp(host, "localhost")) {
731 if (!inet_aton("127.0.0.1", address))
732 return FTPERR_BAD_HOST_ADDR;
735 if (xisdigit(host[0])) {
736 if (!inet_aton(host, address))
737 return FTPERR_BAD_HOST_ADDR;
739 if (mygethostbyname(host, address)) {
741 return FTPERR_BAD_HOSTNAME;
749 static int tcpConnect(FD_t ctrl, const char * host, int port)
753 #ifdef HAVE_GETADDRINFO
754 struct addrinfo hints, *res, *res0;
755 char pbuf[NI_MAXSERV];
757 memset(&hints, 0, sizeof(hints));
758 hints.ai_family = AF_UNSPEC;
759 hints.ai_socktype = SOCK_STREAM;
760 sprintf(pbuf, "%d", port);
761 pbuf[sizeof(pbuf)-1] = '\0';
762 rc = FTPERR_FAILED_CONNECT;
763 if (getaddrinfo(host, pbuf, &hints, &res0) == 0) {
764 for (res = res0; res != NULL; res= res->ai_next) {
765 if ((fdno = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0)
767 if (connect(fdno, res->ai_addr, res->ai_addrlen) < 0) {
774 char hbuf[NI_MAXHOST];
775 getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
776 NULL, 0, NI_NUMERICHOST);
777 fprintf(stderr,"++ connect [%s]:%d on fdno %d\n",
787 #else /* HAVE_GETADDRINFO */
788 struct sockaddr_in sin;
790 memset(&sin, 0, sizeof(sin));
791 sin.sin_family = AF_INET;
792 sin.sin_port = htons(port);
793 sin.sin_addr.s_addr = INADDR_ANY;
796 if ((rc = getHostAddress(host, &sin.sin_addr)) < 0)
799 if ((fdno = socket(sin.sin_family, SOCK_STREAM, IPPROTO_IP)) < 0) {
800 rc = FTPERR_FAILED_CONNECT;
804 if (connect(fdno, (struct sockaddr *) &sin, sizeof(sin))) {
805 rc = FTPERR_FAILED_CONNECT;
814 fprintf(stderr,"++ connect %s:%d on fdno %d\n",
815 inet_ntoa(sin.sin_addr)
817 (int)ntohs(sin.sin_port), fdno);
818 #endif /* HAVE_GETADDRINFO */
820 fdSetFdno(ctrl, (fdno >= 0 ? fdno : -1));
824 fdSetSyserrno(ctrl, errno, ftpStrerror(rc));
830 static int checkResponse(void * uu, FD_t ctrl,
831 int *ecp, char ** str)
844 if (u->bufAlloced == 0 || u->buf == NULL) {
845 u->bufAlloced = _url_iobuf_size;
846 u->buf = xcalloc(u->bufAlloced, sizeof(u->buf[0]));
849 bufAlloced = u->bufAlloced;
858 * Read next line from server.
860 se = buf + bufLength;
862 rc = fdFgets(ctrl, se, (bufAlloced - bufLength));
864 ec = FTPERR_BAD_SERVER_RESPONSE;
866 } else if (rc == 0 || fdWritable(ctrl, 0) < 1)
870 * Process next line from server.
872 for (s = se; *s != '\0'; s = se) {
875 while (*se && *se != '\n') se++;
877 if (se > s && se[-1] == '\r')
883 fprintf(stderr, "<- %s\n", s);
885 /* HTTP: header termination on empty line */
892 /* HTTP: look for "HTTP/1.1 123 ..." */
893 if (!strncmp(s, "HTTP", sizeof("HTTP")-1)) {
894 ctrl->contentLength = -1;
895 if ((e = strchr(s, '.')) != NULL) {
897 u->httpVersion = *e - '0';
898 if (u->httpVersion < 1 || u->httpVersion > 2)
899 ctrl->persist = u->httpVersion = 0;
903 if ((e = strchr(s, ' ')) != NULL) {
905 if (strchr("0123456789", *e))
906 strncpy(errorCode, e, 3);
912 /* HTTP: look for "token: ..." */
913 for (e = s; *e && !(*e == ' ' || *e == ':'); e++)
915 if (e > s && *e++ == ':') {
917 while (*e && *e == ' ') e++;
919 if (!strncmp(s, "Date:", ne)) {
921 if (!strncmp(s, "Server:", ne)) {
923 if (!strncmp(s, "Last-Modified:", ne)) {
925 if (!strncmp(s, "ETag:", ne)) {
928 if (!strncmp(s, "Accept-Ranges:", ne)) {
929 if (!strcmp(e, "bytes"))
931 if (!strcmp(e, "none"))
934 if (!strncmp(s, "Content-Length:", ne)) {
935 if (strchr("0123456789", *e))
936 ctrl->contentLength = atoi(e);
938 if (!strncmp(s, "Connection:", ne)) {
939 if (!strcmp(e, "close"))
944 if (!strncmp(s, "Content-Type:", ne)) {
946 if (!strncmp(s, "Transfer-Encoding:", ne)) {
947 if (!strcmp(e, "chunked"))
948 ctrl->wr_chunked = 1;
950 ctrl->wr_chunked = 0;
952 if (!strncmp(s, "Allow:", ne)) {
958 /* HTTP: look for "<TITLE>501 ... </TITLE>" */
959 if (!strncmp(s, "<TITLE>", sizeof("<TITLE>")-1))
960 s += sizeof("<TITLE>") - 1;
962 /* FTP: look for "123-" and/or "123 " */
963 if (strchr("0123456789", *s)) {
964 if (errorCode[0] != '\0') {
965 if (!strncmp(s, errorCode, sizeof("123")-1) && s[3] == ' ')
968 strncpy(errorCode, s, sizeof("123")-1);
976 if (moretodo && se > s) {
977 bufLength = se - s - 1;
979 memmove(buf, s, bufLength);
983 } while (moretodo && ec == 0);
986 if (ecp) *ecp = atoi(errorCode);
991 static int ftpCheckResponse(urlinfo u, char ** str)
997 rc = checkResponse(u, u->ctrl, &ec, str);
1001 return FTPERR_FILE_NOT_FOUND;
1004 return FTPERR_NIC_ABORT_IN_PROGRESS;
1007 if (ec >= 400 && ec <= 599) {
1008 return FTPERR_BAD_SERVER_RESPONSE;
1015 static int ftpCommand(urlinfo u, char ** str, ...)
1019 const char * s, * t;
1025 while ((s = va_arg(ap, const char *)) != NULL) {
1029 len += sizeof("\r\n")-1;
1032 t = te = alloca(len + 1);
1035 while ((s = va_arg(ap, const char *)) != NULL) {
1036 if (te > t) *te++ = ' ';
1039 te = stpcpy(te, "\r\n");
1043 fprintf(stderr, "-> %s", t);
1044 if (fdWrite(u->ctrl, t, (te-t)) != (te-t))
1045 return FTPERR_SERVER_IO_ERROR;
1047 rc = ftpCheckResponse(u, str);
1051 static int ftpLogin(urlinfo u)
1055 const char * password;
1060 u->ctrl = fdLink(u->ctrl, "open ctrl");
1062 if (((host = (u->proxyh ? u->proxyh : u->host)) == NULL)) {
1063 rc = FTPERR_BAD_HOSTNAME;
1067 if ((port = (u->proxyp > 0 ? u->proxyp : u->port)) < 0) port = IPPORT_FTP;
1069 if ((user = (u->proxyu ? u->proxyu : u->user)) == NULL)
1072 if ((password = u->password) == NULL) {
1073 uid_t uid = getuid();
1075 if (uid && (pw = getpwuid(uid)) != NULL) {
1076 char *myp = alloca(strlen(pw->pw_name) + sizeof("@"));
1077 strcpy(myp, pw->pw_name);
1085 if (fdFileno(u->ctrl) >= 0 && fdWritable(u->ctrl, 0) < 1)
1086 (void) fdClose(u->ctrl);
1088 if (fdFileno(u->ctrl) < 0) {
1089 rc = tcpConnect(u->ctrl, host, port);
1094 if ((rc = ftpCheckResponse(u, NULL)))
1097 if ((rc = ftpCommand(u, NULL, "USER", user, NULL)))
1100 if ((rc = ftpCommand(u, NULL, "PASS", password, NULL)))
1103 if ((rc = ftpCommand(u, NULL, "TYPE", "I", NULL)))
1109 fdSetSyserrno(u->ctrl, errno, ftpStrerror(rc));
1111 if (fdFileno(u->ctrl) >= 0)
1112 (void) fdClose(u->ctrl);
1116 int ftpReq(FD_t data, const char * ftpCmd, const char * ftpArg)
1118 urlinfo u = data->url;
1119 #if !defined(HAVE_GETADDRINFO)
1120 struct sockaddr_in dataAddress;
1121 #endif /* HAVE_GETADDRINFO */
1122 char remoteIP[NI_MAXHOST];
1133 return FTPERR_UNKNOWN; /* XXX W2DO? */
1135 cmdlen = strlen(ftpCmd) + (ftpArg ? 1+strlen(ftpArg) : 0) + sizeof("\r\n");
1136 chptr = cmd = alloca(cmdlen);
1137 chptr = stpcpy(chptr, ftpCmd);
1140 chptr = stpcpy(chptr, ftpArg);
1142 chptr = stpcpy(chptr, "\r\n");
1143 cmdlen = chptr - cmd;
1146 * Get the ftp version of the Content-Length.
1148 if (!strncmp(cmd, "RETR", 4)) {
1152 rc = ftpCommand(u, &passReply, "SIZE", ftpArg, NULL);
1155 if (sscanf(passReply, "%d %u", &rc, &cl) != 2) {
1156 rc = FTPERR_BAD_SERVER_RESPONSE;
1160 data->contentLength = cl;
1165 #ifdef HAVE_GETNAMEINFO
1166 rc = ftpCommand(u, &passReply, "EPSV", NULL);
1168 #ifdef HAVE_GETADDRINFO
1169 struct sockaddr_storage ss;
1170 #else /* HAVE_GETADDRINFO */
1171 struct sockaddr_in ss;
1172 #endif /* HAVE_GETADDRINFO */
1174 /* we need to know IP of remote host */
1176 if ((getpeername(fdFileno(c2f(u->ctrl)), (struct sockaddr *)&ss, &size) == 0) &&
1177 (getnameinfo((struct sockaddr *)&ss, size, remoteIP, sizeof(remoteIP),
1178 NULL, 0, NI_NUMERICHOST) == 0))
1181 /* abort EPSV and fall back to PASV */
1182 rc = ftpCommand(u, &passReply, "ABOR", NULL);
1184 rc = FTPERR_PASSIVE_ERROR;
1190 #endif /* HAVE_GETNAMEINFO */
1191 rc = ftpCommand(u, &passReply, "PASV", NULL);
1193 rc = FTPERR_PASSIVE_ERROR;
1198 while (*chptr && *chptr != '(') chptr++;
1199 if (*chptr != '(') return FTPERR_PASSIVE_ERROR;
1202 while (*chptr && *chptr != ')') chptr++;
1203 if (*chptr != ')') return FTPERR_PASSIVE_ERROR;
1208 if(sscanf(passReply,"%*c%*c%*c%d%*c",&i) != 1) {
1209 rc = FTPERR_PASSIVE_ERROR;
1215 while (*chptr && *chptr != ',') chptr--;
1216 if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
1218 while (*chptr && *chptr != ',') chptr--;
1219 if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
1222 /* now passReply points to the IP portion, and chptr points to the
1223 port number portion */
1226 if (sscanf(chptr, "%d,%d", &i, &j) != 2) {
1227 rc = FTPERR_PASSIVE_ERROR;
1230 port = (((unsigned)i) << 8) + j;
1234 while (*chptr++ != '\0') {
1235 if (*chptr == ',') *chptr = '.';
1237 sprintf(remoteIP, "%s", passReply);
1240 #ifdef HAVE_GETADDRINFO
1242 struct addrinfo hints, *res, *res0;
1243 char pbuf[NI_MAXSERV];
1245 memset(&hints, 0, sizeof(hints));
1246 hints.ai_family = AF_UNSPEC;
1247 hints.ai_socktype = SOCK_STREAM;
1248 hints.ai_flags = AI_NUMERICHOST;
1249 sprintf(pbuf, "%d", port);
1250 pbuf[sizeof(pbuf)-1] = '\0';
1251 if (getaddrinfo(remoteIP, pbuf, &hints, &res0)) {
1252 rc = FTPERR_PASSIVE_ERROR;
1256 for (res = res0; res != NULL; res = res->ai_next) {
1257 rc = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
1258 fdSetFdno(data, (rc >= 0 ? rc : -1));
1263 rc = FTPERR_FAILED_CONNECT;
1268 data = fdLink(data, "open data (ftpReq)");
1270 /* XXX setsockopt SO_LINGER */
1271 /* XXX setsockopt SO_KEEPALIVE */
1272 /* XXX setsockopt SO_TOS IPTOS_THROUGHPUT */
1276 while (connect(fdFileno(data), res->ai_addr, res->ai_addrlen) < 0) {
1286 rc = FTPERR_PASSIVE_ERROR;
1299 #else /* HAVE_GETADDRINFO */
1300 memset(&dataAddress, 0, sizeof(dataAddress));
1301 dataAddress.sin_family = AF_INET;
1302 dataAddress.sin_port = htons(port);
1304 if (!inet_aton(remoteIP, &dataAddress.sin_addr)) {
1305 rc = FTPERR_PASSIVE_ERROR;
1309 rc = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
1310 fdSetFdno(data, (rc >= 0 ? rc : -1));
1312 rc = FTPERR_FAILED_CONNECT;
1315 data = fdLink(data, "open data (ftpReq)");
1317 /* XXX setsockopt SO_LINGER */
1318 /* XXX setsockopt SO_KEEPALIVE */
1319 /* XXX setsockopt SO_TOS IPTOS_THROUGHPUT */
1321 while (connect(fdFileno(data), (struct sockaddr *) &dataAddress,
1322 sizeof(dataAddress)) < 0)
1326 rc = FTPERR_FAILED_DATA_CONNECT;
1329 #endif /* HAVE_GETADDRINFO */
1332 fprintf(stderr, "-> %s", cmd);
1333 if (fdWrite(u->ctrl, cmd, cmdlen) != cmdlen) {
1334 rc = FTPERR_SERVER_IO_ERROR;
1338 if ((rc = ftpCheckResponse(u, NULL))) {
1342 data->ftpFileDoneNeeded = 1;
1343 u->ctrl = fdLink(u->ctrl, "grab data (ftpReq)");
1344 u->ctrl = fdLink(u->ctrl, "open data (ftpReq)");
1348 fdSetSyserrno(u->ctrl, errno, ftpStrerror(rc));
1349 if (fdFileno(data) >= 0)
1350 (void) fdClose(data);
1354 static rpmCallbackFunction urlNotify = NULL;
1356 static void * urlNotifyData = NULL;
1358 static int urlNotifyCount = -1;
1360 void urlSetCallback(rpmCallbackFunction notify, void *notifyData, int notifyCount) {
1362 urlNotifyData = notifyData;
1363 urlNotifyCount = (notifyCount >= 0) ? notifyCount : 4096;
1366 int ufdCopy(FD_t sfd, FD_t tfd)
1370 int itemsCopied = 0;
1376 (void)(*urlNotify) (NULL, RPMCALLBACK_INST_OPEN_FILE,
1377 0, 0, NULL, urlNotifyData);
1381 rc = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd);
1389 rc = Fwrite(buf, sizeof(buf[0]), itemsRead, tfd);
1392 if (rc != itemsRead) {
1393 rc = FTPERR_FILE_IO_ERROR;
1397 itemsCopied += itemsRead;
1398 if (urlNotify && urlNotifyCount > 0) {
1399 int n = itemsCopied/urlNotifyCount;
1400 if (n != notifier) {
1402 (void)(*urlNotify) (NULL, RPMCALLBACK_INST_PROGRESS,
1403 itemsCopied, 0, NULL, urlNotifyData);
1409 DBGIO(sfd, (stderr, "++ copied %d bytes: %s\n", itemsCopied,
1414 (void)(*urlNotify) (NULL, RPMCALLBACK_INST_OPEN_FILE,
1415 itemsCopied, itemsCopied, NULL, urlNotifyData);
1421 static int urlConnect(const char * url, urlinfo * uret)
1426 if (urlSplit(url, &u) < 0)
1429 if (u->urltype == URL_IS_FTP) {
1432 if ((fd = u->ctrl) == NULL) {
1433 fd = u->ctrl = fdNew("persist ctrl (urlConnect FTP)");
1434 fdSetIo(u->ctrl, ufdio);
1437 fd->rd_timeoutsecs = ftpTimeoutSecs;
1438 fd->contentLength = fd->bytesRemain = -1;
1439 fd->url = NULL; /* XXX FTP ctrl has not */
1440 fd->ftpFileDoneNeeded = 0;
1441 fd = fdLink(fd, "grab ctrl (urlConnect FTP)");
1443 if (fdFileno(u->ctrl) < 0) {
1444 rpmMessage(RPMMESS_DEBUG, _("logging into %s as %s, pw %s\n"),
1445 u->host ? u->host : "???",
1446 u->user ? u->user : "ftp",
1447 u->password ? u->password : "(username)");
1449 if ((rc = ftpLogin(u)) < 0) { /* XXX save ftpLogin error */
1450 u->ctrl = fdFree(fd, "grab ctrl (urlConnect FTP)");
1457 *uret = urlLink(u, "urlConnect");
1458 u = urlFree(u, "urlSplit (urlConnect)");
1463 int ufdGetFile(FD_t sfd, FD_t tfd)
1469 rc = ufdCopy(sfd, tfd);
1471 if (rc > 0) /* XXX ufdCopy now returns no. bytes copied */
1476 int ftpCmd(const char * cmd, const char * url, const char * arg2)
1482 if (urlConnect(url, &u) < 0)
1485 (void) urlPath(url, &path);
1487 rc = ftpCommand(u, NULL, cmd, path, arg2, NULL);
1488 u->ctrl = fdFree(u->ctrl, "grab ctrl (ftpCmd)");
1492 /* XXX these aren't worth the pain of including correctly */
1494 #define IAC 255 /* interpret as command: */
1497 #define IP 244 /* interrupt process--permanently */
1500 #define DM 242 /* data mark--for connect. cleaning */
1502 #if !defined(SHUT_RDWR)
1503 #define SHUT_RDWR 1+1
1506 static int ftpAbort(urlinfo u, FD_t data)
1508 static unsigned char ipbuf[3] = { IAC, IP, IAC };
1516 data->ftpFileDoneNeeded = 0;
1517 if (fdFileno(data) >= 0)
1518 u->ctrl = fdFree(u->ctrl, "open data (ftpAbort)");
1519 u->ctrl = fdFree(u->ctrl, "grab data (ftpAbort)");
1523 DBGIO(0, (stderr, "-> ABOR\n"));
1525 if (send(fdFileno(ctrl), ipbuf, sizeof(ipbuf), MSG_OOB) != sizeof(ipbuf)) {
1526 (void) fdClose(ctrl);
1527 return FTPERR_SERVER_IO_ERROR;
1530 sprintf(u->buf, "%cABOR\r\n",(char) DM);
1531 if (fdWrite(ctrl, u->buf, 7) != 7) {
1532 (void) fdClose(ctrl);
1533 return FTPERR_SERVER_IO_ERROR;
1536 if (data && fdFileno(data) >= 0) {
1537 /* XXX shorten data drain time wait */
1538 tosecs = data->rd_timeoutsecs;
1539 data->rd_timeoutsecs = 10;
1540 if (fdReadable(data, data->rd_timeoutsecs) > 0) {
1541 while (timedRead(data, u->buf, u->bufAlloced) > 0)
1544 data->rd_timeoutsecs = tosecs;
1545 /* XXX ftp abort needs to close the data channel to receive status */
1546 (void) shutdown(fdFileno(data), SHUT_RDWR);
1547 (void) close(fdFileno(data));
1548 data->fps[0].fdno = -1; /* XXX WRONG but expedient */
1551 /* XXX shorten ctrl drain time wait */
1552 tosecs = u->ctrl->rd_timeoutsecs;
1553 u->ctrl->rd_timeoutsecs = 10;
1554 if ((rc = ftpCheckResponse(u, NULL)) == FTPERR_NIC_ABORT_IN_PROGRESS) {
1555 rc = ftpCheckResponse(u, NULL);
1557 rc = ftpCheckResponse(u, NULL);
1558 u->ctrl->rd_timeoutsecs = tosecs;
1563 static int ftpFileDone(urlinfo u, FD_t data)
1568 assert(data->ftpFileDoneNeeded);
1570 if (data->ftpFileDoneNeeded) {
1571 data->ftpFileDoneNeeded = 0;
1572 u->ctrl = fdFree(u->ctrl, "open data (ftpFileDone)");
1573 u->ctrl = fdFree(u->ctrl, "grab data (ftpFileDone)");
1574 rc = ftpCheckResponse(u, NULL);
1579 static int httpResp(urlinfo u, FD_t ctrl, char ** str)
1585 rc = checkResponse(u, ctrl, &ec, str);
1587 if (_ftp_debug && !(rc == 0 && (ec == 200 || ec == 201)))
1588 fprintf(stderr, "*** httpResp: rc %d ec %d\n", rc, ec);
1592 case 201: /* 201 Created. */
1594 case 204: /* HACK: if overwriting, 204 No Content. */
1595 case 403: /* 403 Forbidden. */
1596 ctrl->syserrno = EACCES; /* HACK */
1597 rc = FTPERR_UNKNOWN;
1600 rc = FTPERR_FILE_NOT_FOUND;
1606 static int httpReq(FD_t ctrl, const char * httpCmd, const char * httpArg)
1611 char hthost[NI_MAXHOST];
1618 assert(ctrl != NULL);
1622 if (((host = (u->proxyh ? u->proxyh : u->host)) == NULL))
1623 return FTPERR_BAD_HOSTNAME;
1624 if (strchr(host, ':'))
1625 sprintf(hthost, "[%s]", host);
1627 strcpy(hthost, host);
1629 if ((port = (u->proxyp > 0 ? u->proxyp : u->port)) < 0) port = 80;
1630 path = (u->proxyh || u->proxyp > 0) ? u->url : httpArg;
1631 if (path == NULL) path = "";
1634 if (fdFileno(ctrl) >= 0 && (rc = fdWritable(ctrl, 0)) < 1) {
1635 (void) fdClose(ctrl);
1638 if (fdFileno(ctrl) < 0) {
1639 rc = tcpConnect(ctrl, host, port);
1642 ctrl = fdLink(ctrl, "open ctrl (httpReq)");
1647 User-Agent: rpm/3.0.4\r\n\
1649 Accept: text/plain\r\n\
1650 Transfer-Encoding: chunked\r\n\
1652 ") + strlen(httpCmd) + strlen(path) + sizeof(VERSION) + strlen(hthost) + 20;
1657 if (!strcmp(httpCmd, "PUT")) {
1659 %s %s HTTP/1.%d\r\n\
1660 User-Agent: rpm/%s\r\n\
1662 Accept: text/plain\r\n\
1663 Transfer-Encoding: chunked\r\n\
1665 ", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, hthost, port);
1668 %s %s HTTP/1.%d\r\n\
1669 User-Agent: rpm/%s\r\n\
1671 Accept: text/plain\r\n\
1673 ", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, hthost, port);
1677 fprintf(stderr, "-> %s", req);
1680 if (fdWrite(ctrl, req, len) != len) {
1681 rc = FTPERR_SERVER_IO_ERROR;
1685 if (!strcmp(httpCmd, "PUT")) {
1686 ctrl->wr_chunked = 1;
1689 rc = httpResp(u, ctrl, NULL);
1692 if (!retrying) { /* not HTTP_OK */
1694 (void) fdClose(ctrl);
1701 ctrl = fdLink(ctrl, "open data (httpReq)");
1705 fdSetSyserrno(ctrl, errno, ftpStrerror(rc));
1707 if (fdFileno(ctrl) >= 0)
1708 (void) fdClose(ctrl);
1712 /* XXX DYING: unused */
1713 void * ufdGetUrlinfo(FD_t fd)
1716 if (fd->url == NULL)
1718 return urlLink(fd->url, "ufdGetUrlinfo");
1721 /* =============================================================== */
1722 static ssize_t ufdRead(void * cookie, char * buf, size_t count)
1724 FD_t fd = c2f(cookie);
1728 /* XXX preserve timedRead() behavior */
1729 if (fdGetIo(fd) == fdio) {
1731 int fdno = fdFileno(fd);
1732 (void) fstat(fdno, &sb);
1733 if (S_ISREG(sb.st_mode))
1734 return fdRead(fd, buf, count);
1738 assert(fd->rd_timeoutsecs >= 0);
1740 for (total = 0; total < count; total += bytesRead) {
1746 /* Is there data to read? */
1747 if (fd->bytesRemain == 0) return total; /* XXX simulate EOF */
1748 rc = fdReadable(fd, fd->rd_timeoutsecs);
1751 case -1: /* error */
1752 case 0: /* timeout */
1755 default: /* data to read */
1759 rc = fdRead(fd, buf + total, count - total);
1770 fprintf(stderr, "*** read: rc %d errno %d %s \"%s\"\n", rc, errno, strerror(errno), buf);
1773 } else if (rc == 0) {
1783 static ssize_t ufdWrite(void * cookie, const char * buf, size_t count)
1785 FD_t fd = c2f(cookie);
1790 if (fdGetIo(fd) == fdio) {
1792 (void) fstat(fdGetFdno(fd), &sb);
1793 if (S_ISREG(sb.st_mode))
1794 return fdWrite(fd, buf, count);
1800 for (total = 0; total < count; total += bytesWritten) {
1806 /* Is there room to write data? */
1807 if (fd->bytesRemain == 0) {
1808 fprintf(stderr, "*** ufdWrite fd %p WRITE PAST END OF CONTENT\n", fd);
1809 return total; /* XXX simulate EOF */
1811 rc = fdWritable(fd, 2); /* XXX configurable? */
1814 case -1: /* error */
1815 case 0: /* timeout */
1818 default: /* data to write */
1822 rc = fdWrite(fd, buf + total, count - total);
1833 fprintf(stderr, "*** write: rc %d errno %d %s \"%s\"\n", rc, errno, strerror(errno), buf);
1836 } else if (rc == 0) {
1846 static inline int ufdSeek(void * cookie, _libio_pos_t pos, int whence)
1848 FD_t fd = c2f(cookie);
1850 switch (fd->urlType) {
1851 case URL_IS_UNKNOWN:
1863 return fdSeek(cookie, pos, whence);
1866 int ufdClose( void * cookie)
1868 FD_t fd = c2f(cookie);
1873 urlinfo u = fd->url;
1876 fd = u->data = fdFree(fd, "grab data (ufdClose persist)");
1878 fd = fdFree(fd, "grab data (ufdClose)");
1879 (void) urlFree(fd->url, "url (ufdClose)");
1881 u->ctrl = fdFree(u->ctrl, "grab ctrl (ufdClose)");
1883 if (u->urltype == URL_IS_FTP) {
1885 /* XXX if not using libio, lose the fp from fpio */
1893 * Non-error FTP has 4 refs on the data fd:
1894 * "persist data (ufdOpen FTP)" rpmio.c:888
1895 * "grab data (ufdOpen FTP)" rpmio.c:892
1896 * "open data (ftpReq)" ftp.c:633
1897 * "fopencookie" rpmio.c:1507
1899 * Non-error FTP has 5 refs on the ctrl fd:
1900 * "persist ctrl" url.c:176
1901 * "grab ctrl (urlConnect FTP)" rpmio.c:404
1902 * "open ctrl" ftp.c:504
1903 * "grab data (ftpReq)" ftp.c:661
1904 * "open data (ftpReq)" ftp.c:662
1906 if (fd->bytesRemain > 0) {
1907 if (fd->ftpFileDoneNeeded) {
1908 if (fdReadable(u->ctrl, 0) > 0)
1909 (void) ftpFileDone(u, fd);
1911 (void) ftpAbort(u, fd);
1915 /* XXX STOR et al require close before ftpFileDone */
1917 #if 0 /* XXX error exit from ufdOpen does not have this set */
1918 assert(fd->ftpFileDoneNeeded != 0);
1920 /* FIX: u->data undefined */
1921 if (fd->ftpFileDoneNeeded)
1922 (void) ftpFileDone(u, fd);
1927 /* XXX Why not (u->urltype == URL_IS_HTTP) ??? */
1928 /* XXX Why not (u->urltype == URL_IS_HTTPS) ??? */
1929 /* XXX Why not (u->urltype == URL_IS_HKP) ??? */
1930 if (u->scheme != NULL
1931 && (!strncmp(u->scheme, "http", sizeof("http")-1) || !strncmp(u->scheme, "hkp", sizeof("hkp")-1)))
1934 * HTTP has 4 (or 5 if persistent malloc) refs on the fd:
1935 * "persist ctrl" url.c:177
1936 * "grab ctrl (ufdOpen HTTP)" rpmio.c:924
1937 * "grab data (ufdOpen HTTP)" rpmio.c:928
1938 * "open ctrl (httpReq)" ftp.c:382
1939 * "open data (httpReq)" ftp.c:435
1943 fd = u->ctrl = fdFree(fd, "open data (ufdClose HTTP persist ctrl)");
1944 else if (fd == u->data)
1945 fd = u->data = fdFree(fd, "open data (ufdClose HTTP persist data)");
1947 fd = fdFree(fd, "open data (ufdClose HTTP)");
1949 /* XXX if not using libio, lose the fp from fpio */
1956 /* If content remains, then don't persist. */
1957 if (fd->bytesRemain > 0)
1959 fd->contentLength = fd->bytesRemain = -1;
1961 /* If persisting, then Fclose will juggle refcounts. */
1962 if (fd->persist && (fd == u->ctrl || fd == u->data))
1969 FD_t ftpOpen(const char *url, int flags,
1970 mode_t mode, urlinfo *uret)
1975 #if 0 /* XXX makeTempFile() heartburn */
1976 assert(!(flags & O_RDWR));
1978 if (urlConnect(url, &u) < 0)
1981 if (u->data == NULL)
1982 u->data = fdNew("persist data (ftpOpen)");
1984 if (u->data->url == NULL)
1985 fd = fdLink(u->data, "grab data (ftpOpen persist data)");
1987 fd = fdNew("grab data (ftpOpen)");
1991 fd->ftpFileDoneNeeded = 0;
1992 fd->rd_timeoutsecs = ftpTimeoutSecs;
1993 fd->contentLength = fd->bytesRemain = -1;
1994 fd->url = urlLink(u, "url (ufdOpen FTP)");
1995 fd->urlType = URL_IS_FTP;
2005 /* FIX: u->{ctrl,data}->url undef after XurlLink. */
2006 static FD_t httpOpen(const char * url, int flags,
2007 mode_t mode, urlinfo * uret)
2012 #if 0 /* XXX makeTempFile() heartburn */
2013 assert(!(flags & O_RDWR));
2015 if (urlSplit(url, &u))
2018 if (u->ctrl == NULL)
2019 u->ctrl = fdNew("persist ctrl (httpOpen)");
2020 if (u->ctrl->nrefs > 2 && u->data == NULL)
2021 u->data = fdNew("persist data (httpOpen)");
2023 if (u->ctrl->url == NULL)
2024 fd = fdLink(u->ctrl, "grab ctrl (httpOpen persist ctrl)");
2025 else if (u->data->url == NULL)
2026 fd = fdLink(u->data, "grab ctrl (httpOpen persist data)");
2028 fd = fdNew("grab ctrl (httpOpen)");
2032 fd->ftpFileDoneNeeded = 0;
2033 fd->rd_timeoutsecs = httpTimeoutSecs;
2034 fd->contentLength = fd->bytesRemain = -1;
2035 fd->url = urlLink(u, "url (httpOpen)");
2036 fd = fdLink(fd, "grab data (httpOpen)");
2037 fd->urlType = URL_IS_HTTP;
2047 static FD_t ufdOpen(const char * url, int flags, mode_t mode)
2053 urltype urlType = urlPath(url, &path);
2056 fprintf(stderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mode);
2060 fd = ftpOpen(url, flags, mode, &u);
2061 if (fd == NULL || u == NULL)
2064 /* XXX W2DO? use STOU rather than STOR to prevent clobbering */
2065 cmd = ((flags & O_WRONLY)
2066 ? ((flags & O_APPEND) ? "APPE" :
2067 ((flags & O_CREAT) ? "STOR" : "STOR"))
2068 : ((flags & O_CREAT) ? "STOR" : "RETR"));
2069 u->openError = ftpReq(fd, cmd, path);
2070 if (u->openError < 0) {
2071 /* XXX make sure that we can exit through ufdClose */
2072 fd = fdLink(fd, "error data (ufdOpen FTP)");
2074 fd->bytesRemain = ((!strcmp(cmd, "RETR"))
2075 ? fd->contentLength : -1);
2083 fd = davOpen(url, flags, mode, &u);
2085 fd = httpOpen(url, flags, mode, &u);
2087 if (fd == NULL || u == NULL)
2090 cmd = ((flags & O_WRONLY)
2091 ? ((flags & O_APPEND) ? "PUT" :
2092 ((flags & O_CREAT) ? "PUT" : "PUT"))
2095 u->openError = davReq(fd, cmd, path);
2097 u->openError = httpReq(fd, cmd, path);
2099 if (u->openError < 0) {
2100 /* XXX make sure that we can exit through ufdClose */
2101 fd = fdLink(fd, "error ctrl (ufdOpen HTTP)");
2102 fd = fdLink(fd, "error data (ufdOpen HTTP)");
2104 fd->bytesRemain = ((!strcmp(cmd, "GET"))
2105 ? fd->contentLength : -1);
2106 fd->wr_chunked = ((!strcmp(cmd, "PUT"))
2107 ? fd->wr_chunked : 0);
2111 assert(!(flags & O_RDWR));
2112 fd = fdDup( ((flags & O_WRONLY) ? STDOUT_FILENO : STDIN_FILENO) );
2115 fd->rd_timeoutsecs = 600; /* XXX W2DO? 10 mins? */
2116 fd->contentLength = fd->bytesRemain = -1;
2120 case URL_IS_UNKNOWN:
2122 fd = fdOpen(path, flags, mode);
2125 fd->rd_timeoutsecs = 1;
2126 fd->contentLength = fd->bytesRemain = -1;
2131 if (fd == NULL) return NULL;
2132 fd->urlType = urlType;
2133 if (Fileno(fd) < 0) {
2134 (void) ufdClose(fd);
2137 DBGIO(fd, (stderr, "==>\tufdOpen(\"%s\",%x,0%o) %s\n", url, (unsigned)flags, (unsigned)mode, fdbg(fd)));
2141 /* LCL: function typedefs */
2142 static struct FDIO_s ufdio_s = {
2143 ufdRead, ufdWrite, ufdSeek, ufdClose, XfdLink, XfdFree, XfdNew, fdFileno,
2144 ufdOpen, NULL, fdGetFp, NULL, Mkdir, Chdir, Rmdir, Rename, Unlink
2146 FDIO_t ufdio = &ufdio_s ;
2148 /* =============================================================== */
2149 /* Support for GZIP library.
2155 static inline void * gzdFileno(FD_t fd)
2161 for (i = fd->nfps; i >= 0; i--) {
2162 FDSTACK_t * fps = &fd->fps[i];
2163 if (fps->io != gzdio)
2173 FD_t gzdOpen(const char * path, const char * fmode)
2177 if ((gzfile = gzopen(path, fmode)) == NULL)
2179 fd = fdNew("open (gzdOpen)");
2180 fdPop(fd); fdPush(fd, gzdio, gzfile, -1);
2182 DBGIO(fd, (stderr, "==>\tgzdOpen(\"%s\", \"%s\") fd %p %s\n", path, fmode, (fd ? fd : NULL), fdbg(fd)));
2183 return fdLink(fd, "gzdOpen");
2186 static FD_t gzdFdopen(void * cookie, const char *fmode)
2188 FD_t fd = c2f(cookie);
2192 if (fmode == NULL) return NULL;
2193 fdno = fdFileno(fd);
2194 fdSetFdno(fd, -1); /* XXX skip the fdio close */
2195 if (fdno < 0) return NULL;
2196 gzfile = gzdopen(fdno, fmode);
2197 if (gzfile == NULL) return NULL;
2199 fdPush(fd, gzdio, gzfile, fdno); /* Push gzdio onto stack */
2201 return fdLink(fd, "gzdFdopen");
2204 static int gzdFlush(FD_t fd)
2207 gzfile = gzdFileno(fd);
2208 if (gzfile == NULL) return -2;
2209 return gzflush(gzfile, Z_SYNC_FLUSH); /* XXX W2DO? */
2212 /* =============================================================== */
2213 static ssize_t gzdRead(void * cookie, char * buf, size_t count)
2215 FD_t fd = c2f(cookie);
2219 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
2221 gzfile = gzdFileno(fd);
2222 if (gzfile == NULL) return -2; /* XXX can't happen */
2224 fdstat_enter(fd, FDSTAT_READ);
2225 rc = gzread(gzfile, buf, count);
2226 DBGIO(fd, (stderr, "==>\tgzdRead(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
2229 fd->errcookie = gzerror(gzfile, &zerror);
2230 if (zerror == Z_ERRNO) {
2231 fd->syserrno = errno;
2232 fd->errcookie = strerror(fd->syserrno);
2234 } else if (rc >= 0) {
2235 fdstat_exit(fd, FDSTAT_READ, rc);
2236 if (fd->ndigests && rc > 0) fdUpdateDigests(fd, (void *)buf, rc);
2241 static ssize_t gzdWrite(void * cookie, const char * buf, size_t count)
2243 FD_t fd = c2f(cookie);
2247 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
2249 if (fd->ndigests && count > 0) fdUpdateDigests(fd, (void *)buf, count);
2251 gzfile = gzdFileno(fd);
2252 if (gzfile == NULL) return -2; /* XXX can't happen */
2254 fdstat_enter(fd, FDSTAT_WRITE);
2255 rc = gzwrite(gzfile, (void *)buf, count);
2256 DBGIO(fd, (stderr, "==>\tgzdWrite(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
2259 fd->errcookie = gzerror(gzfile, &zerror);
2260 if (zerror == Z_ERRNO) {
2261 fd->syserrno = errno;
2262 fd->errcookie = strerror(fd->syserrno);
2264 } else if (rc > 0) {
2265 fdstat_exit(fd, FDSTAT_WRITE, rc);
2270 /* XXX zlib-1.0.4 has not */
2271 static inline int gzdSeek(void * cookie, _libio_pos_t pos, int whence)
2273 #ifdef USE_COOKIE_SEEK_POINTER
2274 _IO_off64_t p = *pos;
2280 FD_t fd = c2f(cookie);
2283 if (fd == NULL) return -2;
2284 assert(fd->bytesRemain == -1); /* XXX FIXME */
2286 gzfile = gzdFileno(fd);
2287 if (gzfile == NULL) return -2; /* XXX can't happen */
2289 fdstat_enter(fd, FDSTAT_SEEK);
2290 rc = gzseek(gzfile, p, whence);
2291 DBGIO(fd, (stderr, "==>\tgzdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd)));
2294 fd->errcookie = gzerror(gzfile, &zerror);
2295 if (zerror == Z_ERRNO) {
2296 fd->syserrno = errno;
2297 fd->errcookie = strerror(fd->syserrno);
2299 } else if (rc >= 0) {
2300 fdstat_exit(fd, FDSTAT_SEEK, rc);
2308 static int gzdClose( void * cookie)
2310 FD_t fd = c2f(cookie);
2314 gzfile = gzdFileno(fd);
2315 if (gzfile == NULL) return -2; /* XXX can't happen */
2317 fdstat_enter(fd, FDSTAT_CLOSE);
2318 rc = gzclose(gzfile);
2320 /* XXX TODO: preserve fd if errors */
2323 DBGIO(fd, (stderr, "==>\tgzdClose(%p) zerror %d %s\n", cookie, rc, fdbg(fd)));
2325 fd->errcookie = "gzclose error";
2326 if (rc == Z_ERRNO) {
2327 fd->syserrno = errno;
2328 fd->errcookie = strerror(fd->syserrno);
2330 } else if (rc >= 0) {
2331 fdstat_exit(fd, FDSTAT_CLOSE, rc);
2335 DBGIO(fd, (stderr, "==>\tgzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
2337 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "GZDIO", stderr);
2339 fd = fdFree(fd, "open (gzdClose)");
2343 /* LCL: function typedefs */
2344 static struct FDIO_s gzdio_s = {
2345 gzdRead, gzdWrite, gzdSeek, gzdClose, XfdLink, XfdFree, XfdNew, fdFileno,
2346 NULL, gzdOpen, gzdFileno, gzdFlush, NULL, NULL, NULL, NULL, NULL
2348 FDIO_t gzdio = &gzdio_s ;
2350 #endif /* HAVE_ZLIB_H */
2352 /* =============================================================== */
2353 /* Support for BZIP2 library.
2360 # define bzopen BZ2_bzopen
2361 # define bzclose BZ2_bzclose
2362 # define bzdopen BZ2_bzdopen
2363 # define bzerror BZ2_bzerror
2364 # define bzflush BZ2_bzflush
2365 # define bzread BZ2_bzread
2366 # define bzwrite BZ2_bzwrite
2367 #endif /* HAVE_BZ2_1_0 */
2369 static inline void * bzdFileno(FD_t fd)
2375 for (i = fd->nfps; i >= 0; i--) {
2376 FDSTACK_t * fps = &fd->fps[i];
2377 if (fps->io != bzdio)
2386 static FD_t bzdOpen(const char * path, const char * mode)
2390 if ((bzfile = bzopen(path, mode)) == NULL)
2392 fd = fdNew("open (bzdOpen)");
2393 fdPop(fd); fdPush(fd, bzdio, bzfile, -1);
2394 return fdLink(fd, "bzdOpen");
2397 static FD_t bzdFdopen(void * cookie, const char * fmode)
2399 FD_t fd = c2f(cookie);
2403 if (fmode == NULL) return NULL;
2404 fdno = fdFileno(fd);
2405 fdSetFdno(fd, -1); /* XXX skip the fdio close */
2406 if (fdno < 0) return NULL;
2407 bzfile = bzdopen(fdno, fmode);
2408 if (bzfile == NULL) return NULL;
2410 fdPush(fd, bzdio, bzfile, fdno); /* Push bzdio onto stack */
2412 return fdLink(fd, "bzdFdopen");
2415 static int bzdFlush(FD_t fd)
2417 return bzflush(bzdFileno(fd));
2420 /* =============================================================== */
2421 static ssize_t bzdRead(void * cookie, char * buf, size_t count)
2423 FD_t fd = c2f(cookie);
2427 if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
2428 bzfile = bzdFileno(fd);
2429 fdstat_enter(fd, FDSTAT_READ);
2431 rc = bzread(bzfile, buf, count);
2435 fd->errcookie = bzerror(bzfile, &zerror);
2436 } else if (rc >= 0) {
2437 fdstat_exit(fd, FDSTAT_READ, rc);
2438 if (fd->ndigests && rc > 0) fdUpdateDigests(fd, (void *)buf, rc);
2443 static ssize_t bzdWrite(void * cookie, const char * buf, size_t count)
2445 FD_t fd = c2f(cookie);
2449 if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
2451 if (fd->ndigests && count > 0) fdUpdateDigests(fd, (void *)buf, count);
2453 bzfile = bzdFileno(fd);
2454 fdstat_enter(fd, FDSTAT_WRITE);
2455 rc = bzwrite(bzfile, (void *)buf, count);
2458 fd->errcookie = bzerror(bzfile, &zerror);
2459 } else if (rc > 0) {
2460 fdstat_exit(fd, FDSTAT_WRITE, rc);
2465 static inline int bzdSeek(void * cookie, _libio_pos_t pos,
2468 FD_t fd = c2f(cookie);
2474 static int bzdClose( void * cookie)
2476 FD_t fd = c2f(cookie);
2480 bzfile = bzdFileno(fd);
2482 if (bzfile == NULL) return -2;
2483 fdstat_enter(fd, FDSTAT_CLOSE);
2486 rc = 0; /* XXX FIXME */
2488 /* XXX TODO: preserve fd if errors */
2493 fd->errcookie = bzerror(bzfile, &zerror);
2494 } else if (rc >= 0) {
2495 fdstat_exit(fd, FDSTAT_CLOSE, rc);
2499 DBGIO(fd, (stderr, "==>\tbzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
2501 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "BZDIO", stderr);
2503 fd = fdFree(fd, "open (bzdClose)");
2507 /* LCL: function typedefs */
2508 static struct FDIO_s bzdio_s = {
2509 bzdRead, bzdWrite, bzdSeek, bzdClose, XfdLink, XfdFree, XfdNew, fdFileno,
2510 NULL, bzdOpen, bzdFileno, bzdFlush, NULL, NULL, NULL, NULL, NULL
2512 FDIO_t bzdio = &bzdio_s ;
2514 #endif /* HAVE_BZLIB_H */
2516 /* =============================================================== */
2517 static const char * getFdErrstr (FD_t fd)
2519 const char *errstr = NULL;
2522 if (fdGetIo(fd) == gzdio) {
2523 errstr = fd->errcookie;
2525 #endif /* HAVE_ZLIB_H */
2528 if (fdGetIo(fd) == bzdio) {
2529 errstr = fd->errcookie;
2531 #endif /* HAVE_BZLIB_H */
2534 errstr = (fd->syserrno ? strerror(fd->syserrno) : "");
2540 /* =============================================================== */
2542 const char *Fstrerror(FD_t fd)
2545 return (errno ? strerror(errno) : "");
2547 return getFdErrstr(fd);
2550 #define FDIOVEC(_fd, _vec) \
2551 ((fdGetIo(_fd) && fdGetIo(_fd)->_vec) ? fdGetIo(_fd)->_vec : NULL)
2553 ssize_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd) {
2554 fdio_read_function_t _read;
2558 DBGIO(fd, (stderr, "==> Fread(%p,%u,%u,%p) %s\n", buf, (unsigned)size, (unsigned)nmemb, (fd ? fd : NULL), fdbg(fd)));
2560 if (fdGetIo(fd) == fpio) {
2561 rc = fread(buf, size, nmemb, fdGetFILE(fd));
2565 _read = FDIOVEC(fd, read);
2567 rc = (_read ? (*_read) (fd, buf, size * nmemb) : -2);
2571 ssize_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
2573 fdio_write_function_t _write;
2577 DBGIO(fd, (stderr, "==> Fwrite(%p,%u,%u,%p) %s\n", buf, (unsigned)size, (unsigned)nmemb, (fd ? fd : NULL), fdbg(fd)));
2579 if (fdGetIo(fd) == fpio) {
2580 rc = fwrite(buf, size, nmemb, fdGetFILE(fd));
2584 _write = FDIOVEC(fd, write);
2586 rc = (_write ? _write(fd, buf, size * nmemb) : -2);
2590 int Fseek(FD_t fd, _libio_off_t offset, int whence) {
2591 fdio_seek_function_t _seek;
2592 #ifdef USE_COOKIE_SEEK_POINTER
2593 _IO_off64_t o64 = offset;
2594 _libio_pos_t pos = &o64;
2596 _libio_pos_t pos = offset;
2602 DBGIO(fd, (stderr, "==> Fseek(%p,%ld,%d) %s\n", fd, (long)offset, whence, fdbg(fd)));
2604 if (fdGetIo(fd) == fpio) {
2608 rc = fseek(fp, offset, whence);
2612 _seek = FDIOVEC(fd, seek);
2614 rc = (_seek ? _seek(fd, pos, whence) : -2);
2623 DBGIO(fd, (stderr, "==> Fclose(%p) %s\n", (fd ? fd : NULL), fdbg(fd)));
2625 fd = fdLink(fd, "Fclose");
2626 while (fd->nfps >= 0) {
2627 FDSTACK_t * fps = &fd->fps[fd->nfps];
2629 if (fps->io == fpio) {
2635 /* XXX persistent HTTP/1.1 returns the previously opened fp */
2636 if (fd->nfps > 0 && fpno == -1 &&
2637 fd->fps[fd->nfps-1].io == ufdio &&
2638 fd->fps[fd->nfps-1].fp == fp &&
2639 (fd->fps[fd->nfps-1].fdno >= 0 || fd->req != NULL))
2641 int hadreqpersist = (fd->req != NULL);
2647 if (fdGetFdno(fd) >= 0)
2654 /* HACK: flimsy Keepalive wiring. */
2655 if (hadreqpersist) {
2672 fd = fdFree(fd, "fopencookie (Fclose)");
2677 fdio_close_function_t _close = FDIOVEC(fd, close);
2686 fd = fdFree(fd, "Fclose");
2691 * Convert stdio fmode to open(2) mode, filtering out zlib/bzlib flags.
2692 * returns stdio[0] = NUL on error.
2694 * - gzopen: [0-9] is compession level
2695 * - gzopen: 'f' is filtered (Z_FILTERED)
2696 * - gzopen: 'h' is Huffman encoding (Z_HUFFMAN_ONLY)
2697 * - bzopen: [1-9] is block size (modulo 100K)
2698 * - bzopen: 's' is smallmode
2699 * - HACK: '.' terminates, rest is type of I/O
2701 static inline void cvtfmode (const char *m,
2702 char *stdio, size_t nstdio,
2703 char *other, size_t nother,
2704 const char **end, int * f)
2711 flags |= O_WRONLY | O_CREAT | O_APPEND;
2712 if (--nstdio > 0) *stdio++ = *m;
2715 flags |= O_WRONLY | O_CREAT | O_TRUNC;
2716 if (--nstdio > 0) *stdio++ = *m;
2720 if (--nstdio > 0) *stdio++ = *m;
2729 while ((c = *m++) != '\0') {
2734 flags &= ~(O_RDONLY|O_WRONLY);
2736 if (--nstdio > 0) *stdio++ = c;
2740 if (--nstdio > 0) *stdio++ = c;
2745 if (--nstdio > 0) *stdio++ = c;
2749 if (--nother > 0) *other++ = c;
2756 *stdio = *other = '\0';
2758 *end = (*m != '\0' ? m : NULL);
2764 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0
2765 /* XXX retrofit glibc-2.1.x typedef on glibc-2.0.x systems */
2766 typedef _IO_cookie_io_functions_t cookie_io_functions_t;
2770 FD_t Fdopen(FD_t ofd, const char *fmode)
2772 char stdio[20], other[20], zstdio[20];
2773 const char *end = NULL;
2778 fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
2784 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL);
2785 if (stdio[0] == '\0')
2788 strncat(zstdio, stdio, sizeof(zstdio) - strlen(zstdio));
2789 strncat(zstdio, other, sizeof(zstdio) - strlen(zstdio));
2791 if (end == NULL && other[0] == '\0')
2795 if (!strcmp(end, "fdio")) {
2797 } else if (!strcmp(end, "gzdio")) {
2799 fd = gzdFdopen(fd, zstdio);
2801 } else if (!strcmp(end, "bzdio")) {
2803 fd = bzdFdopen(fd, zstdio);
2805 } else if (!strcmp(end, "ufdio")) {
2807 } else if (!strcmp(end, "fpio")) {
2810 int fdno = Fileno(fd);
2811 FILE * fp = fdopen(fdno, stdio);
2813 fprintf(stderr, "*** Fdopen fpio fp %p\n", (void *)fp);
2816 /* XXX gzdio/bzdio use fp for private data */
2817 if (fdGetFp(fd) == NULL)
2819 fdPush(fd, fpio, fp, fdno); /* Push fpio onto stack */
2822 } else if (other[0] != '\0') {
2823 for (end = other; *end && strchr("0123456789fh", *end); end++)
2827 fd = gzdFdopen(fd, zstdio);
2837 { cookie_io_functions_t ciof;
2838 ciof.read = iof->read;
2839 ciof.write = iof->write;
2840 ciof.seek = iof->seek;
2841 ciof.close = iof->close;
2842 fp = fopencookie(fd, stdio, ciof);
2843 DBGIO(fd, (stderr, "==> fopencookie(%p,\"%s\",*%p) returns fp %p\n", fd, stdio, iof, fp));
2848 /* XXX gzdio/bzdio use fp for private data */
2849 if (fdGetFp(fd) == NULL)
2851 fdPush(fd, fpio, fp, fileno(fp)); /* Push fpio onto stack */
2852 fd = fdLink(fd, "fopencookie");
2856 DBGIO(fd, (stderr, "==> Fdopen(%p,\"%s\") returns fd %p %s\n", ofd, fmode, (fd ? fd : NULL), fdbg(fd)));
2860 FD_t Fopen(const char *path, const char *fmode)
2862 char stdio[20], other[20];
2863 const char *end = NULL;
2864 mode_t perms = 0666;
2868 if (path == NULL || fmode == NULL)
2872 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, &flags);
2873 if (stdio[0] == '\0')
2876 if (end == NULL || !strcmp(end, "fdio")) {
2878 fprintf(stderr, "*** Fopen fdio path %s fmode %s\n", path, fmode);
2879 fd = fdOpen(path, flags, perms);
2880 if (fdFileno(fd) < 0) {
2881 if (fd) (void) fdClose(fd);
2889 /* XXX gzdio and bzdio here too */
2891 switch (urlIsURL(path)) {
2899 case URL_IS_UNKNOWN:
2901 fprintf(stderr, "*** Fopen ufdio path %s fmode %s\n", path, fmode);
2902 fd = ufdOpen(path, flags, perms);
2903 if (fd == NULL || !(fdFileno(fd) >= 0 || fd->req != NULL))
2908 fprintf(stderr, "*** Fopen WTFO path %s fmode %s\n", path, fmode);
2913 /* XXX persistent HTTP/1.1 returns the previously opened fp */
2914 if (isHTTP && ((fp = fdGetFp(fd)) != NULL) && ((fdno = fdGetFdno(fd)) >= 0 || fd->req != NULL))
2916 fdPush(fd, fpio, fp, fileno(fp)); /* Push fpio onto stack */
2922 fd = Fdopen(fd, fmode);
2929 if (fd == NULL) return -1;
2930 if (fdGetIo(fd) == fpio)
2931 return fflush(fdGetFILE(fd));
2934 if (vh && fdGetIo(fd) == gzdio)
2935 return gzdFlush(vh);
2937 if (vh && fdGetIo(fd) == bzdio)
2938 return bzdFlush(vh);
2948 if (fd == NULL) return -1;
2949 if (fd->req != NULL) {
2950 /* HACK: flimsy wiring for neon errors. */
2951 rc = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
2953 for (i = fd->nfps; rc == 0 && i >= 0; i--) {
2954 FDSTACK_t * fps = &fd->fps[i];
2957 if (fps->io == fpio) {
2958 ec = ferror(fdGetFILE(fd));
2959 } else if (fps->io == gzdio) {
2960 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
2961 i--; /* XXX fdio under gzdio always has fdno == -1 */
2963 } else if (fps->io == bzdio) {
2964 ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
2965 i--; /* XXX fdio under bzdio always has fdno == -1 */
2968 /* XXX need to check ufdio/gzdio/bzdio/fdio errors correctly. */
2969 ec = (fdFileno(fd) < 0 ? -1 : 0);
2975 DBGIO(fd, (stderr, "==> Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd)));
2983 if (fd == NULL) return -1;
2984 if (fd->req != NULL)
2985 rc = 123456789; /* HACK: https has no steenkin fileno. */
2987 for (i = fd->nfps ; rc == -1 && i >= 0; i--) {
2988 rc = fd->fps[i].fdno;
2991 DBGIO(fd, (stderr, "==> Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, fdbg(fd)));
2995 /* XXX this is naive */
2996 int Fcntl(FD_t fd, int op, void *lip)
2998 return fcntl(Fileno(fd), op, lip);
3001 /* =============================================================== */
3002 /* Helper routines that may be generally useful.
3004 int rpmioMkpath(const char * path, mode_t mode, uid_t uid, gid_t gid)
3012 d = alloca(strlen(path)+2);
3013 de = stpcpy(d, path);
3015 for (de = d; *de != '\0'; de++) {
3019 while (*de && *de != '/') de++;
3032 rc = Mkdir(d, mode);
3036 if (!(uid == (uid_t) -1 && gid == (gid_t) -1)) {
3037 rc = chown(d, uid, gid);
3041 } else if (!S_ISDIR(st.st_mode)) {
3048 rpmMessage(RPMMESS_DEBUG, "created directory(s) %s mode 0%o\n",
3053 int rpmioSlurp(const char * fn, byte ** bp, ssize_t * blenp)
3055 static ssize_t blenmax = (32 * BUFSIZ);
3062 fd = Fopen(fn, "r.ufdio");
3063 if (fd == NULL || Ferror(fd)) {
3069 blen = (size >= 0 ? size : blenmax);
3072 b = xmalloc(blen+1);
3074 nb = Fread(b, sizeof(*b), blen, fd);
3075 if (Ferror(fd) || (size > 0 && nb != blen)) {
3079 if (blen == blenmax && nb < blen) {
3081 b = xrealloc(b, blen+1);
3087 if (fd) (void) Fclose(fd);
3096 else if (b) free(b);
3098 if (blenp) *blenp = blen;
3103 /* LCL: function typedefs */
3104 static struct FDIO_s fpio_s = {
3105 ufdRead, ufdWrite, fdSeek, ufdClose, XfdLink, XfdFree, XfdNew, fdFileno,
3106 ufdOpen, NULL, fdGetFp, NULL, Mkdir, Chdir, Rmdir, Rename, Unlink
3108 FDIO_t fpio = &fpio_s ;