commit 20fcf2fac6a590cdc8f1aede92e28b8efa01d54d Author: Michael Rodin Date: Sat Sep 2 19:49:37 2023 +0200 Initial commit diff --git a/backup-rclone.sh b/backup-rclone.sh new file mode 100755 index 0000000..af2895e --- /dev/null +++ b/backup-rclone.sh @@ -0,0 +1,145 @@ +#!/bin/bash +MAX_NAME_WIDTH=50 # Maximal length of name next to the progress bar in percent (%) + +tempdir=$(mktemp -d /tmp/backup-XXXXXXXXXX) +existing=() + +recursive_backup() { + + hashtemp=$(mktemp $tempdir/hashes-XXXXXXXXXXXXXXX.db) # /tmp dir for saving data and encrypting files + if [[ -n $(rclone lsf "backup:$hashdb" 2>/dev/null) ]]; then # if hash file exists, copy it to tmp dir + rclone cat "backup:$hashdb" > $hashtemp + fi + trap "cleanup $hashtemp $hashdb" SIGINT + trap "cleanup $hashtemp $hashdb" SIGTSTP + + for dir in "${include[@]}"; do # go through all included directories + done_files=0 + progress=0 + total_files=$(wc -l <<<$(find "$dir" -type f)) # count all files for progress bar + action="" + for i in "${exclude[@]}"; do if [[ "$dir" == "$i" ]]; then continue; fi; done # if dir in exclude, skip it # TODO: POSSIBLE WHOOPSIE! + while read k; do # take every file and make a backup + if [[ ${k///} == $k ]]; then filepath="."; else filepath=${k%/*}; fi # if file in root of dir, change the path to not crash everything ,else get filepath + draw_progress $(($progress)) "$k" "$action" + #remotehash="$(cat $hashtemp | grep -n "$k")" # old databese + sqlcommand="SELECT hash FROM files WHERE backpath=\"${k}\"" + remotehash="""$(sqlite3 $hashtemp "$sqlcommand")""" # get hash from database + if [[ -z $remotehash ]]; then entryexists=false; else entryexists=true; fi # if file entry (and hash) exists, save as bool + localhash="$(md5sum "$k")" # hash of local version of file + done_files=$(($done_files+1)) + progress=$(($done_files*100/$total_files)) + if [[ "$remotehash" == "$localhash" ]]; then action="Skip"; continue; fi # if the has his the same, skip backuup + action="Backup" + draw_progress $(($progress)) "$k" "$action" + if [[ $enctype == "gpg" ]]; then + gpg -e -r "$RECIPIENT_ID" -o "$tempdir/${k##*/}.gpg" "$k" + backupfile="$tempdir/${k##*/}.gpg" + else + backupfile="$k" + fi + + if [[ $filepath == "." ]]; then flpth=""; else flpth="/$filepath"; fi + backup "$backupfile" "backup:$backdir$flpth" + done <<< "$(find "$dir" -type f)" + done + touch missing-files.txt + while read i; do # TODO: DELETE THIS PART + sfile="${i#* }" + if [[ -f "$sfile" ]]; then df="Hi"; else echo "Missing: $sfile"; echo "$sfile" >> missing-files.txt; fi + done <<<$(cat $hashtemp) + cleanup $hashtemp $hashdb +} +backup() { # backup 1: 2: + if [[ *"${existing[@]}"* == "$2" ]]; then # if remote directory is set as existing, don't check it's existence + df="Hi" + else + if [[ -n $(rclone lsd "$2" 1>/dev/null) ]]; then # check if directory doesn't exist on server + rclone mkdir "$2" + fi + existing=("${existing[@]}" "$2") + fi + bool=0 + rclone copy "$1" "$2" && bool=1 + #if [[ $remoteline == "0" && $bool == 1 ]]; then echo "$localhash" >> $hashtemp; else sed -i "${remoteline}s|.*|${localhash}|" $hashtemp; fi # TODO: SQL ###### + if [[ $bool==1 && $entryexists ]]; then + sqlcommand="UPDATE files SET hash=\"${localhash}\" WHERE backpath=\"${2}\"" #set new hash in database + sqlite3 $hashtemp "$sqlcommand" + else + if [[ "$enctype" == "gpg" ]]; then encdata="$RECIPIENT_ID" + else encdata=""; fi + sqlcommand="INSERT INTO files(backpath,localroot,hash,backupenc,encdata) VALUES(\'${2}\',\'$(pwd)\',\'$localhash\',\'${enctype}\',\'${encdata}\')" + sqlite3 $hashtemp "$sqlcommand" + fi +} +cleanup() { # 1:hashtemp 2:hashdb + echo -e "\ncleaning up..." + cd ${1%/*} + localhfile=${2##*/} + mv "${1##*/}" "$localhfile" + rclone move "$localhfile" backup:${2%/*} + finish +} +finish() { + rmdir $tempdir || rm -rf $tempdir + exit +} +draw_progress() { # draw_progress 1: 2: 3: + + window_length=$(tput cols); window_length=$(($window_length-3)) # get max window length + max_name_length=$(($window_length*$MAX_NAME_WIDTH/100)) # calc max length of filepath + if [[ ${#2} -gt $max_name_length ]]; then # if filepath too long, cut it, else add whitespace + name="$(cut -c -$max_name_length <<< "$2")" + else + name="$2" + if [[ ${#name} -lt $max_name_length ]]; then + for _ in $(seq ${#name} $max_name_length); do name+=" "; done + fi + fi + window_length=$(($window_length-${#name})) # get length of progress bar + prog=$(($1*$window_length/100)) + tot=$((window_length-1)) + #echo -e "prog $prog tot $tot done $1 total $2 win $window_length"; return + + # Delete the last two lines + printf "\033[3K" + # Restore the cursor position + printf "\033[u" + echo "Progress: $progress% Action: $3 " + printf "[" + for _ in $(seq 1 $prog); do + printf "#" + done + for _ in $(seq $prog $tot); do + printf "-" + done + printf "]$name\n" +} + + +if [[ $# -eq 0 ]]; then + echo "Please select a directory for backup!" + exit +fi + +cd $1 +curdir=$(pwd) +# save cursor position +printf "\033[s" +# print two dummy lines +printf "\n\n" + +if [[ $# -eq 1 ]]; then + if [[ -f ".backup.env" ]]; then + source .backup.env + if [[ -z ${backdir+x} || -z ${hashdb+x} ]]; then echo "ERROR: env-file doesn't hold needed variables!"; exit; fi + if [[ -n ${include+x} ]]; then include+=(".backup.env"); else include=(*); fi + if [[ -z ${exclude+x} ]]; then exclude=("uc3rumcr3urc34u09q347c7055030785c3cc30mq3rcmu83qm3m.notanonionlink"); fi + if [[ -z ${enctype+x} ]]; then enctype="plain"; fi + else echo "ERROR: env-file doesn't exist!!"; exit; fi +else + echo "too many args!" + exit +fi + +rmdir $tempdir ||rm -rf $tempdir \ No newline at end of file diff --git a/example.backup.env b/example.backup.env new file mode 100644 index 0000000..fa9ebf7 --- /dev/null +++ b/example.backup.env @@ -0,0 +1,9 @@ +enctype="gpg" # type of encryption, use plain if the share is already encrypted (gpg,plain) + +#include=("supersecretfiles" "a-folder") # include these folders in the backup (optional) +#exclude=(".thumbnails" ".git") # exclude these folders from the backup (optional) + +backdir="marcel/archive" # directory on the rclone server +hashdb="$backdir/hashes.db" # database file on the rclone server + +RECIPIENT_ID="123ABF84D7FAADB09015825F9231CC1FF5F1E5D2" # needed if enctype="gpg" \ No newline at end of file