#!/usr/bin/env bash
# aufs-diff
# Author: lcpterid, 2026
# License: GPL v3

prog_name="$(basename "$0")"
stack_maker_prog="aufs-list"
nu="[0-9]"
help_text="Syntax: $prog_name [-bn,m] path_to_check

Checks for multiple versions of a file in different AUFS branches,
and if two or more are present, displays the diff between them.

Options:
-bn,m: prints diff from branch n to branch m. If omitted,
       we will use the top two branches in the stack.
       Find branch numbers in the output of $stack_maker_prog.
"

script_dir="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &>/dev/null && pwd )"
lib_path="$(realpath -m "${script_dir}/../lib/libaufs-dir-tools")"
if ! [ -x "$lib_path" ]; then
       echo "Couldn't find library file!" >&2
       exit 1
fi
. "$lib_path"

[ "$#" -eq 0 ] && error_quit 1 ""

if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
	show_help
	exit 0
fi

which "$stack_maker_prog" >/dev/null || error_quit 3 "could not find $stack_maker_prog executable."
mount_check || error_quit 2 "AUFS mounts do not match requirements. This tool requires one AUFS branch system, mounted on root (/) and optionally sub-mounted elsewhere."
branch_files_check || error_quit 2 "could not find AUFS branch files in /sys/fs/. Are you on an AUFS file system?"

custom_branches="no"

while getopts ":hb:" thisopt; do
	case $thisopt in
		h)
			error_quit 0 ""
			;;
		b)
			branch_numbers="$OPTARG"
			if ! [[ "$branch_numbers" =~ ^$nu+,$nu+$ ]]; then
				error_quit 1 "$prog_name: error: -b option provided with no branch numbers" >&2
			else
				custom_branches="yes"
				branch_from="${branch_numbers%,*}"
				branch_to="${branch_numbers#*,}"
			fi
			;;
		:)
			error_quit 1 "$prog_name: error: -b option provided with no branch numbers" >&2
			;;
		?)
			error_quit 1 "$prog_name: error: invalid option -$OPTARG" >&2
			;;
	esac
done

shift $(( OPTIND - 1 ))

[ -z "$1" ] && error_quit 1 "no path_to_check provided"
[ -f "$1" ] || error_quit 2 "could not find the file at $1"

aufs_folder_check "$1" || error_quit 3 "Path $1 is not in the AUFS filesystem"

file_to_check="$1"

stack_raw=$($stack_maker_prog "$file_to_check") || error_quit 5 "$stack_maker_prog returned error code $? for file $file_to_check"
stack_linecount=$(echo "$stack_raw" | wc -l)

if [ "$stack_linecount" -lt 2 ]; then
	error_quit 5 "could not find multiple versions of file $file_to_check"
fi

stack_nums=$(echo "$stack_raw" | cut -f 1)

if [ "$custom_branches" = "yes" ]; then
	if [ -z "$(echo "$stack_nums" | grep "^ *${branch_from}$")" ]; then
		error_quit 4 "file does not exist in from branch $branch_from"
	elif [ -z "$(echo "$stack_nums" | grep "^ *${branch_to}$")" ]; then
		error_quit 4 "file does not exist in to branch $branch_to"
	fi
	fromfile="$(echo "$stack_raw" | grep "^ *${branch_from}[^0-9]" | cut -f 3)"
	tofile="$(echo "$stack_raw" | grep "^ *${branch_to}[^0-9]" | cut -f 3)"
else
	fromfile="$(echo "$stack_raw" | sed -n "2p" | cut -f 3)"
	tofile="$(echo "$stack_raw" | sed -n "1p" | cut -f 3)"
fi

if ! [ -f "$fromfile" ]; then
	error_quit 6 "$fromfile is not a regular file"
elif ! [ -f "$tofile" ]; then
	error_quit 6 "$tofile is not a regular file"
else
	diff --color "$fromfile" "$tofile"
fi

