diff options
author | des <des@FreeBSD.org> | 2012-01-18 15:13:21 +0000 |
---|---|---|
committer | des <des@FreeBSD.org> | 2012-01-18 15:13:21 +0000 |
commit | 939a66af62dc031d0ca35b5e7b1410f8aedc1d7c (patch) | |
tree | a2005365ba56694fd925cd9d8f2687ea003a376f /usr.bin/fetch | |
parent | 7972e45b2052402d891e3dd144472547dac25ec6 (diff) | |
download | FreeBSD-src-939a66af62dc031d0ca35b5e7b1410f8aedc1d7c.zip FreeBSD-src-939a66af62dc031d0ca35b5e7b1410f8aedc1d7c.tar.gz |
Fix two issues related to the use of SIGINFO in fetch(1) to display
progress information. The first is that fetch_read() (used in the HTTP
code but not the FTP code) can enter an infinite loop if it has previously
been interrupted by a signal. The second is that when it is interrupted,
fetch_read() will discard any data it may have read up to that point.
Luckily, both bugs are extremely timing-sensitive and therefore difficult
to trigger.
PR: bin/153240
Submitted by: Mark <markjdb@gmail.com>
MFC after: 3 weeks
Diffstat (limited to 'usr.bin/fetch')
-rw-r--r-- | usr.bin/fetch/fetch.c | 19 |
1 files changed, 12 insertions, 7 deletions
diff --git a/usr.bin/fetch/fetch.c b/usr.bin/fetch/fetch.c index 8d26671..e8b7318 100644 --- a/usr.bin/fetch/fetch.c +++ b/usr.bin/fetch/fetch.c @@ -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) |