#!/bin/sh
# combine multiple sfs (or directory) into one big SFS
# jamesbond 2024
# license: GPLv3

###
COMPTYPE=${COMPTYPE:-xz}
TMPDIR=${TMPDIR:-tmp}
WORKDIR=

### umount all if we are accidentally killed
trap 'umountall' 1
umountall() {
	if [ "$WORKDIR" ]; then
		umount -l $WORKDIR/*
		rmdir $WORKDIR/[0-9]*
		rm -r $WORKDIR/target
		rmdir $WORKDIR
	fi 2> /dev/null
}

###
help() {
	cat << EOF
${0##*/} [-comp comptype] source1 [ source2 ... ] target.sfs 
Combine one or more sources into a target SFS. Source can be SFS, or directory.
-comp specifies compression type. It can be xz, lzo, lz4, zstd; default is xz.

This script uses union filesystem to avoid copying, but if a suitable
union filesystem can't be found, a temporary copy has to be made and
the location of the temporary copy is specified by the environment
TMPDIR, currently set to $TMPDIR.

EOF
	exit
}

### cmdline
while [ $# -gt 0 ]; do
	case "$1" in
		-h|--help) help ;;
		-comp) shift; COMPTYPE="$1" ;;
		*) break ;;
	esac
	shift
done
[ $# -lt 2 ] && help # we need a minimum of 2 files (one source + one target)

### mount source sfs
WORKDIR=$(mktemp -d -p $TMPDIR combine.sfs.XXXXXXX)
SFSCOUNT=1
while [ $# -gt 1 ]; do
	p="$1"; shift;
	mnt=$WORKDIR/$(printf "%0.3d" $SFSCOUNT)
	mkdir -p $mnt
	if [ -d "$p" ]; then
		mount -o bind "$p" $mnt
	else
		mount "$p" $mnt
	fi || {
		printf "Unable to mount branch %0.3d : %s\n" $SFSCOUNT "$p"
		umountall
		exit
	}
	printf "Branch %0.3d : %s\n" $SFSCOUNT "$p"
	robranches=$robranches:$mnt
	: $(( SFSCOUNT++ ))
done
TARGET="$1"

### make target sfs
mkdir -p $WORKDIR/target

# ok, attempt to combine using aufs, overlay, unionfs, and finally plain copy (in that order)
echo "Copying sources to temporary location ..."
mount -t aufs aufs -obr$robranches $WORKDIR/target ||
mount -t overlay overlay -olowerdir=${robranches#:} $WORKDIR/target ||
unionfs -o cow -o hide_meta_files $robranches $WORKDIR/target ||
cp -a $WORKDIR/[0-9]*/* $WORKDIR/target || {
	echo "Cannot create combined image"
	umountall
	exit
}

mksquashfs $WORKDIR/target $TARGET -noappend -comp $COMPTYPE 
umountall
