#!/bin/bash
# barium helper scripts
# author: rosalinux.ru: betcher_

if [ -f $(dirname $0)/lib ] ;  then
    . $(dirname $0)/lib
else
    . $(which lib) || exit 1
fi

filter="$SYSMNT /tmp /var/tmp /var/log /var/spool /var/cache /run /root /boot /proc /sys /root /home"
changes=$(ls_union |head -n1)

mk_point () {
    echo "Create control point. Please wait..."
    [ "$ID" ] || ID=$(date +%H%M%S)
    dir=/tmp/barium_changes/$ID

    mkdir -p $dir
    mkdir -p $dir/ctlpoint
    : > $dir/ctlpoint.list
    : > $dir/ctlpoint.noreg

    for file in $(find $changes/) ; do
        if [ -f $file -o -d $file -o -L $file ]; then
            # Добавляем ведущий слеш при записи в список
            echo "/$(echo $file | sed "s:^$changes/::")" >> $dir/ctlpoint.list
        else
            echo "/$(echo $file | sed "s:^$changes/::")" >> $dir/ctlpoint.noreg
        fi
    done

    for file in $(cat $dir/ctlpoint.list) ; do
        # Убираем ведущий слеш для создания структуры каталогов
        file_without_slash=$(echo $file | sed 's:^/::')
        if [ -d "$changes/$file_without_slash" ] ; then
            mkdir -p $dir/ctlpoint/$file_without_slash
        else
            mkdir -p $dir/ctlpoint/$(dirname $file_without_slash)
            if [ -f "$changes/$file_without_slash" ] ; then
                md5sum "$changes/$file_without_slash" | cut -f1 -d ' ' > $dir/ctlpoint/$file_without_slash
            else
                cp -a "$changes/$file_without_slash" $dir/ctlpoint/$file_without_slash
            fi
        fi
    done
    echo "ID: $ID"
}

