Skip to content

Instantly share code, notes, and snippets.

@nekonaq
Last active April 8, 2019 07:25
Show Gist options
  • Select an option

  • Save nekonaq/de61c63f71d709187f0a0b2decc9dfdc to your computer and use it in GitHub Desktop.

Select an option

Save nekonaq/de61c63f71d709187f0a0b2decc9dfdc to your computer and use it in GitHub Desktop.
スパースファイルの基本操作

スパースファイルの操作

スパースな 10M のファイルを作成する

#// 通常のファイルを作成
$ dd if=/dev/zero of=data.img bs=1 count=10M

#// スパースなファイルを作成
$ truncate --size 10M test1.img

#// スパースなファイルを作成するもうひとつの方法
$ dd if=/dev/zero of=test2.img bs=1 count=0 seek=10M

ls コマンドで見るとサイズは同じ。

$ ls -lah *.img
-rw-rw-r-- 1 nak nak 10M 2019-04-01 05:26 data.img
-rw-rw-r-- 1 nak nak 10M 2019-04-01 05:25 test1.img
-rw-rw-r-- 1 nak nak 10M 2019-04-01 05:25 test2.img

find コマンドで割り当てブロック数と sparseness が確認できる。

$ find . -name '*.img' -printf 'size=%s; blk=%b; sparseness=%S; filename=%p\n'
size=10485760; blk=20480; sparseness=1; filename=./data.img
size=10485760; blk=0; sparseness=0; filename=./test1.img
size=10485760; blk=0; sparseness=0; filename=./test2.img

stat コマンドで割り当てブロック数とブロックの大きさが確認できる。

$ stat --format 'size=%s; blk=%b; blksize=%B; filename=%n' *.img
size=10485760; blk=20480; blksize=512; filename=data.img
size=10485760; blk=0; blksize=512; filename=test1.img
size=10485760; blk=0; blksize=512; filename=test2.img

10M のスパースファイルをもうひとつ作成して ext4 でフォーマットする。 使った分だけブロックが割り当てられている。

$ truncate --size 10M image.img
$ mkfs.ext4 image.img

$ stat --format 'size=%s; blk=%b; blksize=%B; filename=%n' *.img
size=10485760; blk=20480; blksize=512; filename=data.img
size=10485760; blk=224; blksize=512; filename=image.img
size=10485760; blk=0; blksize=512; filename=test1.img
size=10485760; blk=0; blksize=512; filename=test2.img

lsdu でファイルのサイズと割り当てブロック数、スパース度 (sparseness) を表示する。

$ ./lsdu 
10485760 20480 20480 1.000 data.img
10485760 20480   224 0.010 image.img
    1176     8     8 1.000 lsdu
10485760 20480     0 0.000 test1.img
10485760 20480     0 0.000 test2.img

tar コマンドとスパースファイル

tar コマンドでアーカイブする。 オプション -S ( --sparse ) を付けた場合は割り当てられたブロックだけアーカイブされる。

$ tar cvf image.img.tar image.img
$ tar cvf image.img-s.tar -S image.img

$ ls -lah image.*
-rw-rw-r-- 1 nak nak  10M 2019-04-01 05:40 image.img
-rw-rw-r-- 1 nak nak 120K 2019-04-01 05:45 image.img-s.tar
-rw-rw-r-- 1 nak nak  11M 2019-04-01 05:45 image.img.tar

復元して確認する。

$ mkdir -p img; tar xvf image.img.tar -C img
$ mkdir -p img-s; tar xvf image.img-s.tar -C img-s

$ stat --format 'size=%s; blk=%b; blksize=%B; filename=%n' img*/*
size=10485760; blk=224; blksize=512; filename=img-s/image.img
size=10485760; blk=20480; blksize=512; filename=img/image.img

squashfs とスパースファイル

squashfs にして戻してみると割り当てブロックサイズが変わっている。

$ mksquashfs img-s img-s.sqfs
$ unsquashfs -lls img-s.sqfs
Parallel unsquashfs: Using 8 processors
1 inodes (80 blocks) to write

drwxrwxr-x nak/nak                  32 2019-04-01 05:56 squashfs-root
-rw-rw-r-- nak/nak            10485760 2019-04-01 05:40 squashfs-root/image.img

$ unsquashfs img-s.sqfs

$ stat --format 'size=%s; blk=%b; blksize=%B; filename=%n' squashfs-root/*.img
size=10485760; blk=768; blksize=512; filename=squashfs-root/image.img

ブロックサイズ 4k で squashfs すると、割り当てブロックサイズが元のファイルと同じになる。

$ mksquashfs img-s img-s.sqfs -b 4k
$ unsquashfs img-s.sqfs

$ stat --format 'size=%s; blk=%b; blksize=%B; filename=%n' squashfs-root/*.img
size=10485760; blk=224; blksize=512; filename=squashfs-root/image.img
#!/bin/sh
# ファイルのサイズと割り当てブロック数、スパース度 (sparseness) を表示する
set -e
print_file_size_summary() {
local filename="$1"
local blk_allocs=8
local size= blks= blksiz= name=
eval "$( stat --format 'bytes=%s; blks=%b; blksiz=%B; name=%n' "$fn" )"
local size_blknum="$(( ($bytes + $blksiz - 1) / $blksiz ))"
local size_blks="$(( ($size_blknum + $blk_allocs - 1) / $blk_allocs * $blk_allocs ))"
local sparseness="$( printf '%.3f\n' "$(( 1000 * $blks / $size_blks ))e-3" )"
echo "$bytes" "$size_blks" "$blks" "$sparseness" "$name"
}
main() {
local out="$(
for fn in ${@:-$(echo *)}; do
print_file_size_summary "$filename"
done
)"
local size_w=" $( echo "$out" | cut -d' ' -f1 | wc -L )"
local size_blks_w=" $( echo "$out" | cut -d' ' -f2 | wc -L )"
local blks_w=" $( echo "$out" | cut -d' ' -f3 | wc -L )"
echo "$out" |
while read size size_blks blks sparseness filename; do
printf '%*d %*d %*d %.3f %s\n' \
"$size_w" "$size" \
"$size_blks_w" "$size_blks" \
"$blks_w" "$blks" \
"$sparseness" \
"$filename"
done
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment