diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-02-10 14:25:51 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-02-10 14:25:51 +0100 |
commit | 805aa9fec923109e90c87eda2f116ee2fa5fe962 (patch) | |
tree | 1896eafafe3acd5febd244f69c12932f1bfb63ec | |
parent | 9213a55bf0cc833d024975865a96a762b7a90b62 (diff) | |
download | busybox-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.h | 5 | ||||
-rw-r--r-- | libbb/progress.c | 54 |
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 | ||
1593 | void bb_progress_init(bb_progress_t *p) FAST_FUNC; | 1593 | void bb_progress_init(bb_progress_t *p) FAST_FUNC; |
1594 | void bb_progress_update(bb_progress_t *p, const char *curfile, | 1594 | void 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 | ||
1598 | extern const char *applet_name; | 1599 | extern 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 | ||
63 | void FAST_FUNC bb_progress_update(bb_progress_t *p, | 63 | void 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); |