#!/bin/bash

sitepart=ftp.debian.org/debian
sitedir=`basename "$sitepart"`

#where we want to have just current stuff
target_dir=/var/local/pub/mirrored/"$sitepart"

#where we put older stuff
old_target_dir=/var/local/pub/old/mirrored/"$sitepart"

cwd=`/bin/pwd` || exit

cd "$target_dir" || exit
umask 022 || exit

#md5sums and relative pathnames for current stuff
md5sums_and_paths_for_current=`gzip -d < \`dirname "$target_dir"\`/indices/md5sums.gz`

[ X"$md5sums_and_paths_for_current" != X ] || exit 1

#unique md5sums only for current stuff
md5sums_for_current=`awk '{print $1;}' << __EOT__ |
$md5sums_and_paths_for_current
__EOT__
sort -u`

#remove symbolic links
#find .. -type l -exec rm \{\} \;

#md5sums and relative pathnames for stuff we have
md5sums_and_paths_for_what_we_have=`find .. -type f -exec md5sum \\{\\} \\; | sed -e 's/^\\([0-9a-f]\\{32\\}  \\)\\.\\.\\/'"$sitedir"'\\/\\(.*\\)$/\\1\\2/'`

#unique md5sums only for stuff we have
md5sums_for_what_we_have=`awk '{print $1;}' << __EOT__ |
$md5sums_and_paths_for_what_we_have
__EOT__
sort -u`

#unique md5sums only for stuff we have that's current
md5sums_for_current_we_have=`sort << __EOT__ |
$md5sums_for_current
$md5sums_for_what_we_have
__EOT__
sort |
uniq -d |
sed -e '/^$/d'`

#unique md5sums only for stuff we have that's not current
md5sums_for_non_current_we_have=`sort << __EOT__ |
$md5sums_for_what_we_have
$md5sums_for_current_we_have
__EOT__
sort |
uniq -u |
sed -e '/^$/d'`

#old relative paths for stuff we have that's not current,
#excluding reference index file itself
paths_for_non_current_we_have=`fgrep "$md5sums_for_non_current_we_have" << __EOT__ |
$md5sums_and_paths_for_what_we_have
__EOT__
awk '{print $2;}' |
fgrep -vx ../indices/md5sums.gz |
sed -e '/^$/d'`

#relocate non-current stuff
echo "$paths_for_non_current_we_have" |
while read tmp
do
	[ X"$tmp" != X ] || continue
	d=`dirname "$tmp"`
	[ -d "$old_target_dir/$d" ] ||
		mkdir -p "$old_target_dir/$d" && {
			mv "$tmp" "$old_target_dir/$tmp" || {
				cp -p "$tmp" "$old_target_dir/$tmp" &&
					cmp "$tmp" "$old_target_dir/$tmp" &&
						rm "$tmp"
			}
		}
done

md5sums_and_paths_for_current_paths_we_have=`fgrep "$md5sums_for_current_we_have" << __EOT__ |
$md5sums_and_paths_for_what_we_have
__EOT__
sort -u |
sed -e '/^$/d'`
md5sums_and_desired_paths_for_current_we_have=`fgrep "$md5sums_for_current_we_have" << __EOT__ |
$md5sums_and_paths_for_current
__EOT__
sort -u |
sed -e '/^$/d'`
md5sum_prior=
state_key_prior=
path_prior=
md5sum=
state_key=
path=
(
#md5sums and paths for current paths we have where path is obsolete
sort << __EOT__ |
$md5sums_and_paths_for_current_paths_we_have
$md5sums_and_desired_paths_for_current_we_have
$md5sums_and_desired_paths_for_current_we_have
__EOT__
uniq -u |
sed -ne 's/^[0-9a-f]\{32\}  /&0 /p'
#md5sums and paths already with correct paths
sort << __EOT__ |
$md5sums_and_paths_for_current_paths_we_have
$md5sums_and_desired_paths_for_current_we_have
__EOT__
uniq -d |
sed -ne 's/^[0-9a-f]\{32\}  /&1 /p'
#md5sums and desired paths for current we have but need to create path
sort << __EOT__ |
$md5sums_and_paths_for_current_paths_we_have
$md5sums_and_paths_for_current_paths_we_have
$md5sums_and_desired_paths_for_current_we_have
__EOT__
uniq -u |
sed -ne 's/^[0-9a-f]\{32\}  /&2 /p'
) |
(
sort -u
echo ''
) |
#fix paths on current stuff
#add missing paths
#remove bogus/old paths
while read md5sum state_key path
do
	if [ X"$md5sum_prior" = X"$md5sum" ]
	then
		case "$state_key_prior$state_key" in
			00)
				#find and remove the older obsolete path
				older=`ls -tr "$path" "$path_prior" | head -1`
				rm "$older" || exit 1
				case X"$older" in
					X"$path_prior")
						path_prior="$path"
					;;
					X"$path")
						#don't update path_prior
						:
					;;
					*)
						#should be unreachable
						1>&2 echo "$0: reached the unreachable:
