#!/usr/bin/env bash # # Blackbox test for shadow_copy2 VFS. # if [ $# -lt 7 ]; then cat < $destdir/foo mkdir -p $destdir/bar echo "$content" > $destdir/bar/baz echo "$content" > $destdir/bar/lfoo echo "$content" > $destdir/bar/letcpasswd echo "$content" > $destdir/bar/loutside elif [ "$version" = "fullsnap" ] ; then #snapshot files echo "$content" > $destdir/foo mkdir -p $destdir/bar echo "$content" > $destdir/bar/baz ln -fs ../foo $destdir/bar/lfoo ln -fs /etc/passwd $destdir/bar/letcpasswd ln -fs ../../outside $destdir/bar/loutside echo "$content" > `dirname $destdir`/outside else #subshare snapshot - at bar echo "$content" > $destdir/baz ln -fs ../foo $destdir/lfoo ln -fs /etc/passwd $destdir/letcpasswd ln -fs ../../outside $destdir/loutside echo "$content" > `dirname $destdir`/../outside fi } # build a snapshots directory build_snapshots() { local where #where to build snapshots local prefix #prefix from snapshot dir to share root local start #timestamp index of first snapshot local end #timestamp index of last snapshot local sub #creat a snapshot of subtree of share local snapdir local snapname local i local version where=$1 prefix=$2 start=$3 end=$4 sub=$5 snapdir=$where/.snapshots mkdir -p $snapdir version="fullsnap" if [ "$sub" = "1" ] ; then version="subsnap" prefix="" # a valid link target for an inner symlink - # the link is not broken yet should be blocked # by wide link checks touch $snapdir/foo fi for i in `seq $start $end` ; do snapname=${SNAPSHOTS[$i]} mkdir $snapdir/$snapname build_files $snapdir/$snapname "$prefix" $version "$snapname" done } # Test listing previous versions of a file test_count_versions() { local share local path local expected_count local skip_content local versions local tstamps local tstamp local content local is_dir share=$1 path=$2 expected_count=$3 skip_content=$4 versions=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | grep "^create_time:" | wc -l` if [ "$versions" != "$expected_count" ] ; then echo "expected $expected_count versions of $path, got $versions" return 1 fi is_dir=0 $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | grep "^attributes:.*D" && is_dir=1 if [ $is_dir = 1 ] ; then skip_content=1 fi #readable snapshots tstamps=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | awk '/^@GMT-/ {snapshot=$1} /^create_time:/ {printf "%s\n", snapshot}'` for tstamp in $tstamps ; do if [ $is_dir = 0 ] ; then if ! $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "get $tstamp\\$path $WORKDIR/foo" ; then echo "Failed getting \\\\$SERVER\\$share\\$tstamp\\$path" return 1 fi else if ! $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "ls $tstamp\\$path\\*" ; then echo "Failed listing \\\\$SERVER\\$share\\$tstamp\\$path" return 1 fi fi #also check the content, but not for wide links if [ "x$skip_content" != "x1" ] ; then content=`cat $WORKDIR/foo` if [ "$content" != "$tstamp" ] ; then echo "incorrect content of \\\\$SERVER\\$share\\$tstamp\\$path expected [$tstamp] got [$content]" return 1 fi fi done #non-readable snapshots tstamps=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | \ awk '/^@GMT-/ {if (snapshot!=""){printf "%s\n", snapshot} ; snapshot=$1} /^create_time:/ {snapshot=""} END {if (snapshot!=""){printf "%s\n", snapshot}}'` for tstamp in $tstamps ; do if [ $is_dir = 0 ] ; then if $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "get $tstamp\\$path $WORKDIR/foo" ; then echo "Unexpected success getting \\\\$SERVER\\$share\\$tstamp\\$path" return 1 fi else if $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "ls $tstamp\\$path\\*" ; then echo "Unexpected success listing \\\\$SERVER\\$share\\$tstamp\\$path" return 1 fi fi done } # Test fetching a previous version of a file test_fetch_snap_file() { local share local path local snapidx share=$1 path=$2 snapidx=$3 $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP \ -c "get ${SNAPSHOTS[$snapidx]}/$path $WORKDIR/foo" } # Test fetching a previous version of a file test_fetch_snap_dir() { local share local path local snapidx share=$1 path=$2 snapidx=$3 # This first command is not strictly needed, but it causes the snapshots to # appear in a network trace which helps debugging... $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP \ -c "allinfo $path" $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP \ -c "ls ${SNAPSHOTS[$snapidx]}/$path/*" } test_shadow_copy_fixed() { local share #share to contact local where #where to place snapshots local prefix #prefix to files inside snapshot local msg local allow_wl local ncopies_allowd local ncopies_blocked share=$1 where=$2 prefix=$3 msg=$4 allow_wl=$5 ncopies_allowed=4 ncopies_blocked=1 if [ -n "$allow_wl" ] ; then ncopies_blocked=4 fi #delete snapshots from previous tests find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1 build_snapshots $WORKDIR/$where "$prefix" 0 2 testit "$msg - regular file" \ test_count_versions $share foo $ncopies_allowed || \ failed=`expr $failed + 1` testit "$msg - regular file in subdir" \ test_count_versions $share bar/baz $ncopies_allowed || \ failed=`expr $failed + 1` testit "$msg - regular file in case insensitive subdir" \ test_count_versions $share bar/bAz $ncopies_allowed || \ failed=`expr $failed + 1` testit "$msg - local symlink" \ test_count_versions $share bar/lfoo $ncopies_allowed || \ failed=`expr $failed + 1` testit "$msg - abs symlink outside" \ test_count_versions $share bar/letcpasswd $ncopies_blocked 1 || \ failed=`expr $failed + 1` testit "$msg - rel symlink outside" \ test_count_versions $share bar/loutside $ncopies_blocked 1 || \ failed=`expr $failed + 1` testit "$msg - list directory" \ test_count_versions $share bar $ncopies_allowed || \ failed=`expr $failed + 1` } test_shadow_copy_everywhere() { local share #share to contact share=$1 #delete snapshots from previous tests find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1 build_snapshots "$WORKDIR/mount" "base/share" 0 0 build_snapshots "$WORKDIR/mount/base" "share" 1 2 build_snapshots "$WORKDIR/mount/base/share" "" 3 5 build_snapshots "$WORKDIR/mount/base/share/bar" "" 6 9 1 testit "snapshots in each dir - regular file" \ test_count_versions $share foo 4 || \ failed=`expr $failed + 1` testit "snapshots in each dir - regular file in subdir" \ test_count_versions $share bar/baz 5 || \ failed=`expr $failed + 1` testit "snapshots in each dir - local symlink (but outside snapshot)" \ test_count_versions $share bar/lfoo 1 || \ failed=`expr $failed + 1` testit "snapshots in each dir - abs symlink outside" \ test_count_versions $share bar/letcpasswd 1 || \ failed=`expr $failed + 1` testit "snapshots in each dir - rel symlink outside" \ test_count_versions $share bar/loutside 1 || \ failed=`expr $failed + 1` #the previous versions of the file bar/lfoo points to are outside its #snapshot, and are not reachable. However, but previous versions #taken at different, non-overlapping times higher up the #hierarchy are still reachable. testit "fetch a previous version of a regular file" \ test_fetch_snap_file $share "bar/baz" 6 || \ failed=`expr $failed + 1` testit "fetch a previous version of a regular file via non-canonical parent path" \ test_fetch_snap_file $share "BAR/baz" 6 || \ failed=`expr $failed + 1` testit "fetch a previous version of a regular file via non-canonical basepath" \ test_fetch_snap_file $share "bar/BAZ" 6 || \ failed=`expr $failed + 1` testit "fetch a previous version of a regular file via non-canonical path" \ test_fetch_snap_file $share "BAR/BAZ" 6 || \ failed=`expr $failed + 1` testit_expect_failure "fetch a (non-existent) previous version of a symlink" \ test_fetch_snap_file $share "bar/lfoo" 6 || \ failed=`expr $failed + 1` testit "fetch a previous version of a symlink via browsing (1)" \ test_fetch_snap_file $share "bar/lfoo" 0 || \ failed=`expr $failed + 1` testit "fetch a previous version of a symlink via browsing (2)" \ test_fetch_snap_file $share "bar/lfoo" 1 || \ failed=`expr $failed + 1` testit "fetch a previous version of a symlink via browsing (3)" \ test_fetch_snap_file $share "bar/lfoo" 3 || \ failed=`expr $failed + 1` testit "list a previous version directory" \ test_fetch_snap_dir $share "bar" 6 || \ failed=`expr $failed + 1` } test_shadow_copy_format() { local share #share to contact local where #where to place snapshots local prefix #prefix to files inside snapshot local ncopies_allowd local msg share=$1 where=$2 prefix=$3 ncopies_allowed=$4 msg=$5 #delete snapshots from previous tests find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1 build_snapshots $WORKDIR/$where "$prefix" 10 19 testit "$msg - regular file" \ test_count_versions $share foo $ncopies_allowed 1 || \ failed=`expr $failed + 1` } # Test fetching a file where there's no current version of it test_missing_basedir() { local share local where local prefix local snapidx share=$1 where=$2 prefix=$3 snapidx=$4 #delete snapshots from previous tests find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1 build_snapshots $WORKDIR/$where "$prefix" "$snapidx" "$snapidx" (cd "$WORKDIR/$where"/share; mv bar _bar) testit "fetch a file without a latest version" \ test_fetch_snap_file "$share" "bar/baz" "$snapidx" || \ failed=`expr $failed + 1` (cd "$WORKDIR/$where"/share; mv _bar bar) } #build "latest" files build_files $WORKDIR/mount base/share "latest" "latest" failed=0 # a test with wide links allowed - also to verify that what's later # being blocked is a result of server security measures and not # a testing artifact. test_shadow_copy_fixed shadow_wl mount base/share "shadow copies with wide links allowed" 1 # tests for a fixed snapshot location test_shadow_copy_fixed shadow1 mount base/share "full volume snapshots mounted under volume" test_shadow_copy_fixed shadow2 . base/share "full volume snapshots mounted outside volume" test_shadow_copy_fixed shadow3 mount/base share "sub volume snapshots mounted under snapshot point" test_shadow_copy_fixed shadow4 . share "sub volume snapshots mounted outside" test_shadow_copy_fixed shadow5 mount/base/share "" "full volume snapshots and share mounted under volume" test_shadow_copy_fixed shadow6 . "" "full volume snapshots and share mounted outside" test_shadow_copy_fixed shadow8 . share "logical snapshot layout" # tests for snapshot everywhere - one snapshot location test_shadow_copy_fixed shadow7 mount base/share "'everywhere' full volume snapshots" test_shadow_copy_fixed shadow7 mount/base share "'everywhere' sub volume snapshots" test_shadow_copy_fixed shadow7 mount/base/share "" "'everywhere' share snapshots" # a test for snapshots everywhere - multiple snapshot locations test_shadow_copy_everywhere shadow7 # tests for testing snapshot selection via shadow:format test_shadow_copy_format shadow_fmt0 mount/base share 3 "basic shadow:format test" test_shadow_copy_format shadow_fmt1 mount/base share 2 "shadow:format with only date" test_shadow_copy_format shadow_fmt2 mount/base share 2 "shadow:format with some prefix" test_shadow_copy_format shadow_fmt3 mount/base share 2 "shadow:format with modified format" test_shadow_copy_format shadow_fmt4 mount/base share 3 "shadow:format with snapprefix" test_shadow_copy_format shadow_fmt5 mount/base share 6 "shadow:format with delimiter" test_missing_basedir shadow3 "mount/base" "share" 6 exit $failed