#! /bin/sh

#
# babarchive_check_one
#
# Copyright (C) 2001-2016 by John Heidemann  <johnh@isi.edu>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License.
#
#    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, write to the Free Software Foundation, Inc.,
#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#

PROG=$0

usage () {
    cat 1>&2 <<END
usage: $PROG [DIR...]

Babarchive_check_one checks a babarchive (a babarchive-checksumed directory tree),
verifying that all files match the archive's checksum.

Default location to check: the current directory.

Outputs a line for each valid file, or nothing if -q for quiet.

END
    exit 1
}

die () {
	echo "$PROG: $@" 1>&2
	exit 1
}
# pick up jdb
PATH=$PATH:/home/johnh/BIN/DB

test "x$1" = 'x-?' && usage

alg=auto
algprog=""
algargs=""
algneedsbinarystar=''
algprefix=auto
algsuffix=auto
debug=false
quiet=false
while getopts a:dq ch
do
        case $ch in
        a) alg=$OPTARG;;
        d) debug=true;;
        q) quiet=true;;
        *) usage;;
        esac
done
shift `expr $OPTIND - 1`

case x$alg in
	xmd5)
		alg=md5; algprog=md5sum; algargs=""; algprefix=md5; algsuffix=jdb;;
	xsha1|x1)
		alg=1; algprog=sha1sum; algargs=""; algprefix=sha1; algsuffix=jdb;;
	xsha256|x256)
		alg=256; algprog=shasum; algargs="--binary -a $alg"; algneedsbinarystar='*'; algprefix=sha; algsuffix=fsdb;;
	xauto)
		:
		;;
	*)
		die "unknown algorithm $alg"
		;;
esac


maybe_suppress_ok () {
	if $quiet
	then
		grep -v OK
	else
		cat
	fi
}

determine_algorithm_from_file() {
	if test -f .shasum.fsdb
	then
		echo 'alg=256; algprog=shasum; algargs="--binary -a 256"; algneedsbinarystar='*'; algprefix=sha; algsuffix=fsdb'
	elif test -f .sha1sum.jdb
	then
	     	echo 'alg=1; algprog=sha1sum; algargs=""; algprefix=sha1; algsuffix=jdb'
	elif test -f .md5sum.jdb
	then
	     	echo 'alg=md5; algprog=md5sum; algargs=""; algprefix=md5; algsuffix=jdb'
	else
		die "cannot automatically determine algorithm; specify it with -a sha1"
	fi

}

extract_field() {
	# 0-origin field number is in argument
	perl -ape 'print $F['$1'] . "\n";'
		
}

check_archive () {
	dir=$1
	cd $dir || die "cannot cd $dir"
	test "x$alg" = xauto && eval `determine_algorithm_from_file`
	test -f .${algprefix}sum.${algsuffix} || die "cannot find $dir/.${algprefix}sum.${algsuffix}"
	test -f ls-lR && {
		#this is a little messy: we want to check that directory
		#+contents matches ls-lR file, but we want to ignore
		#+timestamps and permissions and such; note that we may
		#+not be able to write to '.' (as in read-only media), so
		#+we have to use /tmp

		#recreate a new ls-lR file, but filter out ls-lR files
		local new_lslR=`mktemp /tmp/babarchive_check_one.ls-lR.XXXXXX`
		test "x$new_lslR" = x && die "Cannot create temp file under /tmp"
		ls -lR | grep -v 'ls-lR$' | grep -v '^total'  >$new_lslR

		#re-create dir contents (only file names, ignore timestamps)
		local fold=$new_lslR.old
		local fnew=$new_lslR.new
		< $new_lslR extract_field 8 | sort >$fnew
		< ls-lR extract_field 8 | sort >$fold 
		diff=`diff -bu $fold $fnew | 
			grep '^[+-]' | 
			grep -v "^[+-]* $new_lslR" |
			grep -v '^[+-]*ls-lR'`
		rm -f $fold $fnew $new_lslR
		test -z "$diff" || {
		    	echo "WARNING: directory $PWD has been updated:" >&2
			echo "$diff" >&2
		}
	}
	# was dbcol ${alg} path <.${alg}sum.jdb
	# but dbcol was removed to avoid dependency on fsdb.
	<.${algprefix}sum.${algsuffix} \
		perl -pe 's/^([^\t]+)\t([^\t]+)\t(.*)$/$1 '${algneedsbinarystar}'$3/;' |
		grep -v '^#' |
		grep -v '\.'${algprefix}'sum.'${algsuffix}'$' |
		${algprog} ${algargs} --check \
		$QUIETNESS | 
		maybe_suppress_ok
	$quiet && {
		if test $? = 0 
		then
			echo "$dir OK"
		else
			echo "$dir BAD"
		fi
	}
}

if test $# -eq 0
then
	check_archive .
else
	for i in $@
	do
	(
		check_archive $i
	)
done
fi

exit 0
