aboutsummaryrefslogtreecommitdiff
path: root/networking/wget.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2012-09-03 12:49:30 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2012-09-03 12:49:30 +0200
commitb7812ce0f7ee230330e18de3ac447b700311ab84 (patch)
tree12919e12982f3ef7a5562ca504417742c170ea7a /networking/wget.c
parent168f87c531d04be06e16f04144c61ba289e0c0ec (diff)
downloadbusybox-w32-b7812ce0f7ee230330e18de3ac447b700311ab84.tar.gz
busybox-w32-b7812ce0f7ee230330e18de3ac447b700311ab84.tar.bz2
busybox-w32-b7812ce0f7ee230330e18de3ac447b700311ab84.zip
wget: reorder fread and poll: poll only if fread returns EAGAIN. Closes 5426
function old new delta retrieve_file_data 451 427 -24 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/wget.c')
-rw-r--r--networking/wget.c114
1 files changed, 62 insertions, 52 deletions
diff --git a/networking/wget.c b/networking/wget.c
index 3416636ae..4eafebe40 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -444,13 +444,10 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
444{ 444{
445#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT 445#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
446# if ENABLE_FEATURE_WGET_TIMEOUT 446# if ENABLE_FEATURE_WGET_TIMEOUT
447 unsigned second_cnt; 447 unsigned second_cnt = G.timeout_seconds;
448# endif 448# endif
449 struct pollfd polldata; 449 struct pollfd polldata;
450 450
451# if ENABLE_FEATURE_WGET_TIMEOUT
452 second_cnt = G.timeout_seconds;
453# endif
454 polldata.fd = fileno(dfp); 451 polldata.fd = fileno(dfp);
455 polldata.events = POLLIN | POLLPRI; 452 polldata.events = POLLIN | POLLPRI;
456#endif 453#endif
@@ -468,7 +465,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
468 * which messes up progress bar and/or timeout logic. 465 * which messes up progress bar and/or timeout logic.
469 * Because of nonblocking I/O, we need to dance 466 * Because of nonblocking I/O, we need to dance
470 * very carefully around EAGAIN. See explanation at 467 * very carefully around EAGAIN. See explanation at
471 * clearerr() call. 468 * clearerr() calls.
472 */ 469 */
473 ndelay_on(polldata.fd); 470 ndelay_on(polldata.fd);
474#endif 471#endif
@@ -476,34 +473,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
476 int n; 473 int n;
477 unsigned rdsz; 474 unsigned rdsz;
478 475
479 rdsz = sizeof(G.wget_buf);
480 if (G.got_clen) {
481 if (G.content_len < (off_t)sizeof(G.wget_buf)) {
482 if ((int)G.content_len <= 0)
483 break;
484 rdsz = (unsigned)G.content_len;
485 }
486 }
487
488#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT 476#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
489 if (safe_poll(&polldata, 1, 1000) == 0) {
490# if ENABLE_FEATURE_WGET_TIMEOUT
491 if (second_cnt != 0 && --second_cnt == 0) {
492 progress_meter(PROGRESS_END);
493 bb_error_msg_and_die("download timed out");
494 }
495# endif
496 /* Needed for "stalled" indicator */
497 progress_meter(PROGRESS_BUMP);
498 /*
499 * We used to loop back to poll here,
500 * but in chunked case, we can be here after
501 * fgets and it could buffer some data in dfp...
502 * which poll knows nothing about!
503 * Therefore let's try fread'ing anyway.
504 */
505 }
506
507 /* fread internally uses read loop, which in our case 477 /* fread internally uses read loop, which in our case
508 * is usually exited when we get EAGAIN. 478 * is usually exited when we get EAGAIN.
509 * In this case, libc sets error marker on the stream. 479 * In this case, libc sets error marker on the stream.
@@ -513,38 +483,71 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
513 * into if (n <= 0) ... 483 * into if (n <= 0) ...
514 */ 484 */
515 clearerr(dfp); 485 clearerr(dfp);
516 errno = 0;
517#endif 486#endif
487 errno = 0;
488 rdsz = sizeof(G.wget_buf);
489 if (G.got_clen) {
490 if (G.content_len < (off_t)sizeof(G.wget_buf)) {
491 if ((int)G.content_len <= 0)
492 break;
493 rdsz = (unsigned)G.content_len;
494 }
495 }
518 n = fread(G.wget_buf, 1, rdsz, dfp); 496 n = fread(G.wget_buf, 1, rdsz, dfp);
519 /* man fread: 497
498 if (n > 0) {
499 xwrite(G.output_fd, G.wget_buf, n);
500#if ENABLE_FEATURE_WGET_STATUSBAR
501 G.transferred += n;
502#endif
503 if (G.got_clen) {
504 G.content_len -= n;
505 if (G.content_len == 0)
506 break;
507 }
508#if ENABLE_FEATURE_WGET_TIMEOUT
509 second_cnt = G.timeout_seconds;
510#endif
511 continue;
512 }
513
514 /* n <= 0.
515 * man fread:
520 * If error occurs, or EOF is reached, the return value 516 * If error occurs, or EOF is reached, the return value
521 * is a short item count (or zero). 517 * is a short item count (or zero).
522 * fread does not distinguish between EOF and error. 518 * fread does not distinguish between EOF and error.
523 */ 519 */
524 if (n <= 0) { 520 if (errno != EAGAIN) {
525#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT 521 if (ferror(dfp)) {
526 if (errno == EAGAIN) /* poll lied, there is no data? */ 522 progress_meter(PROGRESS_END);
527 continue; /* yes */
528#endif
529 if (ferror(dfp))
530 bb_perror_msg_and_die(bb_msg_read_error); 523 bb_perror_msg_and_die(bb_msg_read_error);
524 }
531 break; /* EOF, not error */ 525 break; /* EOF, not error */
532 } 526 }
533 527
534 xwrite(G.output_fd, G.wget_buf, n); 528#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
535#if ENABLE_FEATURE_WGET_TIMEOUT 529 /* It was EAGAIN. There is no data. Wait up to one second
536 second_cnt = G.timeout_seconds; 530 * then abort if timed out, or update the bar and try reading again.
537#endif 531 */
538#if ENABLE_FEATURE_WGET_STATUSBAR 532 if (safe_poll(&polldata, 1, 1000) == 0) {
539 G.transferred += n; 533# if ENABLE_FEATURE_WGET_TIMEOUT
534 if (second_cnt != 0 && --second_cnt == 0) {
535 progress_meter(PROGRESS_END);
536 bb_error_msg_and_die("download timed out");
537 }
538# endif
539 /* We used to loop back to poll here,
540 * but there is no great harm in letting fread
541 * to try reading anyway.
542 */
543 }
544 /* Need to do it _every_ second for "stalled" indicator
545 * to be shown properly.
546 */
540 progress_meter(PROGRESS_BUMP); 547 progress_meter(PROGRESS_BUMP);
541#endif 548#endif
542 if (G.got_clen) { 549 } /* while (reading data) */
543 G.content_len -= n; 550
544 if (G.content_len == 0)
545 break;
546 }
547 }
548#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT 551#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
549 clearerr(dfp); 552 clearerr(dfp);
550 ndelay_off(polldata.fd); /* else fgets can get very unhappy */ 553 ndelay_off(polldata.fd); /* else fgets can get very unhappy */
@@ -560,6 +563,13 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
560 if (G.content_len == 0) 563 if (G.content_len == 0)
561 break; /* all done! */ 564 break; /* all done! */
562 G.got_clen = 1; 565 G.got_clen = 1;
566 /*
567 * Note that fgets may result in some data being buffered in dfp.
568 * We loop back to fread, which will retrieve this data.
569 * Also note that code has to be arranged so that fread
570 * is done _before_ one-second poll wait - poll doesn't know
571 * about stdio buffering and can result in spurious one second waits!
572 */
563 } 573 }
564 574
565 /* If -c failed, we restart from the beginning, 575 /* If -c failed, we restart from the beginning,