md5sum_prior=$md5sum_prior state_key_prior=$state_key_prior path_prior=$path_prior 
md5sum=$md5sum state_key=$state_key path=$path"
						exit 1
					;;
				esac
			;;
			01)
				rm "$path_prior" || exit 1
				state_key_prior="$state_key"
				path_prior="$path"
			;;
			02)
				d=`dirname "$path"`
				[ -d "$d" ] ||
					mkdir -p "$d" && {
						mv "$path_prior" "$path" || {
							cp -p "$path_prior" "$path" &&
								cmp "$path_prior" "$path" &&
									rm "$path_prior"
						} || exit 1
					} || exit 1
				state_key_prior="$state_key"
				path_prior="$path"
			;;
			11)
				path_prior="$path"
			;;
			12)
				d=`dirname "$path"`
				[ -d "$d" ] ||
					mkdir -p "$d" && {
						ln "$path_prior" "$path" || {
							cp -p "$path_prior" "$path" &&
								cmp "$path_prior" "$path"
						} || exit 1
					} || exit 1
				state_key_prior="$state_key"
				path_prior="$path"
			;;
			22)
				d=`dirname "$path"`
				[ -d "$d" ] ||
					mkdir -p "$d" && {
						ln "$path_prior" "$path" || {
							cp -p "$path_prior" "$path" &&
								cmp "$path_prior" "$path"
						} || exit 1
					} || exit 1
				path_prior="$path"
			;;
			*)
				#should be unreachable #10 20 21 *
				1>&2 echo "$0: reached the unreachable:
md5sum_prior=$md5sum_prior state_key_prior=$state_key_prior path_prior=$path_prior 
md5sum=$md5sum state_key=$state_key path=$path"
				exit 1
			;;
		esac
	else
		if [ X"$md5sum" != X ]
		then
			case "$state_key_prior" in
				1|2)
					md5sum_prior="$md5sum"
					state_key_prior="$state_key"
					path_prior="$path"
				;;
				'')
					#this should be our first input line
					if [ X"$md5sum_prior$state_key_prior$path_prior" != X -o X"$md5sum" = X -o X"$state_key" = X -o X"$path" = X ]
					then
						#should be unreachable
						1>&2 echo "$0: reached the unreachable:
md5sum_prior=$md5sum_prior state_key_prior=$state_key_prior path_prior=$path_prior 
md5sum=$md5sum state_key=$state_key path=$path"
						exit 1
					fi
					md5sum_prior="$md5sum"
					state_key_prior="$state_key"
					path_prior="$path"
				;;
				*)
					#should be unreachable #0 *
					1>&2 echo "$0: reached the unreachable:
md5sum_prior=$md5sum_prior state_key_prior=$state_key_prior path_prior=$path_prior 
md5sum=$md5sum state_key=$state_key path=$path"
					exit 1
				;;
			esac
		else
			case "$state_key_prior" in
				1|2)
					#nothing to do at this point
					:
				;;
				*)
					#should be unreachable #0 *
					1>&2 echo "$0: reached the unreachable:
md5sum_prior=$md5sum_prior state_key_prior=$state_key_prior path_prior=$path_prior 
md5sum=$md5sum state_key=$state_key path=$path"
					exit 1
				;;
			esac
			break #we should be done with loop input processing - take us out of the loop
		fi
	fi
done

#clean out any old empty directories
2>>/dev/null find .. -type d ! -path .. ! -path ../"$sitedir" -depth -exec rmdir \{\} \;

#new stuff to possibly move in place
cd "$cwd" || exit
for tmp in "$@"
do
	[ -f "$tmp" ] || continue
	md5sum=`md5sum "$tmp" | awk '{print $1;}'`
	[ 33 -eq `expr X"$md5sum" : 'X[0-9a-f]\{32\}$'` ] || continue
	paths=`fgrep "$md5sum" << __EOT__ |
$md5sums_and_paths_for_current
__EOT__
awk '{print $2;}'`
	[ X"$paths" = X ] && continue
	chown root:staff "$tmp" || continue
	chmod 644 "$tmp" || continue
	l=0
	for tmp2 in $paths
	do
		d=`dirname "$tmp2"`
		[ ! -d "$target_dir/$d" ] && mkdir -p "$target_dir/$d"
		[ -d "$target_dir/$d" ] || break
		if [ $l -eq 0 ]
		then
			mv "$tmp" "$target_dir/$tmp2" || {
				cp -p "$tmp" "$target_dir/$tmp2" &&
					rm "$tmp" ||
						break
				}
			l=1
			p="$target_dir/$tmp2"
		else
			ln "$p" "$target_dir/$tmp2" || break
		fi
	done
done
