From 6f88b06cf80b80fe727f0867d40aa8982a956415 Mon Sep 17 00:00:00 2001 From: Alex Denes Date: Wed, 15 Jan 2025 12:22:28 +0000 Subject: [PATCH] Add delta snapshot restoration script --- btrfs/merge-delta-file | 67 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100755 btrfs/merge-delta-file diff --git a/btrfs/merge-delta-file b/btrfs/merge-delta-file new file mode 100755 index 0000000..ad09dbf --- /dev/null +++ b/btrfs/merge-delta-file @@ -0,0 +1,67 @@ +#!/bin/sh +# +# BTRFS delta snapshots restoration +# CC0 ~caskd +# +# This recursively goes to the initial full backup and restores every step to the requested source + +set -e + +: ${SRC:?'Source not defined'} +: ${SIZE:=1G} + +DATANAME="data" +PARENTNAME="parent" +LOOPBACKNAME="restore" +TMPPATTERN="btrfs-restore.XXXXXXXXXX" + +msg() { + echo "$1" >&2 +} + +cleanup_err() { + cleanup + rm -v "$LOOPBACKNAME" +} + +cleanup() { + # Disable traps and cleanup + trap '' INT TERM EXIT HUP + umount -v "$TMPDIR" + rmdir "$TMPDIR" +} + +decompress() { + zstd -d +} + +delta_recieve() { + local CURRENT="$1" + local DEST="$2" + if [ -L "$CURRENT/$PARENTNAME" ]; then + local PARENT="$(realpath "$CURRENT/$PARENTNAME")" + if ! delta_recieve "$PARENT" "$DEST"; then + msg "Cannot receive $(basename "$PARENT") > $(basename "$CURRENT")" + return + fi + fi + if ! < "$CURRENT"/"$DATANAME" decompress | btrfs -v receive "$DEST"; then + msg "Failed to receive $(basename "$CURRENT")" + return + fi +} + +trap cleanup_err INT TERM EXIT HUP + +fallocate -l "$SIZE" "$LOOPBACKNAME" || return +LOOPBACK="$(losetup --show -f "$LOOPBACKNAME")" || return +echo "$LOOPBACK" + +mkfs.btrfs "$LOOPBACK" || return +TMPDIR="$(mktemp -d "$TMPPATTERN")" || return +echo "$TMPDIR" + +mount -t btrfs "$LOOPBACK" "$TMPDIR" || return +delta_recieve "$SRC" "$TMPDIR" || return + +cleanup