svn commit: r231247 - in stable/9: lib/libfetch usr.bin/fetch
Baptiste Daroussin
bapt at FreeBSD.org
Thu Feb 9 06:48:05 UTC 2012
Author: bapt
Date: Thu Feb 9 06:48:04 2012
New Revision: 231247
URL: http://svn.freebsd.org/changeset/base/231247
Log:
MFH r230307: fix SIGINFO-related data corruption bug
Approved by: des (mentor)
Modified:
stable/9/lib/libfetch/common.c
stable/9/lib/libfetch/common.h
stable/9/lib/libfetch/http.c
stable/9/usr.bin/fetch/fetch.c
Directory Properties:
stable/9/lib/libfetch/ (props changed)
stable/9/usr.bin/fetch/ (props changed)
Modified: stable/9/lib/libfetch/common.c
==============================================================================
--- stable/9/lib/libfetch/common.c Thu Feb 9 05:43:50 2012 (r231246)
+++ stable/9/lib/libfetch/common.c Thu Feb 9 06:48:04 2012 (r231247)
@@ -404,6 +404,34 @@ fetch_ssl_read(SSL *ssl, char *buf, size
}
#endif
+/*
+ * Cache some data that was read from a socket but cannot be immediately
+ * returned because of an interrupted system call.
+ */
+static int
+fetch_cache_data(conn_t *conn, char *src, size_t nbytes)
+{
+ char *tmp;
+
+ if (conn->cache.size < nbytes) {
+ tmp = realloc(conn->cache.buf, nbytes);
+ if (tmp == NULL) {
+ errno = ENOMEM;
+ fetch_syserr();
+ return (-1);
+ }
+ conn->cache.buf = tmp;
+ conn->cache.size = nbytes;
+ }
+
+ memcpy(conn->cache.buf, src, nbytes);
+ conn->cache.len = nbytes;
+ conn->cache.pos = 0;
+
+ return (0);
+}
+
+
static ssize_t
fetch_socket_read(int sd, char *buf, size_t len)
{
@@ -429,6 +457,7 @@ fetch_read(conn_t *conn, char *buf, size
fd_set readfds;
ssize_t rlen, total;
int r;
+ char *start;
if (fetchTimeout) {
FD_ZERO(&readfds);
@@ -437,6 +466,24 @@ fetch_read(conn_t *conn, char *buf, size
}
total = 0;
+ start = buf;
+
+ if (conn->cache.len > 0) {
+ /*
+ * The last invocation of fetch_read was interrupted by a
+ * signal after some data had been read from the socket. Copy
+ * the cached data into the supplied buffer before trying to
+ * read from the socket again.
+ */
+ total = (conn->cache.len < len) ? conn->cache.len : len;
+ memcpy(buf, conn->cache.buf, total);
+
+ conn->cache.len -= total;
+ conn->cache.pos += total;
+ len -= total;
+ buf+= total;
+ }
+
while (len > 0) {
/*
* The socket is non-blocking. Instead of the canonical
@@ -472,6 +519,8 @@ fetch_read(conn_t *conn, char *buf, size
total += rlen;
continue;
} else if (rlen == FETCH_READ_ERROR) {
+ if (errno == EINTR)
+ fetch_cache_data(conn, start, total);
return (-1);
}
// assert(rlen == FETCH_READ_WAIT);
@@ -492,8 +541,12 @@ fetch_read(conn_t *conn, char *buf, size
errno = 0;
r = select(conn->sd + 1, &readfds, NULL, NULL, &delta);
if (r == -1) {
- if (errno == EINTR && fetchRestartCalls)
- continue;
+ if (errno == EINTR) {
+ if (fetchRestartCalls)
+ continue;
+ /* Save anything that was read. */
+ fetch_cache_data(conn, start, total);
+ }
fetch_syserr();
return (-1);
}
@@ -677,6 +730,7 @@ fetch_close(conn_t *conn)
if (--conn->ref > 0)
return (0);
ret = close(conn->sd);
+ free(conn->cache.buf);
free(conn->buf);
free(conn);
return (ret);
Modified: stable/9/lib/libfetch/common.h
==============================================================================
--- stable/9/lib/libfetch/common.h Thu Feb 9 05:43:50 2012 (r231246)
+++ stable/9/lib/libfetch/common.h Thu Feb 9 06:48:04 2012 (r231247)
@@ -52,6 +52,13 @@ struct fetchconn {
size_t bufsize; /* buffer size */
size_t buflen; /* length of buffer contents */
int err; /* last protocol reply code */
+ struct { /* data cached after an interrupted
+ read */
+ char *buf;
+ size_t size;
+ size_t pos;
+ size_t len;
+ } cache;
#ifdef WITH_SSL
SSL *ssl; /* SSL handle */
SSL_CTX *ssl_ctx; /* SSL context */
Modified: stable/9/lib/libfetch/http.c
==============================================================================
--- stable/9/lib/libfetch/http.c Thu Feb 9 05:43:50 2012 (r231246)
+++ stable/9/lib/libfetch/http.c Thu Feb 9 06:48:04 2012 (r231247)
@@ -196,6 +196,8 @@ http_growbuf(struct httpio *io, size_t l
static int
http_fillbuf(struct httpio *io, size_t len)
{
+ ssize_t nbytes;
+
if (io->error)
return (-1);
if (io->eof)
@@ -204,10 +206,11 @@ http_fillbuf(struct httpio *io, size_t l
if (io->chunked == 0) {
if (http_growbuf(io, len) == -1)
return (-1);
- if ((io->buflen = fetch_read(io->conn, io->buf, len)) == -1) {
- io->error = 1;
+ if ((nbytes = fetch_read(io->conn, io->buf, len)) == -1) {
+ io->error = errno;
return (-1);
}
+ io->buflen = nbytes;
io->bufpos = 0;
return (io->buflen);
}
@@ -227,10 +230,11 @@ http_fillbuf(struct httpio *io, size_t l
len = io->chunksize;
if (http_growbuf(io, len) == -1)
return (-1);
- if ((io->buflen = fetch_read(io->conn, io->buf, len)) == -1) {
- io->error = 1;
+ if ((nbytes = fetch_read(io->conn, io->buf, len)) == -1) {
+ io->error = errno;
return (-1);
}
+ io->buflen = nbytes;
io->chunksize -= io->buflen;
if (io->chunksize == 0) {
@@ -272,8 +276,11 @@ http_readfn(void *v, char *buf, int len)
io->bufpos += l;
}
- if (!pos && io->error)
+ if (!pos && io->error) {
+ if (io->error == EINTR)
+ io->error = 0;
return (-1);
+ }
return (pos);
}
Modified: stable/9/usr.bin/fetch/fetch.c
==============================================================================
--- stable/9/usr.bin/fetch/fetch.c Thu Feb 9 05:43:50 2012 (r231246)
+++ stable/9/usr.bin/fetch/fetch.c Thu Feb 9 06:48:04 2012 (r231247)
@@ -317,7 +317,7 @@ fetch(char *URL, const char *path)
struct stat sb, nsb;
struct xferstat xs;
FILE *f, *of;
- size_t size, wr;
+ size_t size, readcnt, wr;
off_t count;
char flags[8];
const char *slash;
@@ -636,21 +636,26 @@ fetch(char *URL, const char *path)
stat_end(&xs);
siginfo = 0;
}
- if ((size = fread(buf, 1, size, f)) == 0) {
+
+ if (size == 0)
+ break;
+
+ if ((readcnt = fread(buf, 1, size, f)) < size) {
if (ferror(f) && errno == EINTR && !sigint)
clearerr(f);
- else
+ else if (readcnt == 0)
break;
}
- stat_update(&xs, count += size);
- for (ptr = buf; size > 0; ptr += wr, size -= wr)
- if ((wr = fwrite(ptr, 1, size, of)) < size) {
+
+ stat_update(&xs, count += readcnt);
+ for (ptr = buf; readcnt > 0; ptr += wr, readcnt -= wr)
+ if ((wr = fwrite(ptr, 1, readcnt, of)) < readcnt) {
if (ferror(of) && errno == EINTR && !sigint)
clearerr(of);
else
break;
}
- if (size != 0)
+ if (readcnt != 0)
break;
}
if (!sigalrm)
More information about the svn-src-stable-9
mailing list