diff options
author | Einhard Leichtfuß <alguien@respiranto.de> | 2019-10-18 00:28:00 +0200 |
---|---|---|
committer | Einhard Leichtfuß <alguien@respiranto.de> | 2019-10-18 01:17:39 +0200 |
commit | 4e2ceb9875c81c33b09f6eaf0858b7f9591b22cc (patch) | |
tree | be3860dc8c26b3c18a30c2a81b58e00025b98069 /destination | |
parent | 51f58d7c4c984ec8ccc5ab0a3d31d04cd39d499c (diff) |
A notable problem (to me) with the former version was, that upon simple
movements in the source file tree, these would in general cause
duplicated data in the backup forest. This problem has been resolved
by essentially tracking file movements, using hard links.
Also, the code has been divided into several different files, extranous
code removed, the organization of remote code execution simplified.
In the process of simplification, all parts requiring direct interaction
of the user with the program have been replaced. In most cases, this
means that the program now just terminates with an error instead of
allowing the user to confirm deletion of an unexpected (remnant) file.
This may be considered a drawback, but actually these interactive
options were anyways suboptimal solutions in most cases - where they
occured, which was due to remnant files of aborted or failed former
backups.
In general, there have been a lot of changes. Which are not thoroughly
documented here. Since there is often no strong relation to the old
code, this is not deemed necessary, as the in-code documentation is
expected to be of sufficient help.
Also, there has been added a little general documentation in the README
and particularly the NOTES file.
It is to be noted that this new version is far from sophisticated. It
has been tested with and is in use for real data, however lacks a lot of
convenience. In particular, if a backup fails unexpectedly, the next
backup will in the very most cases loudly fail without manual
intervention. Also, the program is not able to continue the growth of a
backup tree built with former versions of this program, by itself. This
can however be arranged by hand.
Diffstat (limited to 'destination')
-rw-r--r-- | destination | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/destination b/destination new file mode 100644 index 0000000..4829838 --- /dev/null +++ b/destination @@ -0,0 +1,169 @@ +#!/usr/bin/env bash +# +# destination - functions acting on the destination host. +# +# Copyright 2015 - 2019 Einhard Leichtfuß +# +# This file is part of rsync-backup. +# +# rsync-backup is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# rsync-backup is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with rsync-backup. If not, see <https://www.gnu.org/licenses/>. +# + + +# Setup working directory on the destination files system. +# +# requires: create_new_dir +# +function dest_prepare_initial +{ + create_new_dir "$dest_path" || return $? + create_new_dir "${dest_path}/work" || return $? + + return $RET_SUCCESS +} + + +# Setup working directory on the destination file system, check for too new +# (future) backups and refresh the 'latest' symlink. +# +# requires: assert_is_dir, dest_list_backup_dirs, create_new_dir +# $dest_path +# +# $1: old date: date in $DATEFMT +# $2: new date: date in $DATEFMT +# +function dest_prepare_incremental +{ + local work_dir="${dest_path}/work" + local old_date="$1" + local new_date="$2" + local latest + + assert_is_dir "$dest_path" || return $? + + latest="$(dest_list_backup_dirs | tail -1)" + + if [[ "$old_date" != "$latest" ]] + then + error "Dates of last backup do not match on source and destination." + debug_error "source: ${old_date} | dest: ${latest}" + return $RET_FILE_ERR + fi + + if ! [[ "$latest" < "$new_date" ]] + then + error "Latest backup on destination not older than source." + return $RET_FILE_ERR + fi + + # Refresh 'latest' symlink in case it was obsoleted or corrupted. + ln -sfT "$latest" "${dest_path}/latest" || return $RET_ERROR + + create_new_dir "$work_dir" || return $? + + return $RET_SUCCESS +} + + +# Finalize the backup creation on the destination host. +# +# requires: dest_refresh_symlinks +# `-> assert_is_dir, dest_list_backup_dirs, +# replace_symlink_target, create_dir +# $dest_path (self, <- dest_refresh_symlinks), +# +# $1: old date: date in $DATEFMT +# $2: new date: date in $DATEFMT +# +function dest_finalize +{ + local old_date="$1" + local new_date="$2" + + message "Finish installment of new backup..." + mv -T "${dest_path}/work/${new_date}" "${dest_path}/${new_date}" \ + || return $RET_ERROR + + message "Remove auxiliary directory tree..." + rm -rf "${dest_path}/work/${old_date}" || return $RET_ERROR + rmdir "${dest_path}/work" || return $RET_ERROR + + dest_refresh_symlinks || return $? + + message 'Successfully finished installment of new backup.' +} + + +# Print existing backup directories. +# Must be run on destination host. +# +# requires: $dest_path +# +function dest_list_backup_dirs +{ + find "$dest_path" -mindepth 1 -maxdepth 1 -type d \ + -regextype posix-extended -regex \ + '.*/[0-9]{4}-[0-1][0-9]-[0-3][0-9]_[0-2][0-9]([0-5][0-9]){2}' \ + -printf '%f\n' \ + | LC_ALL=C sort + + if [[ ${PIPESTATUS[0]} -eq 0 && ${PIPESTATUS[1]} -eq 0 ]] + then + return $RET_SUCCESS + else + return $RET_ERROR + fi +} + + +# Create symbolic links to backup directories. +# +# requires: assert_is_dir, dest_list_backup_dirs, replace_symlink_target, +# create_dir +# $dest_path +# +function dest_refresh_symlinks +{ + local -i i + local -i n + local -a backup_dirs + local link + local ret + + assert_is_dir "$dest_path" || return $? + + backup_dirs=( $(dest_list_backup_dirs || return $?) ) + n=${#backup_dirs[@]} + + replace_symlink_target "${dest_path}/latest" "${backup_dirs[n-1]}" \ + || return $? + + ## by_number + numdir="${dest_path}/by_number" + create_dir "$numdir" || return $? + + # Remove old symlinks. + find "$numdir" -mindepth 1 -maxdepth 1 -type l -regextype posix-extended \ + -regex '.*/[0-9]*' -delete || return $RET_ERROR + + for (( i = 0; i < n; i++ )) + do + ln -s "../${backup_dirs[i]}" "$(printf "%s/%.${#n}u" "$numdir" $i)" \ + || return $RET_FILE_ERR + done + + return $RET_SUCCESS +} + +# vi: ft=bash ts=2 sw=2 noet |