diff options
author | Denys Vlasenko | 2011-02-11 21:42:00 +0100 |
---|---|---|
committer | Denys Vlasenko | 2011-02-11 21:42:00 +0100 |
commit | 8766a791e847fdf1f3f00222f18c18833f40abda (patch) | |
tree | c62762ba0d933cb38e25b8c0f00686841b9cf63f | |
parent | ab8d00d64fc23602875952c08c030f05f206686c (diff) | |
download | busybox-8766a791e847fdf1f3f00222f18c18833f40abda.zip busybox-8766a791e847fdf1f3f00222f18c18833f40abda.tar.gz |
wget: correctly handle rare case when we get EAGAIN _on first_ read
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/wget.c | 32 |
1 files changed, 26 insertions, 6 deletions
diff --git a/networking/wget.c b/networking/wget.c index f2d7daf..4868864 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); |