Irritante, btrfs filesystem show retorna um valor aproximado se o tamanho não for um múltiplo de 1MB. Também requer um dispositivo de loop, btrfs filesystem show img.btrfs não funciona (como no Debian jessie). Não consigo encontrar outro subcomando btrfs que ajude.
Mas file img.btrfs de forma útil retorna o tamanho desejado.
$ truncate -s 16684k /tmp/img.btrfs
$ /sbin/mkfs.btrfs /tmp/img.btrfs
SMALL VOLUME: forcing mixed metadata/data groups
Btrfs v3.17
See http://btrfs.wiki.kernel.org for more information.
Turning ON incompat feature 'mixed-bg': mixed data and metadata block groups
Turning ON incompat feature 'extref': increased hardlink limit per file to 65536
Created a data/metadata chunk of size 1703936
failed to open /dev/btrfs-control skipping device registration: Permission denied
fs created label (null) on /tmp/img.btrfs
nodesize 4096 leafsize 4096 sectorsize 4096 size 16.29MiB
$ truncate -s 32m /tmp/img.btrfs
$ file /tmp/img.btrfs
/tmp/img.btrfs: BTRFS Filesystem sectorsize 4096, nodesize 4096, leafsize 4096, UUID=61297945-d399-4fdc-ba9f-750ef9f9dfdb, 28672/17084416 bytes used, 1 devices
Ele lê diretamente o valor little-endian de 8 bytes no deslocamento 0x10070. Se você não quiser analisar a saída de file , poderá extraí-lo. O seguinte trecho POSIX faz o job¹:
size_hex=$(cat /tmp/img.btrfs | dd ibs=8 skip=8206 count=1 2>/dev/null | od -tx8 -An | tr abcdef ABCDEF | tr -dc 0-9ABCDEF)
[ ${#size_hex} -eq 16 ] &&
{ echo "ibase=16; $size_hex"; } | bc
ou em Perl:
</tmp/btrfs.img perl -e 'seek(STDIN, 0x10070, 0) or sysread(STDIN, $_, 0x10070) == 0x10070 or die "seek"; sysread(STDIN, $_, 8) == 8 or die "read"; print unpack("Q<", $_), "\n"'
file funciona para alguns outros tipos de sistema de arquivos, mas isso não ajuda muito em scripts porque a saída não é padronizada. Não consigo pensar em um utilitário genérico com uma interface padrão para todos os sistemas de arquivos comuns, talvez alguma ferramenta de virtualização ou análise forense.
¹ Exercício: por que isso é um uso útil de cat ?