summaryrefslogtreecommitdiffhomepage
path: root/networking
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2011-02-11 21:42:00 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2011-02-11 21:42:00 +0100
commit8766a791e847fdf1f3f00222f18c18833f40abda (patch)
treec62762ba0d933cb38e25b8c0f00686841b9cf63f /networking
parentab8d00d64fc23602875952c08c030f05f206686c (diff)
wget: correctly handle rare case when we get EAGAIN _on first_ read
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking')
-rw-r--r--networking/wget.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/networking/wget.c b/networking/wget.c
index f2d7daf2f..48688640a 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -487,6 +487,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
rdsz = (unsigned)G.content_len;
}
}
+
#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
# if ENABLE_FEATURE_WGET_TIMEOUT
second_cnt = G.timeout_seconds;
@@ -497,22 +498,41 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
# if ENABLE_FEATURE_WGET_TIMEOUT
if (second_cnt != 0 && --second_cnt == 0) {
progress_meter(PROGRESS_END);
- bb_perror_msg_and_die("download timed out");
+ bb_error_msg_and_die("download timed out");
}
# endif
/* Needed for "stalled" indicator */
progress_meter(PROGRESS_BUMP);
}
#endif
+ /* fread internally uses read loop, which in our case
+ * is usually exited when we get EAGAIN.
+ * In this case, libc sets error marker on the stream.
+ * Need to clear it before next fread to avoid possible
+ * rare false positive ferror below. Rare because usually
+ * fread gets more than zero bytes, and we don't fall
+ * into if (n <= 0) ...
+ */
+ clearerr(dfp);
+ errno = 0;
n = fread(G.wget_buf, 1, rdsz, dfp);
+ /* man fread:
+ * If error occurs, or EOF is reached, the return value
+ * is a short item count (or zero).
+ * fread does not distinguish between EOF and error.
+ */
if (n <= 0) {
- if (ferror(dfp)) {
- /* perror will not work: ferror doesn't set errno */
- bb_error_msg_and_die(bb_msg_read_error);
- }
- break;
+#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
+ if (errno == EAGAIN) /* poll lied, there is no data? */
+ continue; /* yes */
+#endif
+ if (ferror(dfp))
+ bb_perror_msg_and_die(bb_msg_read_error);
+ break; /* EOF, not error */
}
+
xwrite(output_fd, G.wget_buf, n);
+
#if ENABLE_FEATURE_WGET_STATUSBAR
G.transferred += n;
progress_meter(PROGRESS_BUMP);