#!/bin/bash

. $(dirname $0)/../../include.rc
. $(dirname $0)/../../volume.rc
. $(dirname $0)/../../common-utils.rc

cleanup;

TEST glusterd
TEST pidof glusterd
TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1,2,3}
TEST $CLI volume set $V0 features.shard on
TEST $CLI volume set $V0 features.shard-block-size 4MB
TEST $CLI volume start $V0

TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0
TEST useradd -M test_user 2>/dev/null

# Create 3 files as root.
TEST touch $M0/foo
TEST touch $M0/bar
TEST touch $M0/baz
TEST touch $M0/qux
TEST mkdir $M0/dir

# Change ownership to non-root on foo and bar.
TEST chown test_user:test_user $M0/foo
TEST chown test_user:test_user $M0/bar

# Write 6M of data on foo as non-root, 2M overflowing into block-1.
TEST run_cmd_as_user test_user "dd if=/dev/zero of=$M0/foo bs=1M count=6"

# Ensure owner and group are root on the block-1 shard.
gfid_foo=$(get_gfid_string $M0/foo)

EXPECT "root" echo `find $B0 -name $gfid_foo.1 | xargs stat -c %U`
EXPECT "root" echo `find $B0 -name $gfid_foo.1 | xargs stat -c %G`

#Ensure /.shard is owned by root.
EXPECT "root" echo `find $B0/${V0}0 -name .shard | xargs stat -c %U`
EXPECT "root" echo `find $B0/${V0}0 -name .shard | xargs stat -c %G`
EXPECT "root" echo `find $B0/${V0}1 -name .shard | xargs stat -c %U`
EXPECT "root" echo `find $B0/${V0}1 -name .shard | xargs stat -c %G`
EXPECT "root" echo `find $B0/${V0}2 -name .shard | xargs stat -c %U`
EXPECT "root" echo `find $B0/${V0}2 -name .shard | xargs stat -c %G`
EXPECT "root" echo `find $B0/${V0}3 -name .shard | xargs stat -c %U`
EXPECT "root" echo `find $B0/${V0}3 -name .shard | xargs stat -c %G`

# Write 6M of data on bar as root.
TEST dd if=/dev/zero of=$M0/bar bs=1M count=6

# Ensure owner and group are root on the block-1 shard.
gfid_bar=$(get_gfid_string $M0/bar)

EXPECT "root" echo `find $B0 -name $gfid_bar.1 | xargs stat -c %U`
EXPECT "root" echo `find $B0 -name $gfid_bar.1 | xargs stat -c %G`

# Write 6M of data on baz as root.
TEST dd if=/dev/zero of=$M0/baz bs=1M count=6

gfid_baz=$(get_gfid_string $M0/baz)

# Ensure owner and group are root on the block-1 shard.
EXPECT "root" echo `find $B0 -name $gfid_baz.1 | xargs stat -c %U`
EXPECT "root" echo `find $B0 -name $gfid_baz.1 | xargs stat -c %G`

# Test to ensure unlink from an unauthorized user does not lead to only
# the shards under /.shard getting unlinked while that on the base file fails
# with EPERM/ACCES.

TEST ! run_cmd_as_user test_user "unlink $M0/baz"
TEST find $B0/*/.shard/$gfid_baz.1

# Test to ensure rename of a file where the dest file exists and is sharded,
# from an unauthorized user does not lead to only the shards under /.shard
# getting unlinked while that on the base file fails with EPERM/ACCES.

TEST ! run_cmd_as_user test_user "mv -f $M0/qux $M0/baz"
TEST find $B0/*/.shard/$gfid_baz.1
TEST stat $M0/qux

# Shard translator executes steps in the following order while doing a truncate
# to a lower size:
# 1) unlinking shards under /.shard first with frame->root->{uid,gid} being 0,
# 2) truncate the original file by the right amount.
# The following two tests are towards ensuring that truncate attempt from an
# unauthorised user doesn't result in only the shards under /.shard getting
# removed (since they're being performed as root) while step 2) above fails,
# leaving the file in an inconsistent state.

TEST ! run_cmd_as_user test_user "truncate -s 1M $M0/baz"
TEST find $B0/*/.shard/$gfid_baz.1

# Perform a cp as non-root user. This should trigger readv() which will trigger
# reads on first shard of "foo" under /.shard, and this must not fail if shard
# translator correctly sets frame->root->uid,gid to 0 before reading off the
# first shard, since it's owned by root.
TEST chown test_user:test_user $M0/dir
TEST run_cmd_as_user test_user "cp $M0/foo $M0/dir/quux"

md5sum_foo=$(md5sum $M0/foo | awk '{print $1}')
EXPECT "$md5sum_foo" echo `md5sum $M0/dir/quux | awk '{print $1}'`

userdel test_user

TEST $CLI volume stop $V0
TEST $CLI volume delete $V0

cleanup;
