Skip to content

Instantly share code, notes, and snippets.

@xenithorb
Last active January 23, 2018 16:23
Show Gist options
  • Save xenithorb/83a03c405bb76da992053ce9a3aebb44 to your computer and use it in GitHub Desktop.
Save xenithorb/83a03c405bb76da992053ce9a3aebb44 to your computer and use it in GitHub Desktop.
#!/bin/bash
#
# Usage:
#
# ./purge-file.sh <snapshot_path> "<file_or_relative_path>"
#
# Example:
#
# ./purge-file.sh /mnt/btrfs/snapshots/home "Downloads/*.iso"
#
# This will remove all *.iso files from all snapshots in /mnt/btrfs/snapshots/home.*
# such as a name like "home.20180121T070102-0500", it looks for
# /mnt/btrfs/snapshots/home.*/**/Downloads/*.iso, precisely
#
# You can also specify a file only, and the -path option to `find` will automatically
# remove itself
#
#
set -eu
# set -x
SUBVOL_PATH="$1"
FILE="$2"
DIR="${2%/*}" && [[ $FILE == "$DIR" ]] && unset DIR
is_ro() {
# Usage: is_ro <btrfs_subvolume>
# Exits true/false if a subvolue is read-only
[[ $(sudo btrfs property get "$(df -h "$1" | awk 'NR>1 { print $6 }')" ro) != 'ro=false' ]]
}
echo_wrap() {
echo "$*"; eval "$*"
}
is_btrfs_subvolume() {
local path inode fstype
path="$1"
inode=$( stat --format='%i' "$path" )
fstype=$( stat -f --format='%T' "$path" )
(
(( inode == 256 )) && [[ $fstype == "btrfs" ]]
) && return 0 || return 1
}
purge_file() {
local file="$1" # ex: /mnt/btrfs/snapshots/home.20180121T070102-0500/file.tar.gz
local suffix="${file#${SUBVOL_PATH}}" # ex: .20180121T070102-0500/file.tar.gz
local snapshot="${SUBVOL_PATH}${suffix%%/*}" # ex: /mnt/btrfs/snapshots/home.20180121T070102-0500
local was_read_only=0
is_btrfs_subvolume "$snapshot" || { echo "File not in a btrfs snapshot"; exit 1; }
if is_ro "$snapshot"; then
echo_wrap sudo btrfs property set "$snapshot" ro false &&
was_read_only=1
fi
echo_wrap sudo rm -v -i "${file:?ERROR NO FILE}"
if (( was_read_only )); then
echo_wrap sudo btrfs property set "$snapshot" ro true
fi
}
# Activate/check sudo early
sudo -v || { echo "Needs sudo"; exit 1; }
# Get an array of all the files we want to remove from the snapshots
echo "Finding files in subvol ${SUBVOL_PATH}*..."
mapfile -t FILE_LIST < <(
sudo find "${SUBVOL_PATH}."* \
-xdev ${DIR:+-path "${SUBVOL_PATH}*/**/${DIR}/\*"} \
-name "${FILE##*/}"
)
echo "Done."
(( ${#FILE_LIST[@]} <= 0 )) && { echo "No files to delete"; exit 0; }
echo "Removing files.."
for file in "${FILE_LIST[@]}"; do
purge_file "$file"
done
echo "Done."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment