diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2021-03-11 13:57:08 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-03-11 13:57:08 +0000 |
commit | 9abda42bf2f5aa6ef403d3140fd3d7d88e8064e9 (patch) | |
tree | 567a39c5c5bbb0cb66b899ab35d9188a7dc8f8b4 /util | |
parent | 363fc963054d8e82cfd55fa9b9aa130692a8dbd7 (diff) | |
parent | 1184b411016bce7590723170aa6b5984518707ec (diff) |
Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2021-03-09' into staging
nbd patches for 2021-03-09
- Add Vladimir as NBD co-maintainer
- Fix reporting of holes in NBD_CMD_BLOCK_STATUS
- Improve command-line parsing accuracy of large numbers (anything going
through qemu_strtosz), including the deprecation of hex+suffix
- Improve some error reporting in the block layer
# gpg: Signature made Tue 09 Mar 2021 15:38:10 GMT
# gpg: using RSA key 71C2CC22B1C4602927D2F3AAA7A16B4A2527436A
# gpg: Good signature from "Eric Blake <eblake@redhat.com>" [full]
# gpg: aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>" [full]
# gpg: aka "[jpeg image of size 6874]" [full]
# Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2 F3AA A7A1 6B4A 2527 436A
* remotes/ericb/tags/pull-nbd-2021-03-09:
block/qcow2: refactor qcow2_update_options_prepare error paths
block/qed: bdrv_qed_do_open: deal with errp
block/qcow2: simplify qcow2_co_invalidate_cache()
block/qcow2: read_cache_sizes: return status value
block/qcow2-bitmap: return status from qcow2_store_persistent_dirty_bitmaps
block/qcow2-bitmap: improve qcow2_load_dirty_bitmaps() interface
block/qcow2: qcow2_get_specific_info(): drop error propagation
blockjob: return status from block_job_set_speed()
block/mirror: drop extra error propagation in commit_active_start()
block: drop extra error propagation for bdrv_set_backing_hd
blockdev: fix drive_backup_prepare() missed error
block: check return value of bdrv_open_child and drop error propagation
utils: Deprecate hex-with-suffix sizes
utils: Improve qemu_strtosz() to have 64 bits of precision
utils: Enhance testsuite for do_strtosz()
nbd: server: Report holes for raw images
MAINTAINERS: add Vladimir as co-maintainer of NBD
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'util')
-rw-r--r-- | util/cutils.c | 98 |
1 files changed, 77 insertions, 21 deletions
diff --git a/util/cutils.c b/util/cutils.c index 70c7d6efbd..d89a40a8c3 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -241,52 +241,108 @@ static int64_t suffix_mul(char suffix, int64_t unit) } /* - * Convert string to bytes, allowing either B/b for bytes, K/k for KB, - * M/m for MB, G/g for GB or T/t for TB. End pointer will be returned - * in *end, if not NULL. Return -ERANGE on overflow, and -EINVAL on - * other error. + * Convert size string to bytes. + * + * The size parsing supports the following syntaxes + * - 12345 - decimal, scale determined by @default_suffix and @unit + * - 12345{bBkKmMgGtTpPeE} - decimal, scale determined by suffix and @unit + * - 12345.678{kKmMgGtTpPeE} - decimal, scale determined by suffix, and + * fractional portion is truncated to byte + * - 0x7fEE - hexadecimal, unit determined by @default_suffix + * + * The following cause a deprecation warning, and may be removed in the future + * - 0xabc{kKmMgGtTpP} - hex with scaling suffix + * + * The following are intentionally not supported + * - octal, such as 08 + * - fractional hex, such as 0x1.8 + * - floating point exponents, such as 1e3 + * + * The end pointer will be returned in *end, if not NULL. If there is + * no fraction, the input can be decimal or hexadecimal; if there is a + * fraction, then the input must be decimal and there must be a suffix + * (possibly by @default_suffix) larger than Byte, and the fractional + * portion may suffer from precision loss or rounding. The input must + * be positive. + * + * Return -ERANGE on overflow (with *@end advanced), and -EINVAL on + * other error (with *@end left unchanged). */ static int do_strtosz(const char *nptr, const char **end, const char default_suffix, int64_t unit, uint64_t *result) { int retval; - const char *endptr; + const char *endptr, *f; unsigned char c; - int mul_required = 0; - double val, mul, integral, fraction; + bool mul_required = false, hex = false; + uint64_t val; + int64_t mul; + double fraction = 0.0; - retval = qemu_strtod_finite(nptr, &endptr, &val); + /* Parse integral portion as decimal. */ + retval = qemu_strtou64(nptr, &endptr, 10, &val); if (retval) { goto out; } - fraction = modf(val, &integral); - if (fraction != 0) { - mul_required = 1; + if (memchr(nptr, '-', endptr - nptr) != NULL) { + endptr = nptr; + retval = -EINVAL; + goto out; + } + if (val == 0 && (*endptr == 'x' || *endptr == 'X')) { + /* Input looks like hex, reparse, and insist on no fraction. */ + retval = qemu_strtou64(nptr, &endptr, 16, &val); + if (retval) { + goto out; + } + if (*endptr == '.') { + endptr = nptr; + retval = -EINVAL; + goto out; + } + hex = true; + } else if (*endptr == '.') { + /* + * Input looks like a fraction. Make sure even 1.k works + * without fractional digits. If we see an exponent, treat + * the entire input as invalid instead. + */ + f = endptr; + retval = qemu_strtod_finite(f, &endptr, &fraction); + if (retval) { + fraction = 0.0; + endptr++; + } else if (memchr(f, 'e', endptr - f) || memchr(f, 'E', endptr - f)) { + endptr = nptr; + retval = -EINVAL; + goto out; + } else if (fraction != 0) { + mul_required = true; + } } c = *endptr; mul = suffix_mul(c, unit); - if (mul >= 0) { + if (mul > 0) { + if (hex) { + warn_report("Using a multiplier suffix on hex numbers " + "is deprecated: %s", nptr); + } endptr++; } else { mul = suffix_mul(default_suffix, unit); - assert(mul >= 0); + assert(mul > 0); } if (mul == 1 && mul_required) { + endptr = nptr; retval = -EINVAL; goto out; } - /* - * Values near UINT64_MAX overflow to 2**64 when converting to double - * precision. Compare against the maximum representable double precision - * value below 2**64, computed as "the next value after 2**64 (0x1p64) in - * the direction of 0". - */ - if ((val * mul > nextafter(0x1p64, 0)) || val < 0) { + if (val > (UINT64_MAX - ((uint64_t) (fraction * mul))) / mul) { retval = -ERANGE; goto out; } - *result = val * mul; + *result = val * mul + (uint64_t) (fraction * mul); retval = 0; out: |