-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathincbak.sh
executable file
·84 lines (63 loc) · 2.53 KB
/
incbak.sh
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
#!/bin/bash
get_target_from_gendir() {
local gendir="$1"
local target
for target in $gendir.*; do
[ -e "$target" ] || target="$gendir.0"
break
done
[ -e "$target" ] || mkdir "$target" || { echo "Could not create $target" 1>&2; exit 2; }
echo "$target"
}
push_down() {
local level="$1"
local rev="$2"
local target="$3"
if [[ "$rev" -eq "1" && "$level" -le "$levels" ]]; then
backup_level "$target" "$((level + 1))"
else
rm -r "$target" || { echo "Could not remove $target" 1>&2; exit 3; }
fi
return
}
backup_level() {
local ref="$1"
local level="$2"
local gendir="$dest.$((1 << level))"
local target=$(get_target_from_gendir "$gendir")
local rev="${target: -1}"
local nextrev="$((1 - rev))"
echo "move $ref down to $gendir.$nextrev"
mv "$ref" "$gendir.$nextrev" || { echo "Could not move $ref to $gendir.$nextrev" 1>&2; exit 4; }
push_down "$level" "$rev" "$target"
return
}
shadow=".backup_sync"
exclude=".backup_exclude"
backup_root() {
local ref="$1"
local gendir="$dest.1"
local target=$(get_target_from_gendir "$gendir")
local rev="${target: -1}"
local nextrev="$((1 - rev))"
local excludefrom="/dev/null"
[ -e "$ref/$exclude" ] && excludefrom="$ref/$exclude"
echo "backup $ref to $gendir.$nextrev with hard-links to $target"
rsync -aH --exclude-from="$excludefrom" --no-inc-recursive --delete --delete-after --link-dest="$target" "$ref/" "$gendir.$nextrev/" || { echo "Could not create primary backup from $ref to $gendir.$nextrev" 1>&2; exit 5; }
touch "$gendir.$nextrev" # without that, we'll never know when that backup was made
# preserve current source and destination structure as hard-link copies, to identify moved files later
rsync -a --exclude-from="$excludefrom" --delete --link-dest="$ref" --exclude="/$shadow" "$ref/" "$ref/$shadow" || { echo "Could not create shadow for $ref" 1>&2; exit 6; }
rsync -a --exclude-from="$excludefrom" --delete --link-dest="$gendir.$nextrev" --exclude="/$shadow" "$gendir.$nextrev/" "$gendir.$nextrev/$shadow" || { echo "Could not create shadow for $gendir.$nextrev" 1>&2; exit 7; }
push_down "0" "$rev" "$target"
return
}
source="$1"
dest="$2"
levels="$3"
[ -d "$source" ] || { echo "Missing source" 1>&2; exit 1; }
[ -z "$dest" ] && { echo "Missing destination" 1>&2; exit 1; }
[ -z "$levels" ] && levels=8
source="$(realpath $source)" || { echo "Source does not exist" 1>&2; exit 4; }
dest="$(realpath $dest)" || { echo "Destination does not exist" 1>&2; exit 5; }
[ -e $(dirname "$dest") ] || { echo "Destination does not exist" 1>&2; exit 8; }
backup_root "$source"