aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2011-02-10 14:25:51 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2011-02-10 14:25:51 +0100
commit805aa9fec923109e90c87eda2f116ee2fa5fe962 (patch)
tree1896eafafe3acd5febd244f69c12932f1bfb63ec
parent9213a55bf0cc833d024975865a96a762b7a90b62 (diff)
downloadbusybox-w32-805aa9fec923109e90c87eda2f116ee2fa5fe962.tar.gz
busybox-w32-805aa9fec923109e90c87eda2f116ee2fa5fe962.tar.bz2
busybox-w32-805aa9fec923109e90c87eda2f116ee2fa5fe962.zip
progress bar: better overflow protection; more precise bar
function old new delta bb_progress_update 639 749 +110 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--include/libbb.h5
-rw-r--r--libbb/progress.c54
2 files changed, 34 insertions, 25 deletions
diff --git a/include/libbb.h b/include/libbb.h
index d390e6840..c0178801f 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1592,8 +1592,9 @@ typedef struct bb_progress_t {
1592 1592
1593void bb_progress_init(bb_progress_t *p) FAST_FUNC; 1593void bb_progress_init(bb_progress_t *p) FAST_FUNC;
1594void bb_progress_update(bb_progress_t *p, const char *curfile, 1594void bb_progress_update(bb_progress_t *p, const char *curfile,
1595 off_t beg_range, off_t transferred, 1595 uoff_t beg_range,
1596 off_t totalsize) FAST_FUNC; 1596 uoff_t transferred,
1597 uoff_t totalsize) FAST_FUNC;
1597 1598
1598extern const char *applet_name; 1599extern const char *applet_name;
1599 1600
diff --git a/libbb/progress.c b/libbb/progress.c
index 40608b047..ced04ac32 100644
--- a/libbb/progress.c
+++ b/libbb/progress.c
@@ -62,35 +62,45 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p)
62 62
63void FAST_FUNC bb_progress_update(bb_progress_t *p, 63void FAST_FUNC bb_progress_update(bb_progress_t *p,
64 const char *curfile, 64 const char *curfile,
65 off_t beg_range, 65 uoff_t beg_range,
66 off_t transferred, 66 uoff_t transferred,
67 off_t totalsize) 67 uoff_t totalsize)
68{ 68{
69 uoff_t beg_and_transferred; 69 uoff_t beg_and_transferred;
70 unsigned since_last_update, elapsed; 70 unsigned since_last_update, elapsed;
71 unsigned ratio; 71 unsigned ratio;
72 int barlength, i; 72 int barlength;
73 int kiloscale;
73 74
74 /* totalsize == 0 if it is unknown */ 75 /* totalsize == 0 if it is unknown */
75 76
77 beg_and_transferred = beg_range + transferred;
78
76 elapsed = monotonic_sec(); 79 elapsed = monotonic_sec();
77 since_last_update = elapsed - p->lastupdate_sec; 80 since_last_update = elapsed - p->lastupdate_sec;
78 /* Do not update on every call 81 /* Do not update on every call
79 * (we can be called on every network read!) */ 82 * (we can be called on every network read!) */
80 if (since_last_update == 0 && !totalsize) 83 if (since_last_update == 0 && beg_and_transferred < totalsize)
81 return; 84 return;
82 85
83 beg_and_transferred = beg_range + transferred; 86 /* Scale sizes down if they are close to overflowing.
84 ratio = 100; 87 * If off_t is only 32 bits, this allows calculations
85 if (beg_and_transferred < totalsize) { 88 * like (100 * transferred / totalsize) without risking overflow.
86 /* Do not update on every call 89 * Introduced error is < 0.1%
87 * (we can be called on every network read!) */ 90 */
88 if (since_last_update == 0) 91 kiloscale = 0;
89 return; 92 if (totalsize >= (1 << 20)) {
90 /* long long helps to have it working even if !LFS */ 93 totalsize >>= 10;
91 ratio = 100ULL * beg_and_transferred / (uoff_t)totalsize; 94 beg_range >>= 10;
95 transferred >>= 10;
96 beg_and_transferred >>= 10;
97 kiloscale++;
92 } 98 }
93 99
100 if (beg_and_transferred >= totalsize)
101 beg_and_transferred = totalsize;
102
103 ratio = 100 * beg_and_transferred / totalsize;
94#if ENABLE_UNICODE_SUPPORT 104#if ENABLE_UNICODE_SUPPORT
95 init_unicode(); 105 init_unicode();
96 { 106 {
@@ -106,21 +116,20 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
106 if (barlength > 0) { 116 if (barlength > 0) {
107 /* god bless gcc for variable arrays :) */ 117 /* god bless gcc for variable arrays :) */
108 char buf[barlength + 1]; 118 char buf[barlength + 1];
109 unsigned stars = (unsigned)barlength * ratio / (unsigned)100; 119 unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize;
110 memset(buf, ' ', barlength); 120 memset(buf, ' ', barlength);
111 buf[barlength] = '\0'; 121 buf[barlength] = '\0';
112 memset(buf, '*', stars); 122 memset(buf, '*', stars);
113 fprintf(stderr, "|%s|", buf); 123 fprintf(stderr, "|%s|", buf);
114 } 124 }
115 125
116 i = 0;
117 while (beg_and_transferred >= 100000) { 126 while (beg_and_transferred >= 100000) {
118 i++; 127 kiloscale++;
119 beg_and_transferred >>= 10; 128 beg_and_transferred >>= 10;
120 } 129 }
121 /* see http://en.wikipedia.org/wiki/Tera */ 130 /* see http://en.wikipedia.org/wiki/Tera */
122 fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[i]); 131 fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]);
123#define beg_and_transferred dont_use_beg_and_transferred_below 132#define beg_and_transferred dont_use_beg_and_transferred_below()
124 133
125 if (transferred > p->lastsize) { 134 if (transferred > p->lastsize) {
126 p->lastupdate_sec = elapsed; 135 p->lastupdate_sec = elapsed;
@@ -137,13 +146,12 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
137 if (since_last_update >= STALLTIME) { 146 if (since_last_update >= STALLTIME) {
138 fprintf(stderr, " - stalled -"); 147 fprintf(stderr, " - stalled -");
139 } else { 148 } else {
140 off_t to_download = totalsize - beg_range; 149 uoff_t to_download = totalsize - beg_range;
141 if (!totalsize || transferred <= 0 || (int)elapsed <= 0 || transferred > to_download) { 150 if (!totalsize || (int)elapsed <= 0 || transferred > to_download) {
142 fprintf(stderr, "--:--:-- ETA"); 151 fprintf(stderr, "--:--:-- ETA");
143 } else { 152 } else {
144 /* to_download / (transferred/elapsed) - elapsed: */ 153 /* to_download / (transferred/elapsed) - elapsed: */
145 /* (long long helps to have working ETA even if !LFS) */ 154 unsigned eta = to_download * elapsed / transferred - elapsed;
146 unsigned eta = (unsigned long long)to_download*elapsed/(uoff_t)transferred - elapsed;
147 unsigned secs = eta % 3600; 155 unsigned secs = eta % 3600;
148 unsigned hours = eta / 3600; 156 unsigned hours = eta / 3600;
149 fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60); 157 fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60);