10
typedef unsigned int uint32_t;
12
#define INADDR_ANY ((uint32_t) 0x00000000)
15
#else /* __LCLINT__ */
17
#if HAVE_MACHINE_TYPES_H
18
# include <machine/types.h>
21
#include <netinet/in.h>
22
#include <arpa/inet.h> /* XXX for inet_aton and HP-UX */
24
#if HAVE_NETINET_IN_SYSTM_H
25
# include <sys/types.h>
26
# include <netinet/in_systm.h>
29
#if HAVE_LIBIO_H && defined(_G_IO_IO_FILE_VERSION)
33
#endif /* __LCLINT__ */
35
#if !defined(HAVE_HERRNO) && defined(__hpux) /* XXX HP-UX w/o -D_XOPEN_SOURCE needs */
43
#define IPPORT_HTTP 80
46
#if !defined(HAVE_INET_ATON)
47
static int inet_aton(const char *cp, struct in_addr *inp)
52
if (addr == ((long) -1)) return 0;
54
memcpy(inp, &addr, sizeof(addr));
59
#if defined(USE_ALT_DNS) && USE_ALT_DNS
63
#include <rpmio_internal.h>
71
#include "rpmmessages.h"
76
/*@access FDSTAT_t @*/
78
#define FDNREFS(fd) (fd ? ((FD_t)fd)->nrefs : -9)
79
#define FDTO(fd) (fd ? ((FD_t)fd)->rd_timeoutsecs : -99)
80
#define FDCPIOPOS(fd) (fd ? ((FD_t)fd)->fd_cpioPos : -99)
82
#define FDONLY(fd) assert(fdGetIo(fd) == fdio)
83
#define GZDONLY(fd) assert(fdGetIo(fd) == gzdio)
84
#define BZDONLY(fd) assert(fdGetIo(fd) == bzdio)
86
#define UFDONLY(fd) /* assert(fdGetIo(fd) == ufdio) */
88
#define fdGetFILE(_fd) ((FILE *)fdGetFp(_fd))
96
#define TIMEOUT_SECS 60
97
static int ftpTimeoutSecs = TIMEOUT_SECS;
98
static int httpTimeoutSecs = TIMEOUT_SECS;
101
int _rpmio_debug = 0;
104
* Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
105
* @param p memory to free
106
* @retval NULL always
108
/*@unused@*/ static inline /*@null@*/ void *
109
_free(/*@only@*/ /*@null@*/ const void * p)
112
if (p != NULL) free((void *)p);
116
/* =============================================================== */
118
static /*@observer@*/ const char * fdbg(/*@null@*/ FD_t fd)
119
/*@modifies fileSystem @*/
121
static char buf[BUFSIZ];
130
sprintf(be, "fd %p", fd); be += strlen(be);
131
if (fd->rd_timeoutsecs >= 0) {
132
sprintf(be, " secs %d", fd->rd_timeoutsecs);
136
if (fd->bytesRemain != -1) {
137
sprintf(be, " clen %d", (int)fd->bytesRemain);
140
if (fd->wr_chunked) {
141
strcpy(be, " chunked");
145
for (i = fd->nfps; i >= 0; i--) {
146
FDSTACK_t * fps = &fd->fps[i];
151
if (fps->io == fdio) {
152
sprintf(be, "FD %d fp %p", fps->fdno, fps->fp);
153
} else if (fps->io == ufdio) {
154
sprintf(be, "UFD %d fp %p", fps->fdno, fps->fp);
155
} else if (fps->io == fadio) {
156
sprintf(be, "FAD %d fp %p", fps->fdno, fps->fp);
157
} else if (fps->io == gzdio) {
158
sprintf(be, "GZD %p fdno %d", fps->fp, fps->fdno);
160
} else if (fps->io == bzdio) {
161
sprintf(be, "BZD %p fdno %d", fps->fp, fps->fdno);
163
} else if (fps->io == fpio) {
165
sprintf(be, "%s %p(%d) fdno %d",
166
(fps->fdno < 0 ? "LIBIO" : "FP"),
167
fps->fp, fileno(((FILE *)fps->fp)), fps->fdno);
170
sprintf(be, "??? io %p fp %p fdno %d ???",
171
fps->io, fps->fp, fps->fdno);
179
/* =============================================================== */
180
off_t fdSize(FD_t fd)
186
DBGIO(0, (stderr, "==>\tfdSize(%p) rc %ld\n", fd, (long)rc));
189
if (fd->contentLength >= 0)
190
rc = fd->contentLength;
191
else switch (fd->urlType) {
194
if (fstat(Fileno(fd), &sb) == 0)
210
if ((nfdno = dup(fdno)) < 0)
212
fd = fdNew("open (fdDup)");
213
fdSetFdno(fd, nfdno);
214
DBGIO(fd, (stderr, "==> fdDup(%d) fd %p %s\n", fdno, (fd ? fd : NULL), fdbg(fd)));
215
/*@-refcounttrans@*/ return fd; /*@=refcounttrans@*/
218
static inline /*@unused@*/ int fdSeekNot(void * cookie,
219
/*@unused@*/ _libio_pos_t pos, /*@unused@*/ int whence)
222
FD_t fd = c2f(cookie);
223
FDSANE(fd); /* XXX keep gcc quiet */
228
FILE *fdFdopen(void * cookie, const char *fmode)
230
FD_t fd = c2f(cookie);
234
if (fmode == NULL) return NULL;
236
if (fdno < 0) return NULL;
237
fp = fdopen(fdno, fmode);
238
DBGIO(fd, (stderr, "==> fdFdopen(%p,\"%s\") fdno %d -> fp %p fdno %d\n", cookie, fmode, fdno, fp, fileno(fp)));
239
fd = fdFree(fd, "open (fdFdopen)");
250
/* =============================================================== */
251
static inline /*@null@*/ FD_t XfdLink(void * cookie, const char * msg,
252
const char * file, unsigned line)
253
/*@modifies internalState @*/
258
DBGREFS(0, (stderr, "--> fd %p ++ %d %s at %s:%u\n", cookie, FDNREFS(cookie)+1, msg, file, line));
263
DBGREFS(fd, (stderr, "--> fd %p ++ %d %s at %s:%u %s\n", fd, fd->nrefs, msg, file, line, fdbg(fd)));
268
static inline /*@null@*/ FD_t XfdFree( /*@killref@*/ FD_t fd, const char *msg,
269
const char *file, unsigned line)
273
DBGREFS(0, (stderr, "--> fd %p -- %d %s at %s:%u\n", fd, FDNREFS(fd), msg, file, line));
276
DBGREFS(fd, (stderr, "--> fd %p -- %d %s at %s:%u %s\n", fd, fd->nrefs, msg, file, line, fdbg(fd)));
278
/*@-refcounttrans -retalias@*/ return fd; /*@=refcounttrans =retalias@*/
279
fd->stats = _free(fd->stats);
280
fd->digest = _free(fd->digest);
281
/*@-refcounttrans@*/ free(fd); /*@=refcounttrans@*/
286
static inline /*@null@*/ FD_t XfdNew(const char * msg,
287
const char * file, unsigned line)
290
FD_t fd = (FD_t) xmalloc(sizeof(struct _FD_s));
291
if (fd == NULL) /* XXX xmalloc never returns NULL */
296
fd->urlType = URL_IS_UNKNOWN;
299
memset(fd->fps, 0, sizeof(fd->fps));
302
fd->fps[0].io = fdio;
304
fd->fps[0].fp = NULL;
305
fd->fps[0].fdno = -1;
308
fd->rd_timeoutsecs = 1; /* XXX default value used to be -1 */
309
fd->contentLength = fd->bytesRemain = -1;
312
fd->errcookie = NULL;
313
fd->stats = xcalloc(1, sizeof(*fd->stats));
315
(void) gettimeofday(&fd->stats->create, NULL);
316
fd->stats->begin = fd->stats->create; /* structure assignment */
318
fd->ftpFileDoneNeeded = 0;
323
return XfdLink(fd, msg, file, line);
326
/*@-redef@*/ /* FIX: legacy API should be made static */
327
ssize_t fdRead(void * cookie, /*@out@*/ char * buf, size_t count)
330
FD_t fd = c2f(cookie);
333
if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
335
fdstat_enter(fd, FDSTAT_READ);
336
rc = read(fdFileno(fd), buf, (count > fd->bytesRemain ? fd->bytesRemain : count));
337
fdstat_exit(fd, FDSTAT_READ, rc);
339
if (fd->digest && rc > 0) rpmDigestUpdate(fd->digest, buf, rc);
341
DBGIO(fd, (stderr, "==>\tfdRead(%p,%p,%ld) rc %ld %s\n", cookie, buf, (long)count, (long)rc, fdbg(fd)));
346
/*@-redef@*/ /* FIX: legacy API should be made static */
347
ssize_t fdWrite(void * cookie, const char * buf, size_t count)
350
FD_t fd = c2f(cookie);
351
int fdno = fdFileno(fd);
354
if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
356
if (fd->digest && count > 0) rpmDigestUpdate(fd->digest, buf, count);
358
if (fd->wr_chunked) {
360
sprintf(chunksize, "%x\r\n", (unsigned)count);
361
rc = write(fdno, chunksize, strlen(chunksize));
362
if (rc == -1) fd->syserrno = errno;
364
if (count == 0) return 0;
366
fdstat_enter(fd, FDSTAT_WRITE);
367
rc = write(fdno, buf, (count > fd->bytesRemain ? fd->bytesRemain : count));
368
fdstat_exit(fd, FDSTAT_WRITE, rc);
370
if (fd->wr_chunked) {
372
ec = write(fdno, "\r\n", sizeof("\r\n")-1);
373
if (ec == -1) fd->syserrno = errno;
376
DBGIO(fd, (stderr, "==>\tfdWrite(%p,%p,%ld) rc %ld %s\n", cookie, buf, (long)count, (long)rc, fdbg(fd)));
381
static inline int fdSeek(void * cookie, _libio_pos_t pos, int whence)
382
/*@modifies internalState, fileSystem @*/
384
#ifdef USE_COOKIE_SEEK_POINTER
385
_IO_off64_t p = *pos;
389
FD_t fd = c2f(cookie);
392
assert(fd->bytesRemain == -1); /* XXX FIXME fadio only for now */
393
fdstat_enter(fd, FDSTAT_SEEK);
394
rc = lseek(fdFileno(fd), p, whence);
395
fdstat_exit(fd, FDSTAT_SEEK, rc);
397
DBGIO(fd, (stderr, "==>\tfdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd)));
402
/*@-redef@*/ /* FIX: legacy API should be made static */
403
int fdClose( /*@only@*/ void * cookie)
410
if (cookie == NULL) return -2;
416
fdstat_enter(fd, FDSTAT_CLOSE);
417
rc = ((fdno >= 0) ? close(fdno) : -2);
418
fdstat_exit(fd, FDSTAT_CLOSE, rc);
420
DBGIO(fd, (stderr, "==>\tfdClose(%p) rc %lx %s\n", (fd ? fd : NULL), (unsigned long)rc, fdbg(fd)));
422
fd = fdFree(fd, "open (fdClose)");
426
/*@-redef@*/ /* FIX: legacy API should be made static */
427
/*@null@*/ FD_t fdOpen(const char *path, int flags, mode_t mode)
433
fdno = open(path, flags, mode);
434
if (fdno < 0) return NULL;
435
fd = fdNew("open (fdOpen)");
438
DBGIO(fd, (stderr, "==>\tfdOpen(\"%s\",%x,0%o) %s\n", path, (unsigned)flags, (unsigned)mode, fdbg(fd)));
439
/*@-refcounttrans@*/ return fd; /*@=refcounttrans@*/
442
static struct FDIO_s fdio_s = {
443
fdRead, fdWrite, fdSeek, fdClose, XfdLink, XfdFree, XfdNew, fdFileno,
444
fdOpen, NULL, fdGetFp, NULL, mkdir, chdir, rmdir, rename, unlink
446
FDIO_t fdio = /*@-compmempass@*/ &fdio_s /*@=compmempass@*/ ;
448
/*@-redef@*/ /* see lib/falloc.c */
449
FDIO_t fadio; /* XXX usually NULL, filled in when linked with rpm */
452
int fdWritable(FD_t fd, int secs)
456
struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL);
459
if ((fdno = fdFileno(fd)) < 0)
460
return -1; /* XXX W2DO? */
464
FD_SET(fdno, &wrfds);
471
/*@-compdef -nullpass@*/
472
rc = select(fdno + 1, NULL, &wrfds, NULL, tvp);
473
/*@=compdef =nullpass@*/
475
if (_rpmio_debug && !(rc == 1 && errno == 0))
476
fprintf(stderr, "*** fdWritable fdno %d rc %d %s\n", fdno, rc, strerror(errno));
481
/*@notreached@*/ break;
484
/*@notreached@*/ break;
492
int fdReadable(FD_t fd, int secs)
496
struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL);
499
if ((fdno = fdFileno(fd)) < 0)
500
return -1; /* XXX W2DO? */
504
FD_SET(fdno, &rdfds);
511
/*@-compdef -nullpass@*/
512
rc = select(fdno + 1, &rdfds, NULL, NULL, tvp);
513
/*@=compdef =nullpass@*/
519
/*@notreached@*/ break;
522
/*@notreached@*/ break;
530
int fdFgets(FD_t fd, char * buf, size_t len)
533
int secs = fd->rd_timeoutsecs;
536
char lastchar = '\0';
538
if ((fdno = fdFileno(fd)) < 0)
539
return 0; /* XXX W2DO? */
544
/* Is there data to read? */
545
rc = fdReadable(fd, secs);
551
/*@notreached@*/ break;
552
case 0: /* timeout */
555
/*@notreached@*/ break;
556
default: /* data to read */
562
rc = fdRead(fd, buf + nb, 1);
564
rc = read(fdFileno(fd), buf + nb, 1);
567
fd->syserrno = errno;
571
/*@notreached@*/ break;
576
fprintf(stderr, "*** read: fd %p rc %d errno %d %s \"%s\"\n", fd, rc, errno, strerror(errno), buf);
579
} else if (rc == 0) {
581
fprintf(stderr, "*** read: fd %p rc %d EOF errno %d %s \"%s\"\n", fd, rc, errno, strerror(errno), buf);
586
lastchar = buf[nb - 1];
588
} while (ec == 0 && nb < len && lastchar != '\n');
590
return (ec >= 0 ? nb : ec);
593
/* =============================================================== */
594
/* Support for FTP/HTTP I/O.
596
const char *const ftpStrerror(int errorNumber) {
597
switch (errorNumber) {
601
case FTPERR_BAD_SERVER_RESPONSE:
602
return _("Bad server response");
604
case FTPERR_SERVER_IO_ERROR:
605
return _("Server I/O error");
607
case FTPERR_SERVER_TIMEOUT:
608
return _("Server timeout");
610
case FTPERR_BAD_HOST_ADDR:
611
return _("Unable to lookup server host address");
613
case FTPERR_BAD_HOSTNAME:
614
return _("Unable to lookup server host name");
616
case FTPERR_FAILED_CONNECT:
617
return _("Failed to connect to server");
619
case FTPERR_FAILED_DATA_CONNECT:
620
return _("Failed to establish data connection to server");
622
case FTPERR_FILE_IO_ERROR:
623
return _("I/O error to local file");
625
case FTPERR_PASSIVE_ERROR:
626
return _("Error setting remote server to passive mode");
628
case FTPERR_FILE_NOT_FOUND:
629
return _("File not found on server");
631
case FTPERR_NIC_ABORT_IN_PROGRESS:
632
return _("Abort in progress");
636
return _("Unknown or unexpected error");
640
const char *urlStrerror(const char *url)
643
switch (urlIsURL(url)) {
647
/* XXX This only works for httpReq/ftpLogin/ftpReq failures */
648
if (urlSplit(url, &u) == 0) {
649
retstr = ftpStrerror(u->openError);
651
retstr = "Malformed URL";
654
retstr = strerror(errno);
660
#if !defined(USE_ALT_DNS) || !USE_ALT_DNS
661
static int mygethostbyname(const char * host,
662
/*@out@*/ struct in_addr * address)
663
/*@modifies *address, fileSystem @*/
665
struct hostent * hostinfo;
667
/*@-unrecog -multithreaded @*/
668
hostinfo = gethostbyname(host);
669
/*@=unrecog =multithreaded @*/
670
if (!hostinfo) return 1;
673
memcpy(address, hostinfo->h_addr_list[0], sizeof(*address));
679
static int getHostAddress(const char * host, /*@out@*/ struct in_addr * address)
680
/*@modifies *address, fileSystem @*/
682
if (xisdigit(host[0])) {
683
if (! /*@-unrecog@*/ inet_aton(host, address) /*@=unrecog@*/ )
684
return FTPERR_BAD_HOST_ADDR;
686
if (mygethostbyname(host, address)) {
687
errno = /*@-unrecog@*/ h_errno /*@=unrecog@*/;
688
return FTPERR_BAD_HOSTNAME;
695
static int tcpConnect(FD_t ctrl, const char * host, int port)
696
/*@modifies ctrl, fileSystem @*/
698
struct sockaddr_in sin;
702
memset(&sin, 0, sizeof(sin));
703
sin.sin_family = AF_INET;
704
sin.sin_port = htons(port);
705
sin.sin_addr.s_addr = INADDR_ANY;
708
if ((rc = getHostAddress(host, &sin.sin_addr)) < 0)
711
if ((fdno = socket(sin.sin_family, SOCK_STREAM, IPPROTO_IP)) < 0) {
712
rc = FTPERR_FAILED_CONNECT;
716
if (connect(fdno, (struct sockaddr *) &sin, sizeof(sin))) {
717
rc = FTPERR_FAILED_CONNECT;
726
fprintf(stderr,"++ connect %s:%d on fdno %d\n",
727
/*@-unrecog@*/ inet_ntoa(sin.sin_addr) /*@=unrecog@*/ ,
728
(int)ntohs(sin.sin_port), fdno);
730
fdSetFdno(ctrl, (fdno >= 0 ? fdno : -1));
735
fdSetSyserrno(ctrl, errno, ftpStrerror(rc));
742
static int checkResponse(void * uu, FD_t ctrl,
743
/*@out@*/ int *ecp, /*@out@*/ char ** str)
744
/*@modifies ctrl, *ecp, *str, fileSystem @*/
757
if (u->bufAlloced == 0 || u->buf == NULL) {
758
u->bufAlloced = url_iobuf_size;
759
u->buf = xcalloc(u->bufAlloced, sizeof(char));
762
bufAlloced = u->bufAlloced;
771
* Read next line from server.
773
se = buf + bufLength;
775
rc = fdFgets(ctrl, se, (bufAlloced - bufLength));
777
ec = FTPERR_BAD_SERVER_RESPONSE;
779
} else if (rc == 0 || fdWritable(ctrl, 0) < 1)
783
* Process next line from server.
785
for (s = se; *s != '\0'; s = se) {
788
while (*se && *se != '\n') se++;
790
if (se > s && se[-1] == '\r')
793
/*@innerbreak@*/ break;
796
fprintf(stderr, "<- %s\n", s);
798
/* HTTP: header termination on empty line */
801
/*@innerbreak@*/ break;
805
/* HTTP: look for "HTTP/1.1 123 ..." */
806
if (!strncmp(s, "HTTP", sizeof("HTTP")-1)) {
807
ctrl->contentLength = -1;
808
if ((e = strchr(s, '.')) != NULL) {
810
u->httpVersion = *e - '0';
811
if (u->httpVersion < 1 || u->httpVersion > 2)
812
ctrl->persist = u->httpVersion = 0;
816
if ((e = strchr(s, ' ')) != NULL) {
818
if (strchr("0123456789", *e))
819
strncpy(errorCode, e, 3);
825
/* HTTP: look for "token: ..." */
826
for (e = s; *e && !(*e == ' ' || *e == ':'); e++)
828
if (e > s && *e++ == ':') {
830
while (*e && *e == ' ') e++;
832
if (!strncmp(s, "Date:", ne)) {
834
if (!strncmp(s, "Server:", ne)) {
836
if (!strncmp(s, "Last-Modified:", ne)) {
838
if (!strncmp(s, "ETag:", ne)) {
841
if (!strncmp(s, "Accept-Ranges:", ne)) {
842
if (!strcmp(e, "bytes"))
844
if (!strcmp(e, "none"))
847
if (!strncmp(s, "Content-Length:", ne)) {
848
if (strchr("0123456789", *e))
849
ctrl->contentLength = atoi(e);
851
if (!strncmp(s, "Connection:", ne)) {
852
if (!strcmp(e, "close"))
857
if (!strncmp(s, "Content-Type:", ne)) {
859
if (!strncmp(s, "Transfer-Encoding:", ne)) {
860
if (!strcmp(e, "chunked"))
861
ctrl->wr_chunked = 1;
863
ctrl->wr_chunked = 0;
865
if (!strncmp(s, "Allow:", ne)) {
871
/* HTTP: look for "<TITLE>501 ... </TITLE>" */
872
if (!strncmp(s, "<TITLE>", sizeof("<TITLE>")-1))
873
s += sizeof("<TITLE>") - 1;
875
/* FTP: look for "123-" and/or "123 " */
876
if (strchr("0123456789", *s)) {
877
if (errorCode[0] != '\0') {
878
if (!strncmp(s, errorCode, sizeof("123")-1) && s[3] == ' ')
881
strncpy(errorCode, s, sizeof("123")-1);
889
if (moretodo && se > s) {
890
bufLength = se - s - 1;
892
memmove(buf, s, bufLength);
896
} while (moretodo && ec == 0);
899
if (ecp) *ecp = atoi(errorCode);
904
static int ftpCheckResponse(urlinfo u, /*@out@*/ char ** str)
905
/*@modifies u, *str, fileSystem @*/
911
rc = checkResponse(u, u->ctrl, &ec, str);
915
return FTPERR_FILE_NOT_FOUND;
916
/*@notreached@*/ break;
918
return FTPERR_NIC_ABORT_IN_PROGRESS;
919
/*@notreached@*/ break;
921
if (ec >= 400 && ec <= 599) {
922
return FTPERR_BAD_SERVER_RESPONSE;
929
static int ftpCommand(urlinfo u, char ** str, ...)
930
/*@modifies u, *str, fileSystem @*/
940
while ((s = va_arg(ap, const char *)) != NULL) {
944
len += sizeof("\r\n")-1;
947
t = te = alloca(len + 1);
950
while ((s = va_arg(ap, const char *)) != NULL) {
951
if (te > t) *te++ = ' ';
954
te = stpcpy(te, "\r\n");
958
fprintf(stderr, "-> %s", t);
959
if (fdWrite(u->ctrl, t, (te-t)) != (te-t))
960
return FTPERR_SERVER_IO_ERROR;
962
rc = ftpCheckResponse(u, str);
966
static int ftpLogin(urlinfo u)
967
/*@modifies u, fileSystem @*/
971
const char * password;
976
u->ctrl = fdLink(u->ctrl, "open ctrl");
978
if (((host = (u->proxyh ? u->proxyh : u->host)) == NULL)) {
979
rc = FTPERR_BAD_HOSTNAME;
983
if ((port = (u->proxyp > 0 ? u->proxyp : u->port)) < 0) port = IPPORT_FTP;
985
if ((user = (u->proxyu ? u->proxyu : u->user)) == NULL)
988
if ((password = u->password) == NULL) {
989
uid_t uid = getuid();
991
if (uid && (pw = getpwuid(uid)) != NULL) {
992
char *myp = alloca(strlen(pw->pw_name) + sizeof("@"));
993
strcpy(myp, pw->pw_name);
1001
if (fdFileno(u->ctrl) >= 0 && fdWritable(u->ctrl, 0) < 1)
1002
/*@-refcounttrans@*/ (void) fdClose(u->ctrl); /*@=refcounttrans@*/
1005
if (fdFileno(u->ctrl) < 0) {
1006
rc = tcpConnect(u->ctrl, host, port);
1011
if ((rc = ftpCheckResponse(u, NULL)))
1014
if ((rc = ftpCommand(u, NULL, "USER", user, NULL)))
1017
if ((rc = ftpCommand(u, NULL, "PASS", password, NULL)))
1020
if ((rc = ftpCommand(u, NULL, "TYPE", "I", NULL)))
1028
/*@-observertrans@*/
1029
fdSetSyserrno(u->ctrl, errno, ftpStrerror(rc));
1030
/*@=observertrans@*/
1032
if (fdFileno(u->ctrl) >= 0)
1033
/*@-refcounttrans@*/ (void) fdClose(u->ctrl); /*@=refcounttrans@*/
1040
int ftpReq(FD_t data, const char * ftpCmd, const char * ftpArg)
1042
urlinfo u = data->url;
1043
struct sockaddr_in dataAddress;
1052
return FTPERR_UNKNOWN; /* XXX W2DO? */
1054
cmdlen = strlen(ftpCmd) + (ftpArg ? 1+strlen(ftpArg) : 0) + sizeof("\r\n");
1055
chptr = cmd = alloca(cmdlen);
1056
chptr = stpcpy(chptr, ftpCmd);
1059
chptr = stpcpy(chptr, ftpArg);
1061
chptr = stpcpy(chptr, "\r\n");
1062
cmdlen = chptr - cmd;
1065
* Get the ftp version of the Content-Length.
1067
if (!strncmp(cmd, "RETR", 4)) {
1071
rc = ftpCommand(u, &passReply, "SIZE", ftpArg, NULL);
1074
if (sscanf(passReply, "%d %u", &rc, &cl) != 2) {
1075
rc = FTPERR_BAD_SERVER_RESPONSE;
1079
data->contentLength = cl;
1083
rc = ftpCommand(u, &passReply, "PASV", NULL);
1085
rc = FTPERR_PASSIVE_ERROR;
1090
while (*chptr && *chptr != '(') chptr++;
1091
if (*chptr != '(') return FTPERR_PASSIVE_ERROR;
1094
while (*chptr && *chptr != ')') chptr++;
1095
if (*chptr != ')') return FTPERR_PASSIVE_ERROR;
1098
while (*chptr && *chptr != ',') chptr--;
1099
if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
1101
while (*chptr && *chptr != ',') chptr--;
1102
if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
1105
/* now passReply points to the IP portion, and chptr points to the
1106
port number portion */
1109
memset(&dataAddress, 0, sizeof(dataAddress));
1110
dataAddress.sin_family = AF_INET;
1111
if (sscanf(chptr, "%d,%d", &i, &j) != 2) {
1112
rc = FTPERR_PASSIVE_ERROR;
1115
dataAddress.sin_port = htons((((unsigned)i) << 8) + j);
1119
while (*chptr++ != '\0') {
1120
if (*chptr == ',') *chptr = '.';
1123
if (!inet_aton(passReply, &dataAddress.sin_addr)) {
1124
rc = FTPERR_PASSIVE_ERROR;
1128
rc = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
1129
fdSetFdno(data, (rc >= 0 ? rc : -1));
1131
rc = FTPERR_FAILED_CONNECT;
1134
data = fdLink(data, "open data (ftpReq)");
1136
/* XXX setsockopt SO_LINGER */
1137
/* XXX setsockopt SO_KEEPALIVE */
1138
/* XXX setsockopt SO_TOS IPTOS_THROUGHPUT */
1140
while (connect(fdFileno(data), (struct sockaddr *) &dataAddress,
1141
sizeof(dataAddress)) < 0) {
1144
rc = FTPERR_FAILED_DATA_CONNECT;
1149
fprintf(stderr, "-> %s", cmd);
1150
if (fdWrite(u->ctrl, cmd, cmdlen) != cmdlen) {
1151
rc = FTPERR_SERVER_IO_ERROR;
1155
if ((rc = ftpCheckResponse(u, NULL))) {
1159
data->ftpFileDoneNeeded = 1;
1160
u->ctrl = fdLink(u->ctrl, "grab data (ftpReq)");
1161
u->ctrl = fdLink(u->ctrl, "open data (ftpReq)");
1165
/*@-observertrans@*/
1166
fdSetSyserrno(u->ctrl, errno, ftpStrerror(rc));
1167
/*@=observertrans@*/
1168
if (fdFileno(data) >= 0)
1169
/*@-refcounttrans@*/ (void) fdClose(data); /*@=refcounttrans@*/
1173
/*@null@*/ static rpmCallbackFunction urlNotify = NULL;
1174
/*@null@*/ static void * urlNotifyData = NULL;
1175
static int urlNotifyCount = -1;
1177
void urlSetCallback(rpmCallbackFunction notify, void *notifyData, int notifyCount) {
1179
urlNotifyData = notifyData;
1180
urlNotifyCount = (notifyCount >= 0) ? notifyCount : 4096;
1183
int ufdCopy(FD_t sfd, FD_t tfd)
1187
int itemsCopied = 0;
1192
(void)(*urlNotify) (NULL, RPMCALLBACK_INST_OPEN_FILE,
1193
0, 0, NULL, urlNotifyData);
1197
rc = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd);
1205
rc = Fwrite(buf, sizeof(buf[0]), itemsRead, tfd);
1208
if (rc != itemsRead) {
1209
rc = FTPERR_FILE_IO_ERROR;
1213
itemsCopied += itemsRead;
1214
if (urlNotify && urlNotifyCount > 0) {
1215
int n = itemsCopied/urlNotifyCount;
1216
if (n != notifier) {
1217
(void)(*urlNotify) (NULL, RPMCALLBACK_INST_PROGRESS,
1218
itemsCopied, 0, NULL, urlNotifyData);
1224
DBGIO(sfd, (stderr, "++ copied %d bytes: %s\n", itemsCopied,
1228
(void)(*urlNotify) (NULL, RPMCALLBACK_INST_OPEN_FILE,
1229
itemsCopied, itemsCopied, NULL, urlNotifyData);
1235
static int urlConnect(const char * url, /*@out@*/ urlinfo * uret)
1236
/*@modifies *uret, fileSystem @*/
1241
if (urlSplit(url, &u) < 0)
1244
if (u->urltype == URL_IS_FTP) {
1247
if ((fd = u->ctrl) == NULL) {
1248
fd = u->ctrl = fdNew("persist ctrl (urlConnect FTP)");
1249
fdSetIo(u->ctrl, ufdio);
1252
fd->rd_timeoutsecs = ftpTimeoutSecs;
1253
fd->contentLength = fd->bytesRemain = -1;
1254
fd->url = NULL; /* XXX FTP ctrl has not */
1255
fd->ftpFileDoneNeeded = 0;
1256
fd = fdLink(fd, "grab ctrl (urlConnect FTP)");
1258
if (fdFileno(u->ctrl) < 0) {
1259
rpmMessage(RPMMESS_DEBUG, _("logging into %s as %s, pw %s\n"),
1260
u->host ? u->host : "???",
1261
u->user ? u->user : "ftp",
1262
u->password ? u->password : "(username)");
1264
if ((rc = ftpLogin(u)) < 0) { /* XXX save ftpLogin error */
1265
u->ctrl = fdFree(fd, "grab ctrl (urlConnect FTP)");
1272
*uret = urlLink(u, "urlConnect");
1273
u = urlFree(u, "urlSplit (urlConnect)");
1278
int ufdGetFile(FD_t sfd, FD_t tfd)
1284
rc = ufdCopy(sfd, tfd);
1286
if (rc > 0) /* XXX ufdCopy now returns no. bytes copied */
1291
int ftpCmd(const char * cmd, const char * url, const char * arg2)
1297
if (urlConnect(url, &u) < 0)
1300
(void) urlPath(url, &path);
1302
rc = ftpCommand(u, NULL, cmd, path, arg2, NULL);
1303
u->ctrl = fdFree(u->ctrl, "grab ctrl (ftpCmd)");
1307
/* XXX these aren't worth the pain of including correctly */
1309
#define IAC 255 /* interpret as command: */
1312
#define IP 244 /* interrupt process--permanently */
1315
#define DM 242 /* data mark--for connect. cleaning */
1317
#if !defined(SHUT_RDWR)
1318
#define SHUT_RDWR 1+1
1321
static int ftpAbort(urlinfo u, FD_t data)
1322
/*@modifies u, data, fileSystem @*/
1324
static unsigned char ipbuf[3] = { IAC, IP, IAC };
1332
data->ftpFileDoneNeeded = 0;
1333
if (fdFileno(data) >= 0)
1334
u->ctrl = fdFree(u->ctrl, "open data (ftpAbort)");
1335
u->ctrl = fdFree(u->ctrl, "grab data (ftpAbort)");
1339
DBGIO(0, (stderr, "-> ABOR\n"));
1341
/*@-usereleased -compdef@*/
1342
if (send(fdFileno(ctrl), ipbuf, sizeof(ipbuf), MSG_OOB) != sizeof(ipbuf)) {
1343
/*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
1344
return FTPERR_SERVER_IO_ERROR;
1347
sprintf(u->buf, "%cABOR\r\n",(char) DM);
1348
if (fdWrite(ctrl, u->buf, 7) != 7) {
1349
/*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
1350
return FTPERR_SERVER_IO_ERROR;
1353
if (data && fdFileno(data) >= 0) {
1354
/* XXX shorten data drain time wait */
1355
tosecs = data->rd_timeoutsecs;
1356
data->rd_timeoutsecs = 10;
1357
if (fdReadable(data, data->rd_timeoutsecs) > 0) {
1358
while (timedRead(data, u->buf, u->bufAlloced) > 0)
1361
data->rd_timeoutsecs = tosecs;
1362
/* XXX ftp abort needs to close the data channel to receive status */
1363
(void) shutdown(fdFileno(data), SHUT_RDWR);
1364
(void) close(fdFileno(data));
1365
data->fps[0].fdno = -1; /* XXX WRONG but expedient */
1368
/* XXX shorten ctrl drain time wait */
1369
tosecs = u->ctrl->rd_timeoutsecs;
1370
u->ctrl->rd_timeoutsecs = 10;
1371
if ((rc = ftpCheckResponse(u, NULL)) == FTPERR_NIC_ABORT_IN_PROGRESS) {
1372
rc = ftpCheckResponse(u, NULL);
1374
rc = ftpCheckResponse(u, NULL);
1375
u->ctrl->rd_timeoutsecs = tosecs;
1378
/*@=usereleased =compdef@*/
1381
static int ftpFileDone(urlinfo u, FD_t data)
1382
/*@modifies u, data, fileSystem @*/
1387
assert(data->ftpFileDoneNeeded);
1389
if (data->ftpFileDoneNeeded) {
1390
data->ftpFileDoneNeeded = 0;
1391
u->ctrl = fdFree(u->ctrl, "open data (ftpFileDone)");
1392
u->ctrl = fdFree(u->ctrl, "grab data (ftpFileDone)");
1393
rc = ftpCheckResponse(u, NULL);
1398
static int httpResp(urlinfo u, FD_t ctrl, /*@out@*/ char ** str)
1399
/*@modifies ctrl, *str, fileSystem @*/
1405
rc = checkResponse(u, ctrl, &ec, str);
1407
if (_ftp_debug && !(rc == 0 && ec == 200))
1408
fprintf(stderr, "*** httpResp: rc %d ec %d\n", rc, ec);
1414
rc = FTPERR_FILE_NOT_FOUND;
1421
static int httpReq(FD_t ctrl, const char * httpCmd, const char * httpArg)
1422
/*@modifies ctrl, fileSystem @*/
1424
urlinfo u = ctrl->url;
1434
assert(ctrl != NULL);
1436
if (((host = (u->proxyh ? u->proxyh : u->host)) == NULL))
1437
return FTPERR_BAD_HOSTNAME;
1439
if ((port = (u->proxyp > 0 ? u->proxyp : u->port)) < 0) port = 80;
1440
path = (u->proxyh || u->proxyp > 0) ? u->url : httpArg;
1441
if (path == NULL) path = "";
1444
if (fdFileno(ctrl) >= 0 && (rc = fdWritable(ctrl, 0)) < 1) {
1445
/*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
1449
if (fdFileno(ctrl) < 0) {
1450
rc = tcpConnect(ctrl, host, port);
1453
ctrl = fdLink(ctrl, "open ctrl (httpReq)");
1458
User-Agent: rpm/3.0.4\r\n\
1460
Accept: text/plain\r\n\
1461
Transfer-Encoding: chunked\r\n\
1463
") + strlen(httpCmd) + strlen(path) + sizeof(VERSION) + strlen(host) + 20;
1468
if (!strcmp(httpCmd, "PUT")) {
1470
%s %s HTTP/1.%d\r\n\
1471
User-Agent: rpm/%s\r\n\
1473
Accept: text/plain\r\n\
1474
Transfer-Encoding: chunked\r\n\
1476
", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, host, port);
1479
%s %s HTTP/1.%d\r\n\
1480
User-Agent: rpm/%s\r\n\
1482
Accept: text/plain\r\n\
1484
", httpCmd, path, (u->httpVersion ? 1 : 0), VERSION, host, port);
1488
fprintf(stderr, "-> %s", req);
1491
if (fdWrite(ctrl, req, len) != len) {
1492
rc = FTPERR_SERVER_IO_ERROR;
1496
if (!strcmp(httpCmd, "PUT")) {
1497
ctrl->wr_chunked = 1;
1500
rc = httpResp(u, ctrl, NULL);
1503
if (!retrying) { /* not HTTP_OK */
1505
/*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
1512
ctrl = fdLink(ctrl, "open data (httpReq)");
1516
/*@-observertrans@*/
1517
fdSetSyserrno(ctrl, errno, ftpStrerror(rc));
1518
/*@=observertrans@*/
1520
if (fdFileno(ctrl) >= 0)
1521
/*@-refcounttrans@*/ (void) fdClose(ctrl); /*@=refcounttrans@*/
1526
/* XXX DYING: unused */
1527
void * ufdGetUrlinfo(FD_t fd)
1530
if (fd->url == NULL)
1532
return urlLink(fd->url, "ufdGetUrlinfo");
1535
/* =============================================================== */
1536
static ssize_t ufdRead(void * cookie, /*@out@*/ char * buf, size_t count)
1537
/*@modifies internalState, *buf, fileSystem @*/
1539
FD_t fd = c2f(cookie);
1543
*buf = '\0'; /* LCL: insistent bugger. */
1544
/* XXX preserve timedRead() behavior */
1545
if (fdGetIo(fd) == fdio) {
1547
int fdno = fdFileno(fd);
1548
(void) fstat(fdno, &sb);
1549
if (S_ISREG(sb.st_mode))
1550
return fdRead(fd, buf, count);
1554
assert(fd->rd_timeoutsecs >= 0);
1556
for (total = 0; total < count; total += bytesRead) {
1562
/* Is there data to read? */
1563
if (fd->bytesRemain == 0) return total; /* XXX simulate EOF */
1564
rc = fdReadable(fd, fd->rd_timeoutsecs);
1567
case -1: /* error */
1568
case 0: /* timeout */
1570
/*@notreached@*/ break;
1571
default: /* data to read */
1575
rc = fdRead(fd, buf + total, count - total);
1581
/*@notreached@*/ break;
1586
fprintf(stderr, "*** read: rc %d errno %d %s \"%s\"\n", rc, errno, strerror(errno), buf);
1588
/*@notreached@*/ break;
1589
} else if (rc == 0) {
1591
/*@notreached@*/ break;
1599
static ssize_t ufdWrite(void * cookie, const char * buf, size_t count)
1600
/*@modifies internalState, fileSystem @*/
1602
FD_t fd = c2f(cookie);
1607
if (fdGetIo(fd) == fdio) {
1609
(void) fstat(fdGetFdno(fd), &sb);
1610
if (S_ISREG(sb.st_mode))
1611
return fdWrite(fd, buf, count);
1617
for (total = 0; total < count; total += bytesWritten) {
1623
/* Is there room to write data? */
1624
if (fd->bytesRemain == 0) {
1625
fprintf(stderr, "*** ufdWrite fd %p WRITE PAST END OF CONTENT\n", fd);
1626
return total; /* XXX simulate EOF */
1628
rc = fdWritable(fd, 2); /* XXX configurable? */
1631
case -1: /* error */
1632
case 0: /* timeout */
1634
/*@notreached@*/ break;
1635
default: /* data to write */
1639
rc = fdWrite(fd, buf + total, count - total);
1645
/*@notreached@*/ break;
1650
fprintf(stderr, "*** write: rc %d errno %d %s \"%s\"\n", rc, errno, strerror(errno), buf);
1652
/*@notreached@*/ break;
1653
} else if (rc == 0) {
1655
/*@notreached@*/ break;
1663
static inline int ufdSeek(void * cookie, _libio_pos_t pos, int whence)
1664
/*@modifies internalState, fileSystem @*/
1666
FD_t fd = c2f(cookie);
1668
switch (fd->urlType) {
1669
case URL_IS_UNKNOWN:
1677
/*@notreached@*/ break;
1679
return fdSeek(cookie, pos, whence);
1682
/*@-usereleased@*/ /* LCL: fd handling is tricky here. */
1683
int ufdClose( /*@only@*/ void * cookie)
1685
FD_t fd = c2f(cookie);
1690
urlinfo u = fd->url;
1693
fd = u->data = fdFree(fd, "grab data (ufdClose persist)");
1695
fd = fdFree(fd, "grab data (ufdClose)");
1696
(void) urlFree(fd->url, "url (ufdClose)");
1698
u->ctrl = fdFree(u->ctrl, "grab ctrl (ufdClose)");
1700
if (u->urltype == URL_IS_FTP) {
1702
/* XXX if not using libio, lose the fp from fpio */
1704
/*@+voidabstract -nullpass@*/
1708
/*@=voidabstract =nullpass@*/
1712
* Normal FTP has 4 refs on the data fd:
1713
* "persist data (ufdOpen FTP)" rpmio.c:888
1714
* "grab data (ufdOpen FTP)" rpmio.c:892
1715
* "open data (ftpReq)" ftp.c:633
1716
* "fopencookie" rpmio.c:1507
1718
* Normal FTP has 5 refs on the ctrl fd:
1719
* "persist ctrl" url.c:176
1720
* "grab ctrl (urlConnect FTP)" rpmio.c:404
1721
* "open ctrl" ftp.c:504
1722
* "grab data (ftpReq)" ftp.c:661
1723
* "open data (ftpReq)" ftp.c:662
1725
if (fd->bytesRemain > 0) {
1726
if (fd->ftpFileDoneNeeded) {
1727
if (fdReadable(u->ctrl, 0) > 0)
1728
(void) ftpFileDone(u, fd);
1730
(void) ftpAbort(u, fd);
1734
/* XXX STOR et al require close before ftpFileDone */
1736
#if 0 /* XXX error exit from ufdOpen does not have this set */
1737
assert(fd->ftpFileDoneNeeded != 0);
1739
if (fd->ftpFileDoneNeeded)
1740
(void) ftpFileDone(u, fd);
1745
/* XXX Why not (u->urltype == URL_IS_HTTP) ??? */
1746
if (u->service != NULL && !strcmp(u->service, "http")) {
1747
if (fd->wr_chunked) {
1749
/* XXX HTTP PUT requires terminating 0 length chunk. */
1750
(void) fdWrite(fd, NULL, 0);
1752
/* XXX HTTP PUT requires terminating entity-header. */
1754
fprintf(stderr, "-> \r\n");
1755
(void) fdWrite(fd, "\r\n", sizeof("\r\n")-1);
1756
rc = httpResp(u, fd, NULL);
1760
fd = u->ctrl = fdFree(fd, "open data (ufdClose HTTP persist ctrl)");
1761
else if (fd == u->data)
1762
fd = u->data = fdFree(fd, "open data (ufdClose HTTP persist data)");
1764
fd = fdFree(fd, "open data (ufdClose HTTP)");
1767
* HTTP has 4 (or 5 if persistent malloc) refs on the fd:
1768
* "persist ctrl" url.c:177
1769
* "grab ctrl (ufdOpen HTTP)" rpmio.c:924
1770
* "grab data (ufdOpen HTTP)" rpmio.c:928
1771
* "open ctrl (httpReq)" ftp.c:382
1772
* "open data (httpReq)" ftp.c:435
1775
/* XXX if not using libio, lose the fp from fpio */
1777
/*@+voidabstract -nullpass@*/
1781
/*@=voidabstract =nullpass@*/
1784
if (fd->persist && u->httpVersion &&
1785
(fd == u->ctrl || fd == u->data) && fd->bytesRemain == 0) {
1786
fd->contentLength = fd->bytesRemain = -1;
1789
fd->contentLength = fd->bytesRemain = -1;
1797
/*@-nullstate@*/ /* FIX: u->{ctrl,data}->url undef after XurlLink. */
1798
/*@null@*/ FD_t ftpOpen(const char *url, /*@unused@*/ int flags,
1799
/*@unused@*/ mode_t mode, /*@out@*/ urlinfo *uret)
1800
/*@modifies *uret, fileSystem @*/
1805
#if 0 /* XXX makeTempFile() heartburn */
1806
assert(!(flags & O_RDWR));
1808
if (urlConnect(url, &u) < 0)
1811
if (u->data == NULL)
1812
u->data = fdNew("persist data (ftpOpen)");
1814
if (u->data->url == NULL)
1815
fd = fdLink(u->data, "grab data (ftpOpen persist data)");
1817
fd = fdNew("grab data (ftpOpen)");
1821
fd->ftpFileDoneNeeded = 0;
1822
fd->rd_timeoutsecs = ftpTimeoutSecs;
1823
fd->contentLength = fd->bytesRemain = -1;
1824
fd->url = urlLink(u, "url (ufdOpen FTP)");
1825
fd->urlType = URL_IS_FTP;
1835
/*@-nullstate@*/ /* FIX: u->{ctrl,data}->url undef after XurlLink. */
1836
static /*@null@*/ FD_t httpOpen(const char * url, /*@unused@*/ int flags,
1837
/*@unused@*/ mode_t mode, /*@out@*/ urlinfo * uret)
1838
/*@modifies *uret, fileSystem @*/
1843
#if 0 /* XXX makeTempFile() heartburn */
1844
assert(!(flags & O_RDWR));
1846
if (urlSplit(url, &u))
1849
if (u->ctrl == NULL)
1850
u->ctrl = fdNew("persist ctrl (httpOpen)");
1851
if (u->ctrl->nrefs > 2 && u->data == NULL)
1852
u->data = fdNew("persist data (httpOpen)");
1854
if (u->ctrl->url == NULL)
1855
fd = fdLink(u->ctrl, "grab ctrl (httpOpen persist ctrl)");
1856
else if (u->data->url == NULL)
1857
fd = fdLink(u->data, "grab ctrl (httpOpen persist data)");
1859
fd = fdNew("grab ctrl (httpOpen)");
1863
fd->ftpFileDoneNeeded = 0;
1864
fd->rd_timeoutsecs = httpTimeoutSecs;
1865
fd->contentLength = fd->bytesRemain = -1;
1866
fd->url = urlLink(u, "url (httpOpen)");
1867
fd = fdLink(fd, "grab data (httpOpen)");
1868
fd->urlType = URL_IS_HTTP;
1878
static /*@null@*/ FD_t ufdOpen(const char * url, int flags, mode_t mode)
1879
/*@modifies fileSystem @*/
1885
urltype urlType = urlPath(url, &path);
1888
fprintf(stderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mode);
1892
fd = ftpOpen(url, flags, mode, &u);
1893
if (fd == NULL || u == NULL)
1896
/* XXX W2DO? use STOU rather than STOR to prevent clobbering */
1897
cmd = ((flags & O_WRONLY)
1898
? ((flags & O_APPEND) ? "APPE" :
1899
((flags & O_CREAT) ? "STOR" : "STOR"))
1900
: ((flags & O_CREAT) ? "STOR" : "RETR"));
1901
u->openError = ftpReq(fd, cmd, path);
1902
if (u->openError < 0) {
1903
/* XXX make sure that we can exit through ufdClose */
1904
fd = fdLink(fd, "error data (ufdOpen FTP)");
1906
fd->bytesRemain = ((!strcmp(cmd, "RETR"))
1907
? fd->contentLength : -1);
1912
fd = httpOpen(url, flags, mode, &u);
1913
if (fd == NULL || u == NULL)
1916
cmd = ((flags & O_WRONLY)
1917
? ((flags & O_APPEND) ? "PUT" :
1918
((flags & O_CREAT) ? "PUT" : "PUT"))
1920
u->openError = httpReq(fd, cmd, path);
1921
if (u->openError < 0) {
1922
/* XXX make sure that we can exit through ufdClose */
1923
fd = fdLink(fd, "error ctrl (ufdOpen HTTP)");
1924
fd = fdLink(fd, "error data (ufdOpen HTTP)");
1926
fd->bytesRemain = ((!strcmp(cmd, "GET"))
1927
? fd->contentLength : -1);
1928
fd->wr_chunked = ((!strcmp(cmd, "PUT"))
1929
? fd->wr_chunked : 0);
1933
assert(!(flags & O_RDWR));
1934
fd = fdDup( ((flags & O_WRONLY) ? STDOUT_FILENO : STDIN_FILENO) );
1937
fd->rd_timeoutsecs = 600; /* XXX W2DO? 10 mins? */
1938
fd->contentLength = fd->bytesRemain = -1;
1942
case URL_IS_UNKNOWN:
1944
fd = fdOpen(path, flags, mode);
1947
fd->rd_timeoutsecs = 1;
1948
fd->contentLength = fd->bytesRemain = -1;
1953
if (fd == NULL) return NULL;
1954
fd->urlType = urlType;
1955
if (Fileno(fd) < 0) {
1956
(void) ufdClose(fd);
1959
DBGIO(fd, (stderr, "==>\tufdOpen(\"%s\",%x,0%o) %s\n", url, (unsigned)flags, (unsigned)mode, fdbg(fd)));
1963
static struct FDIO_s ufdio_s = {
1964
ufdRead, ufdWrite, ufdSeek, ufdClose, XfdLink, XfdFree, XfdNew, fdFileno,
1965
ufdOpen, NULL, fdGetFp, NULL, Mkdir, Chdir, Rmdir, Rename, Unlink
1967
FDIO_t ufdio = /*@-compmempass@*/ &ufdio_s /*@=compmempass@*/ ;
1969
/* =============================================================== */
1970
/* Support for GZIP library.
1976
static inline /*@dependent@*/ /*@null@*/ void * gzdFileno(FD_t fd)
1983
for (i = fd->nfps; i >= 0; i--) {
1984
FDSTACK_t * fps = &fd->fps[i];
1985
if (fps->io != gzdio)
1994
static /*@null@*/ FD_t gzdOpen(const char * path, const char * fmode)
1995
/*@modifies fileSystem @*/
1999
if ((gzfile = gzopen(path, fmode)) == NULL)
2001
fd = fdNew("open (gzdOpen)");
2002
fdPop(fd); fdPush(fd, gzdio, gzfile, -1);
2004
DBGIO(fd, (stderr, "==>\tgzdOpen(\"%s\", \"%s\") fd %p %s\n", path, fmode, (fd ? fd : NULL), fdbg(fd)));
2005
return fdLink(fd, "gzdOpen");
2008
static /*@null@*/ FD_t gzdFdopen(void * cookie, const char *fmode)
2009
/*@modifies internalState, fileSystem @*/
2011
FD_t fd = c2f(cookie);
2015
if (fmode == NULL) return NULL;
2016
fdno = fdFileno(fd);
2017
fdSetFdno(fd, -1); /* XXX skip the fdio close */
2018
if (fdno < 0) return NULL;
2019
gzfile = gzdopen(fdno, fmode);
2020
if (gzfile == NULL) return NULL;
2022
fdPush(fd, gzdio, gzfile, fdno); /* Push gzdio onto stack */
2024
return fdLink(fd, "gzdFdopen");
2027
static int gzdFlush(FD_t fd)
2028
/*@modifies fileSystem @*/
2030
return gzflush(gzdFileno(fd), Z_SYNC_FLUSH); /* XXX W2DO? */
2033
/* =============================================================== */
2034
/*@-mustmod@*/ /* LCL: *buf is modified */
2035
static ssize_t gzdRead(void * cookie, /*@out@*/ char * buf, size_t count)
2036
/*@modifies internalState, *buf, fileSystem @*/
2038
FD_t fd = c2f(cookie);
2042
if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
2043
gzfile = gzdFileno(fd);
2044
fdstat_enter(fd, FDSTAT_READ);
2045
rc = gzread(gzfile, buf, count);
2047
DBGIO(fd, (stderr, "==>\tgzdRead(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
2051
fd->errcookie = gzerror(gzfile, &zerror);
2052
if (zerror == Z_ERRNO) {
2053
fd->syserrno = errno;
2054
fd->errcookie = strerror(fd->syserrno);
2056
} else if (rc >= 0) {
2057
fdstat_exit(fd, FDSTAT_READ, rc);
2059
if (fd->digest && rc > 0) rpmDigestUpdate(fd->digest, buf, rc);
2066
static ssize_t gzdWrite(void * cookie, const char * buf, size_t count)
2067
/*@modifies internalState, fileSystem @*/
2069
FD_t fd = c2f(cookie);
2073
if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
2075
if (fd->digest && count > 0) rpmDigestUpdate(fd->digest, buf, count);
2077
gzfile = gzdFileno(fd);
2078
fdstat_enter(fd, FDSTAT_WRITE);
2079
rc = gzwrite(gzfile, (void *)buf, count);
2080
DBGIO(fd, (stderr, "==>\tgzdWrite(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
2083
fd->errcookie = gzerror(gzfile, &zerror);
2084
if (zerror == Z_ERRNO) {
2085
fd->syserrno = errno;
2086
fd->errcookie = strerror(fd->syserrno);
2088
} else if (rc > 0) {
2089
fdstat_exit(fd, FDSTAT_WRITE, rc);
2094
/* XXX zlib-1.0.4 has not */
2095
static inline int gzdSeek(void * cookie, _libio_pos_t pos, int whence)
2096
/*@modifies internalState, fileSystem @*/
2098
#ifdef USE_COOKIE_SEEK_POINTER
2099
_IO_off64_t p = *pos;
2105
FD_t fd = c2f(cookie);
2108
if (fd == NULL) return -2;
2109
assert(fd->bytesRemain == -1); /* XXX FIXME */
2110
gzfile = gzdFileno(fd);
2111
fdstat_enter(fd, FDSTAT_SEEK);
2112
rc = gzseek(gzfile, p, whence);
2113
DBGIO(fd, (stderr, "==>\tgzdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd)));
2116
fd->errcookie = gzerror(gzfile, &zerror);
2117
if (zerror == Z_ERRNO) {
2118
fd->syserrno = errno;
2119
fd->errcookie = strerror(fd->syserrno);
2121
} else if (rc >= 0) {
2122
fdstat_exit(fd, FDSTAT_SEEK, rc);
2130
static int gzdClose( /*@only@*/ void * cookie)
2131
/*@modifies internalState, fileSystem @*/
2133
FD_t fd = c2f(cookie);
2137
gzfile = gzdFileno(fd);
2139
if (gzfile == NULL) return -2;
2140
fdstat_enter(fd, FDSTAT_CLOSE);
2141
rc = gzclose(gzfile);
2143
/* XXX TODO: preserve fd if errors */
2146
DBGIO(fd, (stderr, "==>\tgzdClose(%p) zerror %d %s\n", cookie, rc, fdbg(fd)));
2148
fd->errcookie = gzerror(gzfile, &rc);
2149
if (rc == Z_ERRNO) {
2150
fd->syserrno = errno;
2151
fd->errcookie = strerror(fd->syserrno);
2153
} else if (rc >= 0) {
2154
fdstat_exit(fd, FDSTAT_CLOSE, rc);
2158
DBGIO(fd, (stderr, "==>\tgzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
2160
if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "GZDIO", stderr);
2162
fd = fdFree(fd, "open (gzdClose)");
2166
static struct FDIO_s gzdio_s = {
2167
gzdRead, gzdWrite, gzdSeek, gzdClose, XfdLink, XfdFree, XfdNew, fdFileno,
2168
NULL, gzdOpen, gzdFileno, gzdFlush, NULL, NULL, NULL, NULL, NULL
2170
FDIO_t gzdio = /*@-compmempass@*/ &gzdio_s /*@=compmempass@*/ ;
2172
#endif /* HAVE_ZLIB_H */
2174
/* =============================================================== */
2175
/* Support for BZIP2 library.
2182
# define bzopen BZ2_bzopen
2183
# define bzclose BZ2_bzclose
2184
# define bzdopen BZ2_bzdopen
2185
# define bzerror BZ2_bzerror
2186
# define bzflush BZ2_bzflush
2187
# define bzread BZ2_bzread
2188
# define bzwrite BZ2_bzwrite
2189
#endif /* HAVE_BZ2_1_0 */
2191
static inline /*@dependent@*/ void * bzdFileno(FD_t fd)
2198
for (i = fd->nfps; i >= 0; i--) {
2199
FDSTACK_t * fps = &fd->fps[i];
2200
if (fps->io != bzdio)
2209
static /*@null@*/ FD_t bzdOpen(const char * path, const char * mode)
2210
/*@modifies fileSystem @*/
2214
if ((bzfile = bzopen(path, mode)) == NULL)
2216
fd = fdNew("open (bzdOpen)");
2217
fdPop(fd); fdPush(fd, bzdio, bzfile, -1);
2218
return fdLink(fd, "bzdOpen");
2221
static /*@null@*/ FD_t bzdFdopen(void * cookie, const char * fmode)
2222
/*@modifies internalState, fileSystem @*/
2224
FD_t fd = c2f(cookie);
2228
if (fmode == NULL) return NULL;
2229
fdno = fdFileno(fd);
2230
fdSetFdno(fd, -1); /* XXX skip the fdio close */
2231
if (fdno < 0) return NULL;
2232
bzfile = bzdopen(fdno, fmode);
2233
if (bzfile == NULL) return NULL;
2235
fdPush(fd, bzdio, bzfile, fdno); /* Push bzdio onto stack */
2237
return fdLink(fd, "bzdFdopen");
2240
static int bzdFlush(FD_t fd)
2241
/*@modifies fileSystem @*/
2243
return bzflush(bzdFileno(fd));
2246
/* =============================================================== */
2247
/*@-mustmod@*/ /* LCL: *buf is modified */
2248
static ssize_t bzdRead(void * cookie, /*@out@*/ char * buf, size_t count)
2249
/*@modifies internalState, *buf, fileSystem @*/
2251
FD_t fd = c2f(cookie);
2255
if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
2256
bzfile = bzdFileno(fd);
2257
fdstat_enter(fd, FDSTAT_READ);
2260
rc = bzread(bzfile, buf, count);
2265
fd->errcookie = bzerror(bzfile, &zerror);
2266
} else if (rc >= 0) {
2267
fdstat_exit(fd, FDSTAT_READ, rc);
2269
if (fd->digest && rc > 0) rpmDigestUpdate(fd->digest, buf, rc);
2276
static ssize_t bzdWrite(void * cookie, const char * buf, size_t count)
2277
/*@modifies internalState, fileSystem @*/
2279
FD_t fd = c2f(cookie);
2283
if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
2285
if (fd->digest && count > 0) rpmDigestUpdate(fd->digest, buf, count);
2287
bzfile = bzdFileno(fd);
2288
fdstat_enter(fd, FDSTAT_WRITE);
2289
rc = bzwrite(bzfile, (void *)buf, count);
2292
fd->errcookie = bzerror(bzfile, &zerror);
2293
} else if (rc > 0) {
2294
fdstat_exit(fd, FDSTAT_WRITE, rc);
2299
static inline int bzdSeek(void * cookie, /*@unused@*/ _libio_pos_t pos,
2300
/*@unused@*/ int whence)
2303
FD_t fd = c2f(cookie);
2309
static int bzdClose( /*@only@*/ void * cookie)
2310
/*@modifies internalState, fileSystem @*/
2312
FD_t fd = c2f(cookie);
2316
bzfile = bzdFileno(fd);
2318
if (bzfile == NULL) return -2;
2319
fdstat_enter(fd, FDSTAT_CLOSE);
2321
rc = 0; /* XXX FIXME */
2323
/* XXX TODO: preserve fd if errors */
2328
fd->errcookie = bzerror(bzfile, &zerror);
2329
} else if (rc >= 0) {
2330
fdstat_exit(fd, FDSTAT_CLOSE, rc);
2334
DBGIO(fd, (stderr, "==>\tbzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
2336
if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "BZDIO", stderr);
2338
fd = fdFree(fd, "open (bzdClose)");
2342
static struct FDIO_s bzdio_s = {
2343
bzdRead, bzdWrite, bzdSeek, bzdClose, XfdLink, XfdFree, XfdNew, fdFileno,
2344
NULL, bzdOpen, bzdFileno, bzdFlush, NULL, NULL, NULL, NULL, NULL
2346
FDIO_t bzdio = /*@-compmempass@*/ &bzdio_s /*@=compmempass@*/ ;
2348
#endif /* HAVE_BZLIB_H */
2350
/* =============================================================== */
2351
/*@observer@*/ static const char * getFdErrstr (FD_t fd)
2354
const char *errstr = NULL;
2357
if (fdGetIo(fd) == gzdio) {
2358
errstr = fd->errcookie;
2360
#endif /* HAVE_ZLIB_H */
2363
if (fdGetIo(fd) == bzdio) {
2364
errstr = fd->errcookie;
2366
#endif /* HAVE_BZLIB_H */
2369
errstr = strerror(fd->syserrno);
2375
/* =============================================================== */
2377
const char *Fstrerror(FD_t fd)
2380
return strerror(errno);
2382
return getFdErrstr(fd);
2385
#define FDIOVEC(_fd, _vec) \
2386
((fdGetIo(_fd) && fdGetIo(_fd)->_vec) ? fdGetIo(_fd)->_vec : NULL)
2388
size_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd) {
2389
fdio_read_function_t *_read;
2394
*(char *)buf = '\0';
2396
DBGIO(fd, (stderr, "==> Fread(%p,%u,%u,%p) %s\n", buf, (unsigned)size, (unsigned)nmemb, (fd ? fd : NULL), fdbg(fd)));
2398
if (fdGetIo(fd) == fpio) {
2399
/*@+voidabstract -nullpass@*/
2400
rc = fread(buf, size, nmemb, fdGetFILE(fd));
2401
/*@=voidabstract =nullpass@*/
2406
_read = FDIOVEC(fd, read);
2409
rc = (_read ? (*_read) (fd, buf, size * nmemb) : -2);
2413
size_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
2415
fdio_write_function_t *_write;
2419
DBGIO(fd, (stderr, "==> Fwrite(%p,%u,%u,%p) %s\n", buf, (unsigned)size, (unsigned)nmemb, (fd ? fd : NULL), fdbg(fd)));
2421
if (fdGetIo(fd) == fpio) {
2422
/*@+voidabstract -nullpass@*/
2423
rc = fwrite(buf, size, nmemb, fdGetFILE(fd));
2424
/*@=voidabstract =nullpass@*/
2429
_write = FDIOVEC(fd, write);
2432
rc = (_write ? _write(fd, buf, size * nmemb) : -2);
2436
int Fseek(FD_t fd, _libio_off_t offset, int whence) {
2437
fdio_seek_function_t *_seek;
2438
#ifdef USE_COOKIE_SEEK_POINTER
2439
_IO_off64_t o64 = offset;
2440
_libio_pos_t pos = &o64;
2442
_libio_pos_t pos = offset;
2448
DBGIO(fd, (stderr, "==> Fseek(%p,%ld,%d) %s\n", fd, (long)offset, whence, fdbg(fd)));
2450
if (fdGetIo(fd) == fpio) {
2453
/*@+voidabstract -nullpass@*/
2455
rc = fseek(fp, offset, whence);
2456
/*@=voidabstract =nullpass@*/
2461
_seek = FDIOVEC(fd, seek);
2464
rc = (_seek ? _seek(fd, pos, whence) : -2);
2473
DBGIO(fd, (stderr, "==> Fclose(%p) %s\n", (fd ? fd : NULL), fdbg(fd)));
2475
fd = fdLink(fd, "Fclose");
2476
while (fd->nfps >= 0) {
2477
FDSTACK_t * fps = &fd->fps[fd->nfps];
2479
if (fps->io == fpio) {
2483
/*@+voidabstract -nullpass@*/
2486
/*@=voidabstract =nullpass@*/
2487
/* XXX persistent HTTP/1.1 returns the previously opened fp */
2488
if (fd->nfps > 0 && fpno == -1 &&
2489
fd->fps[fd->nfps-1].io == ufdio &&
2490
fd->fps[fd->nfps-1].fp == fp &&
2491
fd->fps[fd->nfps-1].fdno >= 0)
2496
/*@-refcounttrans@*/
2498
/*@=refcounttrans@*/
2500
if (fdGetFdno(fd) >= 0)
2513
fd = fdFree(fd, "fopencookie (Fclose)");
2519
fdio_close_function_t * _close = FDIOVEC(fd, close);
2529
fd = fdFree(fd, "Fclose");
2535
* Convert stdio fmode to open(2) mode, filtering out zlib/bzlib flags.
2536
* returns stdio[0] = '\0' on error.
2538
* gzopen: [0-9] is compession level
2539
* gzopen: 'f' is filtered (Z_FILTERED)
2540
* gzopen: 'h' is Huffman encoding (Z_HUFFMAN_ONLY)
2541
* bzopen: [1-9] is block size (modulo 100K)
2542
* bzopen: 's' is smallmode
2543
* HACK: '.' terminates, rest is type of I/O
2545
static inline void cvtfmode (const char *m,
2546
/*@out@*/ char *stdio, size_t nstdio,
2547
/*@out@*/ char *other, size_t nother,
2548
/*@out@*/ const char **end, /*@out@*/ int * f)
2549
/*@modifies *stdio, *other, *end, *f @*/
2556
flags |= O_WRONLY | O_CREAT | O_APPEND;
2557
if (--nstdio > 0) *stdio++ = *m;
2560
flags |= O_WRONLY | O_CREAT | O_TRUNC;
2561
if (--nstdio > 0) *stdio++ = *m;
2565
if (--nstdio > 0) *stdio++ = *m;
2570
/*@notreached@*/ break;
2574
while ((c = *m++) != '\0') {
2579
flags &= ~(O_RDONLY|O_WRONLY);
2581
if (--nstdio > 0) *stdio++ = c;
2584
if (--nstdio > 0) *stdio++ = c;
2588
if (--nstdio > 0) *stdio++ = c;
2591
if (--nother > 0) *other++ = c;
2597
*stdio = *other = '\0';
2599
*end = (*m != '\0' ? m : NULL);
2605
#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0
2606
/* XXX retrofit glibc-2.1.x typedef on glibc-2.0.x systems */
2607
typedef _IO_cookie_io_functions_t cookie_io_functions_t;
2611
FD_t Fdopen(FD_t ofd, const char *fmode)
2613
char stdio[20], other[20], zstdio[20];
2614
const char *end = NULL;
2619
fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
2625
cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL);
2626
if (stdio[0] == '\0')
2629
strncat(zstdio, stdio, sizeof(zstdio) - strlen(zstdio));
2630
strncat(zstdio, other, sizeof(zstdio) - strlen(zstdio));
2632
if (end == NULL && other[0] == '\0')
2633
/*@-refcounttrans -retalias@*/ return fd; /*@=refcounttrans =retalias@*/
2636
if (!strcmp(end, "fdio")) {
2638
} else if (!strcmp(end, "gzdio")) {
2640
fd = gzdFdopen(fd, zstdio);
2642
} else if (!strcmp(end, "bzdio")) {
2644
fd = bzdFdopen(fd, zstdio);
2646
} else if (!strcmp(end, "ufdio")) {
2648
} else if (!strcmp(end, "fadio")) {
2650
} else if (!strcmp(end, "fpio")) {
2653
int fdno = Fileno(fd);
2654
FILE * fp = fdopen(fdno, stdio);
2655
/*@+voidabstract -nullpass@*/
2657
fprintf(stderr, "*** Fdopen fpio fp %p\n", (void *)fp);
2658
/*@=voidabstract =nullpass@*/
2661
/* XXX gzdio/bzdio use fp for private data */
2663
if (fdGetFp(fd) == NULL)
2665
fdPush(fd, fpio, fp, fdno); /* Push fpio onto stack */
2669
} else if (other[0] != '\0') {
2670
for (end = other; *end && strchr("0123456789fh", *end); end++)
2674
fd = gzdFdopen(fd, zstdio);
2678
/*@-refcounttrans -retalias@*/ return fd; /*@=refcounttrans =retalias@*/
2684
{ cookie_io_functions_t ciof;
2685
ciof.read = iof->read;
2686
ciof.write = iof->write;
2687
ciof.seek = iof->seek;
2688
ciof.close = iof->close;
2689
fp = fopencookie(fd, stdio, ciof);
2690
DBGIO(fd, (stderr, "==> fopencookie(%p,\"%s\",*%p) returns fp %p\n", fd, stdio, iof, fp));
2695
/* XXX gzdio/bzdio use fp for private data */
2696
/*@+voidabstract -nullpass@*/
2697
if (fdGetFp(fd) == NULL)
2699
fdPush(fd, fpio, fp, fileno(fp)); /* Push fpio onto stack */
2700
/*@=voidabstract =nullpass@*/
2701
fd = fdLink(fd, "fopencookie");
2705
DBGIO(fd, (stderr, "==> Fdopen(%p,\"%s\") returns fd %p %s\n", ofd, fmode, (fd ? fd : NULL), fdbg(fd)));
2706
/*@-refcounttrans -retalias@*/ return fd; /*@=refcounttrans =retalias@*/
2709
FD_t Fopen(const char *path, const char *fmode)
2711
char stdio[20], other[20];
2712
const char *end = NULL;
2713
mode_t perms = 0666;
2717
if (path == NULL || fmode == NULL)
2720
cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, &flags);
2721
if (stdio[0] == '\0')
2724
if (end == NULL || !strcmp(end, "fdio")) {
2726
fprintf(stderr, "*** Fopen fdio path %s fmode %s\n", path, fmode);
2727
fd = fdOpen(path, flags, perms);
2728
if (fdFileno(fd) < 0) {
2729
if (fd) (void) fdClose(fd);
2732
} else if (!strcmp(end, "fadio")) {
2734
fprintf(stderr, "*** Fopen fadio path %s fmode %s\n", path, fmode);
2735
fd = fadio->_open(path, flags, perms);
2736
if (fdFileno(fd) < 0) {
2737
/*@-refcounttrans@*/ (void) fdClose(fd); /*@=refcounttrans@*/
2745
/* XXX gzdio and bzdio here too */
2747
switch (urlIsURL(path)) {
2754
case URL_IS_UNKNOWN:
2756
fprintf(stderr, "*** Fopen ufdio path %s fmode %s\n", path, fmode);
2757
fd = ufdOpen(path, flags, perms);
2758
if (fd == NULL || fdFileno(fd) < 0)
2763
fprintf(stderr, "*** Fopen WTFO path %s fmode %s\n", path, fmode);
2765
/*@notreached@*/ break;
2768
/* XXX persistent HTTP/1.1 returns the previously opened fp */
2769
if (isHTTP && ((fp = fdGetFp(fd)) != NULL) && ((fdno = fdGetFdno(fd)) >= 0)) {
2771
fdPush(fd, fpio, fp, fileno(fp)); /* Push fpio onto stack */
2778
fd = Fdopen(fd, fmode);
2785
if (fd == NULL) return -1;
2786
if (fdGetIo(fd) == fpio)
2787
/*@+voidabstract -nullpass@*/
2788
return fflush(fdGetFILE(fd));
2789
/*@=voidabstract =nullpass@*/
2792
if (vh && fdGetIo(fd) == gzdio)
2793
return gzdFlush(vh);
2795
if (vh && fdGetIo(fd) == bzdio)
2796
return bzdFlush(vh);
2806
if (fd == NULL) return -1;
2807
for (i = fd->nfps; rc == 0 && i >= 0; i--) {
2808
FDSTACK_t * fps = &fd->fps[i];
2811
if (fps->io == fpio) {
2812
/*@+voidabstract -nullpass@*/
2813
ec = ferror(fdGetFILE(fd));
2814
/*@=voidabstract =nullpass@*/
2815
} else if (fps->io == gzdio) {
2816
ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
2817
i--; /* XXX fdio under gzdio always has fdno == -1 */
2819
} else if (fps->io == bzdio) {
2820
ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
2821
i--; /* XXX fdio under bzdio always has fdno == -1 */
2824
/* XXX need to check ufdio/gzdio/bzdio/fdio errors correctly. */
2825
ec = (fdFileno(fd) < 0 ? -1 : 0);
2831
DBGIO(fd, (stderr, "==> Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd)));
2839
for (i = fd->nfps ; rc == -1 && i >= 0; i--) {
2840
rc = fd->fps[i].fdno;
2842
DBGIO(fd, (stderr, "==> Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, fdbg(fd)));
2846
/* XXX this is naive */
2847
int Fcntl(FD_t fd, int op, void *lip)
2849
return fcntl(Fileno(fd), op, lip);
2852
/* =============================================================== */
2853
/* Helper routines that may be generally useful.
2856
/* XXX falloc.c: analogues to pread(3)/pwrite(3). */
2857
ssize_t Pread(FD_t fd, void * buf, size_t count, _libio_off_t offset)
2859
if (Fseek(fd, offset, SEEK_SET) < 0)
2861
return Fread(buf, sizeof(char), count, fd);
2864
ssize_t Pwrite(FD_t fd, const void * buf, size_t count, _libio_off_t offset)
2866
if (Fseek(fd, offset, SEEK_SET) < 0)
2868
return Fwrite(buf, sizeof(char), count, fd);
2871
static struct FDIO_s fpio_s = {
2872
ufdRead, ufdWrite, fdSeek, ufdClose, XfdLink, XfdFree, XfdNew, fdFileno,
2873
ufdOpen, NULL, fdGetFp, NULL, Mkdir, Chdir, Rmdir, Rename, Unlink
2875
FDIO_t fpio = /*@-compmempass@*/ &fpio_s /*@=compmempass@*/ ;