From 8766a791e847fdf1f3f00222f18c18833f40abda Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 11 Feb 2011 21:42:00 +0100 Subject: wget: correctly handle rare case when we get EAGAIN _on first_ read Signed-off-by: Denys Vlasenko --- networking/wget.c | 32 ++++++++++++++++++++++++++------ 1 file 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); -- cgit v1.2.3