########################################################################
# #
# This software is part of the ast package #
# Copyright (c) 1994-2011 AT&T Intellectual Property #
# and is licensed under the #
# Eclipse Public License, Version 1.0 #
# by AT&T Intellectual Property #
# #
# A copy of the License is available at #
# (with md5 checksum b35adb5213ca9657e911e9befb180842) #
# #
# Information and Software Systems Research #
# AT&T Research #
# Florham Park NJ #
# #
# Glenn Fowler <gsf@research.att.com> #
# #
########################################################################
USAGE=$'
[-?
@(#)$Id: ditto (AT&T Labs Research) 2010-11-22 $
]
[+NAME?ditto - replicate directory hierarchies]
[+DESCRIPTION?\bditto\b replicates the \asource\a directory hierarchy
to the \adestination\a directory hierarchy. Both \asource\a and
\adestination\a may be of the form
[\auser\a@]][\ahost\a:]][\adirectory\a]]. At least one of
\ahost\a: or \adirectory\a must be specified. The current user is used
if \auser@\a is omitted, the local host is used if \ahost\a: is
omitted, and the user home directory is used if \adirectory\a is
omitted.]
[+?Remote hosts and files are accessed via \bssh\b(1) or \brsh\b(1). \bksh\b(1),
\bpax\b(1), and \btw\b(1) must be installed on the local and remote hosts.]
[+?For each source file \bditto\b does one of these actions:]{
file to match the source]
[+copy?copy the source file to the destination]
[+delete?delete the destination file]
[+skip?the destination file is not changed]
}
[+?The source and destination hierarchies are generated by \btw\b(1) with
the \b--logical\b option. An \b--expr\b option may
be specified to prune the search. The \btw\b searches are relative to
the \asource\a and \adestination\a directories.]
[c:checksum?Copy if the \btw\b(1) 32x4 checksum mismatches.]
[d:delete?Delete \adestination\a files that are not in the \asource\a.]
[e:expr?\btw\b(1) select expression.]:[tw-expression]
[m!:mode?Preserve file mode.]
[n:show?Show the operations but do not exectute.]
[o:owner?Preserve file user and group ownership.]
[p:physical?Generate source and destination hierarchies by \btw\b(1) with
the \b--physical\b option.]
[r:remote?The remote access protocol; either \bssh\b or
\brsh\b.]:[protocol:=ssh]
[u:update?Copy only if the \asource\a file is newer than the
\adestination\a file.]
[v:verbose?Trace the operations as they are executed.]
[D:debug?Enable the debug trace.]
source destination
[+SEE ALSO?\brdist\b(1), \brsync\b(1), \brsh\b(1), \bssh\b(1), \btw\b(1)]
'
;;
*) ARGV0=""
USAGE="de:[tw-expression]mnouvD source destination"
;;
esac
{
OPTIND=0
exit 2
}
{
id=$1
dir=$2
if [[ $dir == *@* ]]
then
else
user=
fi
if [[ $dir == *:* ]]
then
else
host=
fi
if [[ $user ]]
then
if [[ ! $host ]]
then
fi
fi
}
# initialize
# grab the options
d) delete=1 ;;
m) mode=0 ;;
o) owner=1 ;;
u) update=1 ;;
v) verbose=1 ;;
D) debug=1 ;;
*) usage ;;
esac
done
shift $OPTIND-1
if (( $# != 2 ))
then usage
fi
tw[ntw++]=--expr=\''action:printf("%d\t%d\t%s\t%s\t%s\t%-.1s\t%o\t%s\t%s\n", size, mtime, '$checksum', uid, gid, mode, perm, path, symlink);'\'
if (( exec ))
then
paxreadflags="$paxreadflags --read"
fi
then
paxreadflags="$paxreadflags --verbose"
fi
# start the source and destination path list generators
# the |& command may exit before the exec &p
# the print sync + read delays the |& until the exec &p finishes
if [[ $src_host ]]
then ($remote $src_user $src_host "{ test ! -f .profile || . ./.profile ;} && cd $src_dir && read && ${tw[*]}") 2>&1 |&
fi
exec 5<&p 7>&p
exec 7>&-
if [[ $dst_host ]]
then ($remote $dst_user $dst_host "{ test ! -f .profile || . ./.profile ;} && cd $dst_dir && read && ${tw[*]}") 2>&1 |&
fi
exec 6<&p 7>&p
exec 7>&-
# scan through the sorted path lists
if (( exec ))
then
src_skip=*
dst_skip=*
else
fi
IFS=$'\t'
while :
do
# get the next source path
then
then
then
continue
fi
then
break
then
exit 1
else
src_eof=1
fi
fi
# get the next destination path
then
then
then
continue
fi
then
break
then
exit 1
else
dst_eof=1
fi
fi
# determine the { cp rm chmod chown } ops
then
[[ $src_path ]] && print -r -u2 -f $': src %8s %10s %s %s %s %s %3s %s\n' $src_size $src_mtime $src_sum $src_uid $src_gid $src_type $src_perm "$src_path"
[[ $dst_path ]] && print -r -u2 -f $': dst %8s %10s %s %s %s %s %3s %s\n' $dst_size $dst_mtime $dst_sum $dst_uid $dst_gid $dst_type $dst_perm "$dst_path"
fi
then
then
then
if [[ $dst_type == d ]]
then
else
fi
fi
fi
if [[ $src_type == l ]]
then
then
fi
fi
elif [[ $src_type != d ]] && { (( update && src_mtime > dst_mtime )) || (( ! update )) && { (( src_size != dst_size )) || [[ $src_sum != $dst_sum ]] ;} ;}
then
if [[ $src_path != . ]]
then
then
fi
fi
else
then
then
fi
then
then
fi
fi
then
then
fi
fi
fi
then
if [[ $src_path != . ]]
then
then
if [[ $src_type == d ]]
then
else
fi
fi
fi
elif [[ $dst_path ]]
then
then
then
if [[ $dst_type == d ]]
then
else
fi
fi
fi
fi
done
(( exec )) || exit 0
# generate, transfer and execute the { rm chown chmod } script
if (( ${#rm[@]} || ${#chmod[@]} || ${#chown[@]} ))
then
{
then
print -r -- set -x
fi
n=0
do
if (( --n <= 0 ))
then
n=32
print
fi
print -nr -- " '$i'"
done
do
n=0
do
if (( --n <= 0 ))
then
n=32
print
fi
print -nr -- " $j"
done
done
do
n=0
do
if (( --n <= 0 ))
then
n=32
print
fi
print -nr -- " $j"
done
done
print
} | {
if (( ! exec ))
then
elif [[ $dst_host ]]
then
else
fi
}
fi
# generate, transfer and read back the { cp } tarball
if (( ${#cp[@]} ))
then
{
cd $src_dir &&
print -r -f $'%s\n' "${cp[@]}" |
} | {
if [[ $dst_host ]]
then
$remote $dst_user $dst_host "{ test ! -f .profile || . ./.profile ;} && { test -d \"$dst_dir\" || mkdir -p \"$dst_dir\" ;} && cd \"$dst_dir\" && gunzip | $pax $paxreadflags"
else
fi
}
wait
fi