diff options
Diffstat (limited to 'tests/agent/btrfs-cpdir')
-rwxr-xr-x | tests/agent/btrfs-cpdir | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/tests/agent/btrfs-cpdir b/tests/agent/btrfs-cpdir new file mode 100755 index 0000000..d2dbd43 --- /dev/null +++ b/tests/agent/btrfs-cpdir @@ -0,0 +1,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" |