get_new () {
    echo "Processing directory \"$dir/new\""
    mkdir -p $dir/new
    : > $dir/new.list
    : > $dir/filtered.list

    for file in $(find $changes/) ; do
        if [ -f $file -o -d $file -o -L $file ]; then
            # Получаем путь с ведущим слешем
            file_with_slash="/$(echo $file | sed "s:^$changes/::")"

            # Проверяем фильтры (они уже с ведущим слешем)
            filtered=0
            for int in $filter ;do
                if echo "$file_with_slash" | grep -q "^$int"; then
                    echo "$file" >> $dir/filtered.list
                    filtered=1
                    break
                fi
            done

            # Если файл не под фильтр, проверяем, есть ли он в контрольной точке
            if [ "$filtered" -eq 0 ]; then
                if ! grep -q "^$file_with_slash\$" $dir/ctlpoint.list; then
                    echo $file >> $dir/new.list
                fi
            fi
        else
            file_with_slash="/$(echo $file | sed "s:^$changes/::")"
            if ! grep -q "^$file_with_slash\$" $dir/ctlpoint.noreg ; then
                echo $file >> $dir/new.noreg
            fi
        fi
    done

    echo "Finished creating files list. Copying files"
    # Очищаем каталог new перед копированием
    rm -rf $dir/new/*
    mkdir -p $dir/new

    for file in $(cat $dir/new.list) ; do
        dest_dir="$dir/new/$(dirname $file | sed "s:^$changes::")"
        mkdir -p "$dest_dir"
        cp -fax "$file" "$dest_dir/"
    done
}

get_removed () {
    echo "Processing \"removed\""
    : > $dir/removed.list
    for file in $(cat $dir/ctlpoint.list) ; do
        # Убираем ведущий слеш для проверки существования
        file_without_slash=$(echo $file | sed 's:^/::')
        [ ! -e "$changes/$file_without_slash" -a ! -L "$changes/$file_without_slash" ] && echo $file >> $dir/removed.list
    done
}

get_changed () {
    echo "Processing directory \"$dir/changed\""
    mkdir -p $dir/changed
    : > $dir/changed.list

    for file in $(find $changes -cnewer $dir/ctlpoint.list ) ; do
        if [ -f $file ]; then
            file_with_slash="/$(echo $file | sed "s:^$changes/::")"
            if grep -q "^$file_with_slash\$" $dir/ctlpoint.list; then
                new_md5=$(md5sum $file | cut -f1 -d ' ')
                old_md5=$(cat $dir/ctlpoint/$(echo $file | sed "s:^$changes/::"))
                [ "$new_md5" != "$old_md5" ] && echo $file >> $dir/changed.list
            fi
        fi
    done

    echo "Finished creating files list. Copying files"
    for file in $(cat $dir/changed.list) ; do
        mkdir -p $dir/changed/$(dirname $file | sed "s:^$changes::")
        cp -fax $file $dir/changed/$(dirname $file | sed "s:^$changes::")/
    done
}

get_whiteouts() {
    echo "Processing \"whiteouts\""
    : > $dir/whiteouts.list
    if [ $(check_union) == 'ovl' ]; then
        find $changes -cnewer $dir/ctlpoint.list  -perm 0000 | sed "s:^$changes:/:" >> $dir/whiteouts.list
    elif [ $(check_union) == 'aufs' ] ; then
        find $changes -cnewer $dir/ctlpoint.list  -name '*.wh.*' | sed "s:^$changes:/:" >> $dir/whiteouts.list
    fi
}

HELP () {
cat <<EOF
$0 - Tool to calculate diff of current changes and control point created earlye

Using:
$0                  create control point
$0 -d               calculate diff  of changes
$0 -d -m new -r     calculate diff, create module from new files, remove control point

Patameters:
  -h | --help               - this help
  -l | --ls | --list        - show list of control points
  -i | --ID                 - id for control point
  -p | --control-point      - create control point
  -r | --remove             - remove control point
  -d | --diff               - calculate diff
  -F | --filter             - set own filter instead internal
  -m | --mkmod (all)        - create module ID.xzm from changed and new files
  --mkmod new               - create module ID.xzm from new files
  --mkmod changed           - create module ID.xzm from changed files
EOF
exit
}

if [ ! "$1" ] ; then
    mkpoint='yes'
else
    while [ -n "$1" ] ; do
        case $1 in
            '-h' | '--help' ) HELP ;;
            '-l' | "--ls" | "--list" )  ls -1 /tmp/barium_changes/
                                        exit ;;
            '-R' | '--remove-all' ) rm -rf '/tmp/barium_changes'
                                    exit ;;
            '-i' | '--ID' ) shift ; ID="$1" ;;
            '-p' | '--control-point' ) mkpoint='yes' ;;
            '-r' | '--remove' ) REMOVE='yes' ;;
            '-d' | '--diff' ) DIFF='yes' ;;
            '-F' | '--filter') shift ; filter="$1" ;;
            '-m' | '--mkmod')   if [ "$2" ] && [ "${2:0:1}" != '-' ] ; then
                                    MKMOD="$2"
                                    shift
                                else
                                    MKMOD='all'
                                fi ;;
            '-*')   echo "$(basename "$0"): invalid option ${1}"
                    exit ${LINENO} ;;
            *)  [ $ID ] || ID="$1";;
        esac
        shift
    done
fi

if [ "$mkpoint" == "yes" ] ; then
    mk_point
    exit $?
fi

if [ ! "$ID" ] ; then
    ID=$(ls -1 /tmp/barium_changes/)
    if [ $(echo "$ID" | wc -l) -gt 1 ] ; then
        echo "Please specify control point ID:"
        echo "$ID"
        exit ${LINENO}
    fi
fi

dir="/tmp/barium_changes/$ID"
if ! [ -d "/tmp/barium_changes/$ID" ] ; then
    echo -e "Unknown ID: $ID\nselect one from:"
    ls -1 /tmp/barium_changes
    exit ${LINENO}
fi

if [ "$DIFF" ] ; then
    : > $dir/new.list
    : > $dir/new.noreg
    : > $dir/changed.list
    : > $dir/filtered.list
    rm -rf "$dir/new"
    rm -rf "$dir/changed"
    get_new
    get_changed
    get_whiteouts
    get_removed
    echo "See: $dir"
fi

if [ "$MKMOD" ] ; then
    if [ -d "${dir}/new" ] && [ -d "${dir}/changed" ] ; then
        if [ "$MKMOD" == 'new' ] ; then
            mksquashfs ${dir}/new "${ID}.$EXT" ${SQFSOPT}  -noappend
        elif  [ "$MKMOD" == 'changed' ] ; then
            mksquashfs ${dir}/new "${ID}.$EXT" ${SQFSOPT}  -noappend
        elif  [ "$MKMOD" == 'all' ] ; then
            barium mkmod -o "${ID}.$EXT" ${dir}/new ${dir}/changed
            if [ -s "$dir/whiteouts.list" ] || [ -s "$dir/removed.list" ] ; then
                union=$(check_union)
                echo ==========================================================================
                echo "Warning!
One of source directories for module ${ID}.$EXT contains $union whiteouts,
or some files from $changes have been removed by the current system changes.
Module: ${ID}.$EXT - may not work properly! !
You can try:
    $0 --mkmod new
or / and
    $0 --mkmod changed
because merged (new + changed) modules have no $union whiteouts."
                echo ==========================================================================
            fi
        else
            echo "Unknown value for --mkmod: $MKMOD"
            exit ${LINENO}
        fi
    else
        echo "Please calculate diff first"
    fi
    [ -f "${ID}.$EXT" ] && echo "$(realpath ${ID}.$EXT)"
fi

[ "$REMOVE" ] && rm -rf "$dir"
