diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-02-11 21:42:00 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-02-11 21:42:00 +0100 |
commit | 8766a791e847fdf1f3f00222f18c18833f40abda (patch) | |
tree | c62762ba0d933cb38e25b8c0f00686841b9cf63f /networking/wget.c | |
parent | ab8d00d64fc23602875952c08c030f05f206686c (diff) | |
download | busybox-w32-8766a791e847fdf1f3f00222f18c18833f40abda.tar.gz busybox-w32-8766a791e847fdf1f3f00222f18c18833f40abda.tar.bz2 busybox-w32-8766a791e847fdf1f3f00222f18c18833f40abda.zip |
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/wget.c')
-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 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) | |||
487 | rdsz = (unsigned)G.content_len; | 487 | rdsz = (unsigned)G.content_len; |
488 | } | 488 | } |
489 | } | 489 | } |
490 | |||
490 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT | 491 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT |
491 | # if ENABLE_FEATURE_WGET_TIMEOUT | 492 | # if ENABLE_FEATURE_WGET_TIMEOUT |
492 | second_cnt = G.timeout_seconds; | 493 | second_cnt = G.timeout_seconds; |
@@ -497,22 +498,41 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) | |||
497 | # if ENABLE_FEATURE_WGET_TIMEOUT | 498 | # if ENABLE_FEATURE_WGET_TIMEOUT |
498 | if (second_cnt != 0 && --second_cnt == 0) { | 499 | if (second_cnt != 0 && --second_cnt == 0) { |
499 | progress_meter(PROGRESS_END); | 500 | progress_meter(PROGRESS_END); |
500 | bb_perror_msg_and_die("download timed out"); | 501 | bb_error_msg_and_die("download timed out"); |
501 | } | 502 | } |
502 | # endif | 503 | # endif |
503 | /* Needed for "stalled" indicator */ | 504 | /* Needed for "stalled" indicator */ |
504 | progress_meter(PROGRESS_BUMP); | 505 | progress_meter(PROGRESS_BUMP); |
505 | } | 506 | } |
506 | #endif | 507 | #endif |
508 | /* fread internally uses read loop, which in our case | ||
509 | * is usually exited when we get EAGAIN. | ||
510 | * In this case, libc sets error marker on the stream. | ||
511 | * Need to clear it before next fread to avoid possible | ||
512 | * rare false positive ferror below. Rare because usually | ||
513 | * fread gets more than zero bytes, and we don't fall | ||
514 | * into if (n <= 0) ... | ||
515 | */ | ||
516 | clearerr(dfp); | ||
517 | errno = 0; | ||
507 | n = fread(G.wget_buf, 1, rdsz, dfp); | 518 | n = fread(G.wget_buf, 1, rdsz, dfp); |
519 | /* man fread: | ||
520 | * If error occurs, or EOF is reached, the return value | ||
521 | * is a short item count (or zero). | ||
522 | * fread does not distinguish between EOF and error. | ||
523 | */ | ||
508 | if (n <= 0) { | 524 | if (n <= 0) { |
509 | if (ferror(dfp)) { | 525 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT |
510 | /* perror will not work: ferror doesn't set errno */ | 526 | if (errno == EAGAIN) /* poll lied, there is no data? */ |
511 | bb_error_msg_and_die(bb_msg_read_error); | 527 | continue; /* yes */ |
512 | } | 528 | #endif |
513 | break; | 529 | if (ferror(dfp)) |
530 | bb_perror_msg_and_die(bb_msg_read_error); | ||
531 | break; /* EOF, not error */ | ||
514 | } | 532 | } |
533 | |||
515 | xwrite(output_fd, G.wget_buf, n); | 534 | xwrite(output_fd, G.wget_buf, n); |
535 | |||
516 | #if ENABLE_FEATURE_WGET_STATUSBAR | 536 | #if ENABLE_FEATURE_WGET_STATUSBAR |
517 | G.transferred += n; | 537 | G.transferred += n; |
518 | progress_meter(PROGRESS_BUMP); | 538 | progress_meter(PROGRESS_BUMP); |