-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathbbump
executable file
·161 lines (147 loc) · 4.48 KB
/
bbump
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#! /bin/sh
# bbump (Bourne shell script) -- Incremental tarball metadata management
#
# Creates a set of metadata files that allow the creation of multi-level
# incremental tarballs. (As supported by GNU tar.) Each invocation creates a
# copy of the previous metadata file at the requested level*, which will then be
# modified. It also creates a symlink called backup.meta pointing to the newly
# created metadata file.
# * Because toplevel backups are considered full, the file isn't copied but the
# symlink is updated and left dangling, so tar will create the metadata file
# from scratch, i.e. not relative to a previous metadata file.
#
# GNU tar rewrites the metadata file during each invocation, so run this script
# before `tar -g .../backup.meta ...`.
#
# Usage: bbump [ -n ] [ -u | -i | <level> ]
# Where:
# -n No act, i.e. print what would be done but take no action
# <level> (Not currently supported.)
# -u Means go up a level (and do a full or differential backup)
# instead of continuing a branch.
# -i Add an incremental branch off the latest backup
#
# In the example, each amount of indent (starting at 1) corresponds to a level.
# The first level is considered the highest.
# Each incremental (i.e. not full or differential) tarball is relative to
# either the previous contiguous one at the same level. Each differential tarball is
# relative to the previous one (contiguous or otherwise) at the same level.
# Exception: non-full tarballs ending with .1 are relative to the preceding
# tarball at the higher level.
#
# backup.1.meta
# backup.2.meta
# backup.2.1.meta
# backup.2.2.meta
# backup.2.3.meta
# backup.2.3.1.meta
# backup.2.3.2.meta
# backup.2.4.meta
# backup.2.5.meta
# backup.3.meta
#
# The default is to continue at the same level.
#
# It doesn't make sense to "go back in time" and create a continuation
# of a previous "branch" (at either the same level or a sub-branch) when
# there is a more recent higher-level branch in existence.
SELF=bbump
DIR=${BBUMP_DIR:-/srv/mail/work}
## DIR=/tmp/i
# *** FUNCTIONS ***
# Usage: regular_bump <filename> [ y ]
# Where the second parameter means branch off a new, lower level
regular_bump()
{
if [ ${2-n} = y ] ; then
# Append a .1 to the given increment, i.e. start a new, lower level
new_file="$t.1.meta"
else
# Increment count at current level
new_file="$p.$((increment + 1)).meta"
fi
old_file=$last_file
}
higher_bump()
{
if [ "$p" = $DIR/backup ] ; then
echo "$SELF: At top level, can't go up." >&2
exit 3
fi
upper_increment=${p##*.} # Get lowest-level increment from parent
new_file="${p%.*}.$((upper_increment + 1)).meta"
old_file=$p.meta
}
# *** MAINLINE ***
verbose=0
if [ "x$1" = x-n ] ; then
no_act=y
shift
fi
new_incr=n
if [ "x$1" = x-i ] ; then
new_incr=y
shift
fi
if [ "x$1" = x-u ] ; then
go_up=y
shift
else
go_up=n
fi
if [ $go_up = y ] && [ $new_incr = y ] ; then
echo "$SELF: Can't specify conflicting options" >&2
exit 4
fi
## LEVEL=${1-1}
set $(ls $DIR/backup.$1*.meta | sort --version-sort | tail -n 2)
last_file=$2
penultimate_file=$1 # This should instead be previous-at-same-level for differential
if [ $# -gt 1 ] &&
[ "$(md5sum $last_file | cut -d' ' -f1)" = "$(md5sum $penultimate_file | cut -d' ' -f1)" ]
then
echo "$SELF: $DIR/backup.*.meta has already been copied; bailing out." >&2
exit 2
fi
t=${last_file%.meta}
p=${t%.*}
increment=${t##*.}
# Set $new_file
if [ $go_up = y ] ; then
higher_bump $last_file
if [ "$no_act" = y -o $verbose -ge 1 ] ; then
echo "$old_file -> $new_file"
fi
else
if [ "$p" = $DIR/backup ] ; then
# Bail out here if defaulting to a full backup is not desired
:
else
# New branch from parent
:
fi
regular_bump $last_file $new_incr
if [ "$no_act" = y -o $verbose -ge 1 ] ; then
echo "$old_file ($increment) -> $new_file"
fi
fi
if [ "$no_act" = y ] ; then
echo "Bailing out as requested."
exit
fi
echo $new_file
new_file_t=${new_file%.*}
if [ "${new_file_t%.*}" = $DIR/backup ] ; then
# Don't copy anything (just create the symlink) when making a top level
# increment because we want GNU tar to create the file from scratch
echo full
else
# For an incremental backup, GNU tar reads the file and then rewrites an
# updated version
cp -pi $old_file $new_file
fi
if [ -L $DIR/backup.meta ] ; then
rm -f $DIR/backup.prev.meta
mv $DIR/backup.meta $DIR/backup.prev.meta
fi
ln -s --force ${new_file##*/} $DIR/backup.meta