#!/bin/bash
# Author: B. Alcock <alcockba@educk.globalnet.co.uk>
# Date: 07/04/1999
# Name: fragfile
# Description: Fragments a specified file into files of the specified size
# Version: 1.0

# Set defaults
SIZE=5
UNIT=m

# Get value from cmdline option
get_param() {
	echo $1 | cut -d= -f2
}

# There has to be a better way!! Something like realpath(3) for shells
deref_link() {
	NEWFILE=$1
	while [ "$NEWFILE" != "" -a -L $NEWFILE ] ; do
		TEMP=`ls -l $NEWFILE | awk '{ print $11 }'`
		if [ "`echo $TEMP | cut -c 1`" != "/" ] ; then
			NEWFILE=`dirname $NEWFILE`/$TEMP
		else
			NEWFILE=$TEMP
		fi

		if ! [ -e $NEWFILE ] ; then
			NEWFILE=""
		fi
	done
	echo $NEWFILE
}


# Main script starts here
while [ "$#" != "0" ] ; do
	case $1 in
		--version)
			cat << EOF
File Fragmenter v1.0 - 07/04/1999
Author: B. Alcock <alcockba@educk.globalnet.co.uk>
This script is distributed under the terms of
the GNU General Public License.

EOF
			exit 0
			;;

		--help)
			cat << EOF
File Fragmenter v1.0 - 07/04/1999
Author: B. Alcock <alcockba@educk.globalnet.co.uk>
This script is distributed under the terms of
the GNU General Public License.

	--source=FILE		Gets data from the file specified by FILE.
	--dest=FILE		Writes the fragmented data into files
				beginning with the basename FILE. Files are
				appended with ".n", where n is the sequence
				number of the file. A file FILE.sum will be
				generated containing the checksums of all
				files.
	--size=SIZE		The number of units that the destination
				files will contain.
	--unit={b,k,m}		The units that SIZE is measured in.
					b = bytes
					k = kilobytes
					m = megabytes
	--version		Display version information
	--help			Display this text

EOF
		exit 0
		;;

		--source=*)
			SOURCE=`get_param $1`
			shift
			;;

		--size=*)
			SIZE=`get_param $1`
			shift
			;;

		--unit=[bkmBKM])
			UNIT=`get_param $1`
			shift
			;;

		--unit=*)
			echo "$0: Invalid unit value: `get_param $1`"
			exit 1
			;;

		--dest=*)
			DEST=`get_param $1`
			shift
			;;

		*)
			echo "$0: Invalid parameter: $1"
			exit 1
			;;
	esac
done

# --source option is required
if [ "$SOURCE" = "" ] ; then
	echo "$0: No source specified"
	exit 1
fi

# Default DEST = SOURCE
if [ "$DEST" = "" ] ; then
	DEST=$SOURCE
fi

# Make source point at a real file
if [ -L $SOURCE ] ; then
	NEW_SOURCE=`deref_link $SOURCE`
	if [ "$NEW_SOURCE" = "" ] ; then
		echo "$0: Error dereferencing link $SOURCE"
		exit 1
	fi
	SOURCE=$NEW_SOURCE
fi

# Check source is a file
if ! [ -b $SOURCE -o -c $SOURCE -o -f $SOURCE ] ; then
	echo "$0: Source must be either a regular, block or character file"
	exit 1
fi

# Check readability of source
if ! [ -r $SOURCE ] ; then
	echo "$0: Failed to read source file: $SOURCE"
	exit 1
fi

# Check writability of dest
if [ ! -w `dirname $DEST` ] ; then
	echo "$0: Destination directory not writable: `dirname $DEST`"
	exit 1
fi

# Set the real SIZE
case $UNIT in
	[bB])
		;;		

	[kK])
		SIZE=`expr $SIZE '*' 1024`
		;;

	[mM])
		SIZE=`expr $SIZE '*' 1048576`
		;;
esac

TOTAL_SIZE=`ls -l $SOURCE | awk '{ print $5 }'`
FRAGMENTS=`expr $TOTAL_SIZE '/' $SIZE`
if [ ! "`expr $TOTAL_SIZE '%' $SIZE`" = "0" ] ; then
	FRAGMENTS=`expr $FRAGMENTS '+' 1`
fi

rm -f $DEST.sum >/dev/null 2>&1
cksum $SOURCE >sum.$DEST

OFFSET=0
FRAG=1
while [ "`expr $FRAG '<=' $FRAGMENTS`" = "1" ]  ; do
	dd if=$SOURCE of=$DEST.$FRAG skip=$OFFSET bs=$SIZE count=1 >/dev/null 2>&1
	cksum $DEST.$FRAG >>sum.$DEST
	FRAG=`expr $FRAG '+' 1`
	OFFSET=`expr $OFFSET '+' 1`
done
