[pve-devel] [PATCH common 1/4] Tools: add `convert_size` for generic byte conversion
Thomas Lamprecht
t.lamprecht at proxmox.com
Mon Aug 28 10:37:42 CEST 2017
We often need to convert between file sizes, for formatting output,
but also code-internal. Some methods expect kilobytes, some gigabytes
and sometimes we need bytes.
While conversion from smaller to bigger units can be simply done with
a left-shift, the opposite conversion may need more attention -
depending on the used context.
If we allocate disks this is quite critical. For example, if we need
to allocate a disk with size 1023 bytes using the
PVE::Storage::vdisk_alloc method (which expects kilobytes) a
right shift by 10 (<=> division by 1024) would result in "0", which
obviously fails.
Thus we round up the converted value if a remainder was lost on the
transformation in this new method. This behaviour is opt-out, to be
on the safe side.
The method can be used in a clear way, as it gives information about
the source and target unit size, unlike "$var *= 1024", which doesn't
gives direct information at all, if not commented or derived
somewhere from its context.
my $kilobytes = convert_unit($value, 'gb' => 'kb');
We return also the remainder in list context, which may be useful for
formatting output, e.g. if a float is desired.
Signed-off-by: Thomas Lamprecht <t.lamprecht at proxmox.com>
---
src/PVE/Tools.pm | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/src/PVE/Tools.pm b/src/PVE/Tools.pm
index 9818f63..90facc5 100644
--- a/src/PVE/Tools.pm
+++ b/src/PVE/Tools.pm
@@ -1619,4 +1619,35 @@ sub encrypt_pw {
return crypt(encode("utf8", $pw), "\$5\$$salt\$");
}
+# intended usage: convert_size($val, "kb" => "gb")
+# on reduction (converting to a bigger unit) we round up by default if
+# information got lost. E.g. `convert_size(1023, "b" => "kb")` returns 1
+# use $no_round_up to switch this off, above example would then return 0
+sub convert_size {
+ my ($value, $from, $to, $no_round_up) = @_;
+
+ my $units = {
+ b => 0,
+ kb => 1,
+ mb => 2,
+ gb => 3,
+ tb => 4,
+ pb => 5,
+ };
+
+ $from = lc($from); $to = lc($to);
+
+ my $shift_amount = $units->{$from} - $units->{$to};
+ my $remainder = ($value & (1 << abs($shift_amount)*10) - 1);
+
+ if ($shift_amount > 0) {
+ $value <<= ($shift_amount * 10);
+ } elsif ($shift_amount < 0) {
+ $value >>= abs($shift_amount * 10);
+ $value++ if $remainder && !$no_round_up;
+ }
+
+ return wantarray ? ($value, $remainder) : $value;
+}
+
1;
--
2.11.0
More information about the pve-devel
mailing list