From owner-svn-src-stable@FreeBSD.ORG Thu Feb 9 06:50:44 2012 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 86B86106564A; Thu, 9 Feb 2012 06:50:44 +0000 (UTC) (envelope-from bapt@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 6FEAA8FC0C; Thu, 9 Feb 2012 06:50:44 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q196oiVc085922; Thu, 9 Feb 2012 06:50:44 GMT (envelope-from bapt@svn.freebsd.org) Received: (from bapt@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q196oids085917; Thu, 9 Feb 2012 06:50:44 GMT (envelope-from bapt@svn.freebsd.org) Message-Id: <201202090650.q196oids085917@svn.freebsd.org> From: Baptiste Daroussin Date: Thu, 9 Feb 2012 06:50:44 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r231248 - in stable/8: lib/libfetch usr.bin/fetch X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 09 Feb 2012 06:50:44 -0000 Author: bapt Date: Thu Feb 9 06:50:43 2012 New Revision: 231248 URL: http://svn.freebsd.org/changeset/base/231248 Log: MFH r230307: fix SIGINFO-related data corruption bug Approved by: des (mentor) Modified: stable/8/lib/libfetch/common.c stable/8/lib/libfetch/common.h stable/8/lib/libfetch/http.c stable/8/usr.bin/fetch/fetch.c Directory Properties: stable/8/lib/libfetch/ (props changed) stable/8/usr.bin/fetch/ (props changed) Modified: stable/8/lib/libfetch/common.c ============================================================================== --- stable/8/lib/libfetch/common.c Thu Feb 9 06:48:04 2012 (r231247) +++ stable/8/lib/libfetch/common.c Thu Feb 9 06:50:43 2012 (r231248) @@ -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/8/lib/libfetch/common.h ============================================================================== --- stable/8/lib/libfetch/common.h Thu Feb 9 06:48:04 2012 (r231247) +++ stable/8/lib/libfetch/common.h Thu Feb 9 06:50:43 2012 (r231248) @@ -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/8/lib/libfetch/http.c ============================================================================== --- stable/8/lib/libfetch/http.c Thu Feb 9 06:48:04 2012 (r231247) +++ stable/8/lib/libfetch/http.c Thu Feb 9 06:50:43 2012 (r231248) @@ -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/8/usr.bin/fetch/fetch.c ============================================================================== --- stable/8/usr.bin/fetch/fetch.c Thu Feb 9 06:48:04 2012 (r231247) +++ stable/8/usr.bin/fetch/fetch.c Thu Feb 9 06:50:43 2012 (r231248) @@ -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)