quilt-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Quilt-dev] Another shell re-write of backup-files.


From: Kaz Kylheku
Subject: [Quilt-dev] Another shell re-write of backup-files.
Date: Thu, 17 Mar 2011 18:26:27 -0700
User-agent: Roundcube Webmail/0.4


Hey everyone,

Recently I became interested in a quilt that consists only of shell scripts.

I did find Martin Quinson's script from 2007 in the list archives,
as well as Jan Delvare's followup.

Noting the performance problems inherent in launching numerous
utilities for each file that is processed, and also noting
remarks about the -z option being deprecated, I took a few
liberties and followed a different approach, leading to the following:

#!/bin/bash

#
# Shell script replacement for quilt's backup-files utility
# Proof-of-concept alpha code
# Mar 17, 2011
# Kaz Kylheku <address@hidden>
#

#
# Main concepts:
#
# - Goal is to avoid invoking a process for each file name
# - We use the CPIO utility for creating hard-linked backups; CPIO pass-through # mode can take list of names and create hard links (in pass-through mode). # - Use tree-to-tree recursive cp to restore a backup (taking everything
#   in the backup, ignoring the file list).
# - To touch files on restore, if requested, we can do a find + xargs + touch
#   over the backup instead, prior to restoring it.
# - Added files (i.e. backups of nonexistent files) are represented as a # specially named file containing an explicit list, and not as zero-length
#   files. This eases the implementation, and lets us back up/restore
#   zero-length files!
#

set -eu # bail on any errors, and unbound variable uses

opt_prefix=
opt_suffix=
opt_file=
opt_backup=
opt_restore=
opt_remove_backup=
opt_keep_backups=
opt_silent=
opt_touch=
opt_nolink=

usage()
{
cat <<!
Usage: $0 [-B prefix] [-f {file|-}] [-sktL] [-b|-r|-x] {file|-} ...

        Create hard linked backup copies of a list of files
        read from a file (or standard input), or from the
        argument list.

        -b      Create backup
        -r      Restore the backup
        -x      Remove backup files and empty parent directories
        -k      When doing a restore, keep the backup files
        -B      Path name prefix for backup files
        -z      Unsupported, obsolete option
        -s      Silent operation; only print error messages
        -f      Read the filenames to process from file (- = standard input)
        -t      Touch original files after restore (update their mtimes)

        -L      Ensure that when finished, the source file has a link count of 1
!
}

if ! options=`getopt -o B:f:brxkstLh -- "$@"` ; then
        usage
        exit 1
fi

eval set -- "$options"

while true
do
        case "$1" in
        -B)
                opt_prefix="$2"
                shift 2 ;;
       -f)
               opt_file="$2"
               shift 2 ;;
       -b)
               opt_backup=B
               shift ;;
       -r)
               opt_restore=R
               shift ;;
       -x)
               opt_remove_backup=D
               shift ;;
       -k)
               opt_keep_backups=y
               shift ;;
       -s)
               opt_silent=y
               shift ;;
       -t)
               opt_touch=y
               shift ;;
       -L)
               opt_nolink=y
               shift ;;
        -h)
                usage
                exit 0 ;;
        --)
                shift
                break ;;
        esac
done

if [ $# -eq 0 -a -z "$opt_file" ] ; then
        echo "Error: specify input file names as arguments or via -f option"
        echo
        usage
        exit 1
fi

if [ $# -ge 1 -a -n "$opt_file" ] ; then
        echo "Error: conflict: both -f and file name argument given"
        echo
        usage
        exit 1
fi

if [ $# -gt 1 -a "$1" == "-" ] ; then
        echo "Error: if - is specified, then no other arguments can be added"
        echo
        usage
        exit 1
fi


if [ -z "$opt_prefix" ] ; then
        echo "Error: specify backup/restore directory with -B"
        echo
        usage
        exit 1
fi

temp_list=$(mktemp "${TMP_DIR:-/tmp}/backup-files-tl-XXXXXX")
file_list=$(mktemp "${TMP_DIR:-/tmp}/backup-files-fl-XXXXXX")
noex_list=$(mktemp "${TMP_DIR:-/tmp}/backup-files-ne-XXXXXX")

cleanup()
{
        rm -f $temp_list $file_list $noex_list
}

trap cleanup exit

#
# capture the file list into the $temp_list file
#

if [ -n "$opt_file" -a "$opt_file" == "-" -o "$1" == "-" ] ; then
        cat > $temp_list
elif [ -n "$opt_file" ] ; then
        cat "$opt_file" > $temp_list
else
        # IFS trick. The string literal here contains a newline
        ( IFS="
"
          echo "$*" > $temp_list )
fi

#
# separate name list into existing and nonexisting
#

$file_list
$noex_list

while read name ; do
        if [ -e "$name" ] ; then
                echo "$name" >> $file_list
        else
                echo "$name" >> $noex_list
        fi
done < $temp_list

if [ $opt_silent ] ; then
        echo "$0: operating on these files:"
        cat $file_list
fi

case $opt_backup$opt_restore$opt_remove_backup in
B )
        if [ $opt_nolink ] ; then
                cpio --quiet -pd "$opt_prefix" < $file_list
        else
                cpio --quiet -pdl "$opt_prefix" < $file_list
        fi

        mv $noex_list "$opt_prefix/.#new-files#"

        ;;
R )
        if [ $opt_nolink ] ; then
                cp -a "$opt_prefix"/. .
        else
                if [ $opt_touch ] ; then
                        find "$opt_prefix" -type f | xargs touch
                fi

                cp -rlf "$opt_prefix"/. .
        fi

        if [ -z "$opt_keep_backups" ] ; then
                rm -rf "$opt_prefix"
        fi

        # Trick! .#new-files# list gets copied along with the files from
        # the backup directory to the working directory: we process
        # it and remove it.

        xargs rm -f < .#new-files#
        rm -f .#new-files#

        ;;
D )
        rm -rf "$opt_prefix"
        ;;
* )
        # either no operation was specified, or multiple operations
        # were been specified, like -b and -r.
        usage
        exit 1
        ;;
esac




reply via email to

[Prev in Thread] Current Thread [Next in Thread]