btrfs 文件系统结束偏移(图像大小)

Anu*_*nul 5 filesystems btrfs disk-image

我在 10G 图像文件中有一个大约 7G 的 btrfs 文件系统img.btrfs(我使用 缩小了它btrfs fi resize -3G /mnt)。如何找到文件系统的总大小(结束字节偏移量),以便缩小图像大小?即找出$SIZE

truncate -s $SIZE img.btrfs
Run Code Online (Sandbox Code Playgroud)

适用于图像文件内的任何其他文件系统的机制将是一个加分项。

注意:有一点的工作是:

INITIAL=$(stat -c %s img.btrfs)
mount img.btrfs /mnt
btrfs fi resize -$NBYTES /mnt
umount /mnt
truncate -s $((INITIAL - NBYTES + 1024*1024)) img.btrfs
mount /img.btrfs /mnt
btrfs fi resize max /mnt
Run Code Online (Sandbox Code Playgroud)

即缩小 btrfs,将图像缩小一点(留下 1M 的开销),然后将 btrfs 增大到缩小图像所提供的最大值。

Gil*_*il' 5

Annoyingly, btrfs filesystem show returns an approximate value if the size isn't a multiple of 1MB. It also requires a loop device, btrfs filesystem show img.btrfs doesn't work (as of Debian jessie). I can't find another btrfs subcommand that would help.

But file img.btrfs helpfully returns the desired size.

$ 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

It directly reads the 8-byte little-endian value at offset 0x10070. If you don't want to parse the output of file, you can extract it. The following POSIX snippet does the 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
Run Code Online (Sandbox Code Playgroud)

or in 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"'
Run Code Online (Sandbox Code Playgroud)

file works for some other filesystem types, but that doesn't help much for scripts because the output isn't standardized. I can't think of a generic utility with a standard interface for all common filesystems, maybe some virtualization or forensics tool.

¹ Exercise: why is this a useful use of cat?