blob: a51b2ef8e82a75bd91d8cb3e080d56fd3827cdaf (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
#!/bin/sh
die() { printf "%s: Error: %s\n" "$0" "$*" >&2; exit 1; }
[ "$(id -u)" = 0 ] || die 'you are not root'
TEMP="$(getopt -o 'f:vcxz' --long size:,file:,create,extract,gzip,gunzip,ungzip -n "$0" -- "$@")" ||
die 'getopt error'
eval set -- "$TEMP"
MIN_BYTES=$((128 * 1024 * 1024))
FILE=
MODE=
ZIP=y
BYTES=$((256 * 1024 * 1024))
while [ $# -gt 0 ]; do
case "$1" in
--size)
BYTES=$(( $2 * 1024 * 1024))
[ "$BYTES" -ge "$MIN_BYTES" ] || die "invalid size (too small or not a number)"
SIZE="$2"
shift 2 ;;
-f|--file)
[ "$FILE" ] && die "only one archive file can be specified"
FILE="$2"
shift 2 ;;
-c|--create)
[ "$MODE" ] && die "incompatible modes"
MODE=create
shift ;;
-x|--extract)
[ "$MODE" ] && die "incompatible modes"
MODE=extract
shift ;;
-v)
VERBOSE=y
shift ;;
-z|--gzip|--gunzip|--ungzip)
ZIP=y
shift ;;
--)
shift; break;;
*) die 'getopt error';;
esac
done
[ "$FILE" ] || die "you must specify a file (this is not tar, there is no stdout)"
create()
{
TMPFILE=$(dirname "$FILE")/.~.$(basename "$FILE")
# [ ! -e "$FILE" ] || die "refusing to overwrite '$FILE'"
# [ ! -e "$TMPFILE" ] || die "refusing to overwrite '.~.$FILE'"
rm -f "$TMPFILE"
fallocate -l "$BYTES" "$TMPFILE"
mountpoint=$(mktemp -d) || die
trap 'umount "$mountpoint"; rmdir "$mountpoint"; rm "$TMPFILE"' EXIT
mkfs.btrfs "$TMPFILE" || die
mount -o ${ZIP:+compress,}loop "$TMPFILE" "$mountpoint" || die
rsync -a ${VERBOSE:+ -i} "$@" "$mountpoint" || die
shrink "$mountpoint"
umount "$mountpoint" || die
btrfs_truncate "$TMPFILE"
rmdir "$mountpoint"
btrfstune -S1 "$TMPFILE" || die
mv "$TMPFILE" "$FILE"
trap '' EXIT
}
btrfs_truncate()
{
local img="$1" bytes
bytes=$(file "$img" | sed -ne 's?.*/\([0-9]*\) bytes used.*?\1?p')
if [ "$bytes" ]; then
truncate -s "$bytes" "$img"
fi
}
get_k()
{
local mountpoint="$1" kilos
kilos=$(btrfs fi usage -k "$mountpoint"|sed -ne 's/[\t ]*Device size:[\t ]*//p')
case "$kilos" in
*.00KiB) echo "${kilos%.00KiB}";;
*) return 1;;
esac
}
shrink()
{
shrinkmegs=100
while true; do
while ! btrfs filesystem resize -${shrinkmegs}M "$mountpoint"/; do
shrinkmegs=$((shrinkmegs - 10 ))
if [ $shrinkmegs -lt 10 ]; then
return
fi
done
done
}
$MODE "$@"
|