blob: d2dbd435737e2bfb73c2653ed5860cf8e9c556c5 (
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
106
107
108
109
110
111
112
113
|
#! /usr/bin/env bash
# Copy a directory on (the same) btrfs filesystem. Inside, subvolumes
# are copied with btrfs subvolume snapshot and everything else with
# cp --reflink=always.
#
# If the -f option is specified and <dst> exists, it is first removed by
# calling btrfs-rmdir (which is expected to be found next to btrfs-cpdir).
#
# Notes:
#
# 1. <src> should not be a subvolume (use snapshot directly in this case).
#
# 2. Copying of symlinks is not supported (symlinks in submodules are ok).
#
# 3. Read-only subvolumes are snapshotted as read-only.
#
# Note also that <src> is clones as <dst>, not into <dst> (i.e., like cp -T).
#
usage="usage: $0 [-f] <src>/ <dst>/"
owd="$(pwd)"
trap "{ cd '$owd'; exit 1; }" ERR
set -o errtrace # Trap in functions.
function info () { echo "$*" 1>&2; }
function error () { info "$*"; exit 1; }
force=
while [ "$#" -gt 0 ]; do
case "$1" in
-f)
shift
force="true"
;;
--)
break
;;
-*)
error "unknown option: $1"
;;
*)
break
;;
esac
done
src="${1%/}"
dst="${2%/}"
if [ -z "$src" -o -z "$dst" ]; then
error "$usage"
fi
shopt -s nullglob dotglob
function cp_dir () # <src> <dst>
{
local src="$1"
local dst="$2"
mkdir "$dst"
local s d
for s in "$src"/*; do
d="$dst/${s#$src/}"
if [ -f "$s" ]; then
cp -p --reflink=always "$s" "$d"
continue
fi
if [ -d "$s" ]; then
# See if this is a subvolume: btrfs subvolume list requires root
# priviliges so we use the inode number which for subvolumes is always
# 256.
#
if [ "$(stat --format=%i "$s")" -eq 256 ]; then
cp_subvol "$s" "$d"
else
cp_dir "$s" "$d"
fi
continue
fi
error "$s is not a file/directory, not supported"
done
chmod --reference="$src" "$dst"
chown --reference="$src" "$dst"
}
function cp_subvol () # <src> <dst>
{
local src="$1"
local dst="$2"
local o=()
if [ "$(btrfs property get -ts "$src" ro)" = "ro=true" ]; then
o+=(-r)
fi
btrfs subvolume snapshot "${o[@]}" "$src" "$dst" >/dev/null
}
if [ -d "$dst" -a -n "$force" ]; then
"$(dirname "$(realpath ${BASH_SOURCE[0]})")/btrfs-rmdir" "$dst"
fi
cp_dir "$src" "$dst"
|