--- /dev/null
+#!/bin/bash
+
+#########################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the version 3 of the GNU General Public License #
+# as published by the Free Software Foundation. #
+# #
+# This program 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 #
+# General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+# Written by and Copyright (C) Francois Fleuret #
+# Contact <francois.fleuret@idiap.ch> for comments & bug reports #
+#########################################################################
+
+# This script takes two filenames as arguments, mounts them as luks
+# volumes, and synchronizes their contents.
+
+# IT CHANGES THE CONTENT OF THE SECOND ARGUMENT
+
+set -e
+set -o pipefail
+
+if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
+ cat <<EOF
+Usage: rsync-luks.sh <source file> <dest file>
+
+Mounts both files as LUKS volume and rsync the source to the dest. It
+first performs a dry-run and then asks for interactive confirmation
+before synchronizing for real.
+
+Comments and bug reports to francois@fleuret.org
+
+EOF
+ exit 0
+fi
+
+[ -f "$1" ] && [ -f "$2" ] || (echo "$0 <source> <dest>" >&2 && exit 1)
+
+[ -e "/dev/mapper/crypt-src" ] && (echo "/dev/mapper/crypt-src already exists." >&2 && exit 1)
+
+[ -e "/dev/mapper/crypt-dst" ] && (echo "/dev/mapper/crypt-dst already exists." >&2 && exit 1)
+
+function exit_handler () {
+
+ [ -n "${VOL_SRC+yes}" ] && umount "${VOL_SRC}" && rmdir "${VOL_SRC}" && unset VOL_SRC
+ [ -e "/dev/mapper/crypt-src" ] && cryptsetup luksClose crypt-src
+ [ -n "${LOOP_SRC+yes}" ] && losetup -d "${LOOP_SRC}" && unset LOOP_SRC
+
+ [ -n "${VOL_DST+yes}" ] && umount "${VOL_DST}" && rmdir "${VOL_DST}" && unset VOL_DST
+ [ -e "/dev/mapper/crypt-dst" ] && cryptsetup luksClose crypt-dst
+ [ -n "${LOOP_DST+yes}" ] && losetup -d "${LOOP_DST}" && unset LOOP_DST
+
+}
+
+trap exit_handler EXIT SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+
+######################################################################
+# Mount the volumes
+
+LOOP_SRC="$(losetup -f)"
+losetup "${LOOP_SRC}" "$1"
+cryptsetup luksOpen "${LOOP_SRC}" crypt-src
+VOL_SRC="$(mktemp -d /tmp/sync-luks.XXXXXX)"
+mount /dev/mapper/crypt-src "${VOL_SRC}"
+
+LOOP_DST="$(losetup -f)"
+losetup "${LOOP_DST}" "$2"
+cryptsetup luksOpen "${LOOP_DST}" crypt-dst
+VOL_DST="$(mktemp -d /tmp/sync-luks.XXXXXX)"
+mount /dev/mapper/crypt-dst "${VOL_DST}"
+
+######################################################################
+# First, show the changes
+
+echo "**********************************************************************"
+echo "* Dry-run"
+
+rsync -n --itemize-changes --delete --progress -axz "${VOL_SRC}/" "${VOL_DST}/"
+
+######################################################################
+# Ask for confirmation and synchronize
+
+echo "**********************************************************************"
+echo "* Synchronize [y]/N ?"
+
+read -n 1 KEY
+
+if [ "${KEY}" == "y" ]; then
+ rsync --itemize-changes --delete --progress -axz "${VOL_SRC}/" "${VOL_DST}/"
+else
+ echo "No synchronization."
+fi
+
+######################################################################
+
+echo "**********************************************************************"