Skip to content

Commit

Permalink
Fallback to encode/decode helpers if perl does not support 'Q' in pac…
Browse files Browse the repository at this point in the history
…k/unpack

Kudos to Marcus Huewe for the ideas and first implementation.
  • Loading branch information
mlschroe committed Jun 12, 2018
1 parent f0f652a commit 4be1109
Showing 1 changed file with 31 additions and 2 deletions.
33 changes: 31 additions & 2 deletions computeblocklists
Original file line number Diff line number Diff line change
Expand Up @@ -102,23 +102,51 @@ sub bytes_in_blocks($$) {
#
# see /usr/include/linux/fiemap.h for definitions of the flags used below
#
my $q_pack = 'Q';
my $q_le = 0;

sub encode_q {
my ($v) = @_;
return $v if $q_pack eq 'Q';
my $v1 = int($v / 4294967296);
my $v2 = int($v - 4294967296 * $v1);
($v1, $v2) = ($v2, $v1) if $q_le;
return pack("LL", $v1, $v2);
}

sub decode_q {
return $_[0] if $q_pack eq 'Q';
my ($v1, $v2) = unpack("LL", $_[0]);
($v1, $v2) = ($v2, $v1) if $q_le;
my $v = $v1 * 4294967296 + $v2;
die("decode_q: number too big\n") if int($v - 4294967296 * $v1) != $v2;
return $v;
}

sub fiemap_blocklist($$$) {
my ($file, $size, $blocksize) = @_;

# check if pack/unpack supports the Q template
eval { die if unpack('Q', pack('Q', 1)) != 1 };
if ($@) {
# nope, fallback to encode/decode helpers
$q_pack = 'a8';
$q_le = unpack('C', pack('L', 1)) ? 1 : 0;
}
my $FIEMAP = 0xc020660b;
my $offset = 0;

while ($offset < $size) {
my $flags_in = 0x00000001; # FIEMAP_FLAG_SYNC
my $x = pack("QQIIIx4.", $offset, $size, $flags_in, 0, 50, 4096);
my $x = pack("${q_pack}${q_pack}IIIx4.", encode_q($offset), encode_q($size), $flags_in, 0, 50, 4096);

if (not defined ioctl($file, $FIEMAP, $x)) {
if (not defined ioctl($file, alt_ioctl($FIEMAP), $x)) {
die("fiemap ioctl: $!\n");
}
}

my ($flags, $count, @extents) = unpack("x16IIx8(QQQQQIIII)[50]", $x);
my ($flags, $count, @extents) = unpack("x16IIx8(${q_pack}${q_pack}${q_pack}${q_pack}${q_pack}IIII)[50]", $x);

$count = int($count);

Expand All @@ -129,6 +157,7 @@ sub fiemap_blocklist($$$) {
my $start = $i * 9;
my $hole;
my @record = @extents[$start..$start+9];
$record[$_] = decode_q($record[$_]) for 0, 1, 2;
my ($logical, $physical, $length, $resv1, $resv2, $flags) = @record;
if ($offset != $logical) {
$hole = bytes_in_blocks($logical - $offset, $blocksize) - 1;
Expand Down

0 comments on commit 4be1109

Please sign in to comment.