lib/strutils: parse_size() fix frac digit calculation
Old code: ./test_strutils --size 0.5MiB 0.5MiB : 512000 : 500K : 500 KiB ./test_strutils --size 0.50MiB 0.50MiB : 5120000 : 4.9M : 4.9 MiB New code: ./test_strutils --size 0.5MiB 0.5MiB : 524288 : 512K : 512 KiB ./test_strutils --size 0.50MiB 0.50MiB : 524288 : 512K : 512 KiB Note that the new implementation also does not use float points, because we need to support PiB and so on... it seems good enough for things like: ./test_strutils --size 7.13G 7.13G : 7656104581 : 7.1G : 7.1 GiB ./test_strutils --size 7.16G 7.16G : 7690675814 : 7.2G : 7.2 GiB to avoid situation where cfdisk creates partition with completely crazy numbers. Addresses: https://github.com/karelzak/util-linux/issues/782 Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
482e0a0754
commit
8c368dc6d3
|
@ -162,17 +162,39 @@ check_suffix:
|
||||||
if (power)
|
if (power)
|
||||||
*power = pwr;
|
*power = pwr;
|
||||||
if (frac && pwr) {
|
if (frac && pwr) {
|
||||||
int zeros_in_pwr = frac_zeros % 3;
|
int i;
|
||||||
int frac_pwr = pwr - (frac_zeros / 3) - 1;
|
uintmax_t frac_div = 10, frac_poz = 1, frac_base = 1;
|
||||||
uintmax_t y = frac * (zeros_in_pwr == 0 ? 100 :
|
|
||||||
zeros_in_pwr == 1 ? 10 : 1);
|
|
||||||
|
|
||||||
if (frac_pwr < 0) {
|
/* mega, giga, ... */
|
||||||
rc = -EINVAL;
|
do_scale_by_power(&frac_base, base, pwr);
|
||||||
goto err;
|
|
||||||
}
|
/* maximal divisor for last digit (e.g. for 0.05 is
|
||||||
do_scale_by_power(&y, base, frac_pwr);
|
* frac_div=100, for 0.054 is frac_div=1000, etc.)
|
||||||
x += y;
|
*/
|
||||||
|
while (frac_div < frac)
|
||||||
|
frac_div *= 10;
|
||||||
|
|
||||||
|
/* 'frac' is without zeros (5 means 0.5 as well as 0.05) */
|
||||||
|
for (i = 0; i < frac_zeros; i++)
|
||||||
|
frac_div *= 10;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Go backwardly from last digit and add to result what the
|
||||||
|
* digit represents in the frac_base. For example 0.25G
|
||||||
|
*
|
||||||
|
* 5 means 1GiB / (100/5)
|
||||||
|
* 2 means 1GiB / (10/2)
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
unsigned int seg = frac % 10; /* last digit of the frac */
|
||||||
|
uintmax_t seg_div = frac_div / frac_poz; /* what represents the segment 1000, 100, .. */
|
||||||
|
|
||||||
|
frac /= 10; /* remove last digit from frac */
|
||||||
|
frac_poz *= 10;
|
||||||
|
|
||||||
|
if (seg)
|
||||||
|
x += frac_base / (seg_div / seg);
|
||||||
|
} while (frac);
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
*res = x;
|
*res = x;
|
||||||
|
|
Loading…
Reference in New Issue