#!/bin/sh -e
#
# 2018 Ander Punnar (ander-at-kvlt-dot-ee)
#
# This file is part of cdist.
#
# cdist is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# cdist is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#

file_is="$( cat "$__object/explorer/file_is" )"

[ "$file_is" = 'missing' ] && [ -z "$__cdist_dry_run" ] && exit 0

os="$( cat "$__global/explorer/os" )"

acl_path="/$__object_id"

acl_is="$( cat "$__object/explorer/acl_is" )"

if [ -f "$__object/parameter/acl" ]
then
    acl_should="$( cat "$__object/parameter/acl" )"
elif
    [ -f "$__object/parameter/user" ] \
        || [ -f "$__object/parameter/group" ] \
        || [ -f "$__object/parameter/mask" ] \
        || [ -f "$__object/parameter/other" ]
then
    acl_should="$( for param in user group mask other
    do
        [ ! -f "$__object/parameter/$param" ] && continue

        echo "$param" | grep -Eq 'mask|other' && sep=:: || sep=:

        echo "$param$sep$( cat "$__object/parameter/$param" )"
    done )"
else
    echo 'no parameters set' >&2
    exit 1
fi

if [ -f "$__object/parameter/default" ]
then
    acl_should="$( echo "$acl_should" \
        | sed 's/^default://' \
        | sort -u \
        | sed 's/\(.*\)/default:\1\n\1/' )"
fi

if [ "$file_is" = 'regular' ] \
    && echo "$acl_should" | grep -Eq '^default:'
then
    # only directories can have default ACLs,
    # but instead of error,
    # let's just remove default entries
    acl_should="$( echo "$acl_should" | grep -Ev '^default:' )"
fi

if echo "$acl_should" | awk -F: '{ print $NF }' | grep -Fq 'X'
then
    [ "$file_is" = 'directory' ] && rep=x || rep=-

    acl_should="$( echo "$acl_should" | sed "s/\\(.*\\)X/\\1$rep/" )"
fi

setfacl_exec='setfacl'

if [ -f "$__object/parameter/recursive" ]
then
    if echo "$os" | grep -Fq 'freebsd'
    then
        echo "$os setfacl do not support recursive operations" >&2
    else
        setfacl_exec="$setfacl_exec -R"
    fi
fi

if [ -f "$__object/parameter/remove" ]
then
    echo "$acl_is" | while read -r acl
    do
        # skip wanted ACL entries which already exist
        # and skip mask and other entries, because we
        # can't actually remove them, but only change.
        if echo "$acl_should" | grep -Eq "^$acl" \
            || echo "$acl" | grep -Eq '^(default:)?(mask|other)'
        then continue
        fi

        if echo "$os" | grep -Fq 'freebsd'
        then
            remove="$acl"
        else
            remove="$( echo "$acl" | sed 's/:...$//' )"
        fi

        echo "$setfacl_exec -x \"$remove\" \"$acl_path\""
        echo "removed '$remove'" >> "$__messages_out"
    done
fi

for acl in $acl_should
do
    if ! echo "$acl_is" | grep -Eq "^$acl"
    then
        if echo "$os" | grep -Fq 'freebsd' \
            && echo "$acl" | grep -Eq '^default:'
        then
            echo "setting default ACL in $os is currently not supported" >&2
        else
            echo "$setfacl_exec -m \"$acl\" \"$acl_path\""
            echo "added '$acl'" >> "$__messages_out"
        fi
    fi
done
