| #! /bin/bash | 
 | # SPDX-License-Identifier: GPL-2.0 | 
 | # Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved. | 
 | # | 
 | # FS QA Test No. 001 | 
 | # | 
 | # Random file copier to produce chains of identical files so the head | 
 | # and the tail can be diff'd at the end of each iteration. | 
 | # | 
 | # Exercises creat, write and unlink for a variety of directory sizes, and | 
 | # checks for data corruption. | 
 | # | 
 | # run [config] | 
 | # | 
 | # config has one line per file with filename and byte size, else use | 
 | # the default one below. | 
 | # | 
 | . ./common/preamble | 
 | _begin_fstest rw dir udf auto quick | 
 |  | 
 | # Import common functions. | 
 | . ./common/filter | 
 |  | 
 | status=1 | 
 | done_cleanup=false | 
 | _register_cleanup "_cleanup; rm -f $tmp.*" | 
 |  | 
 | _require_test | 
 |  | 
 | verbose=true | 
 | verify=$here/verify_fill | 
 |  | 
 | if [ $# -eq 0 ] | 
 | then | 
 |     # use the default config | 
 |     # | 
 |     cat <<End-of-File >$tmp.config | 
 | # pathname	size in bytes | 
 | # | 
 | small		10 | 
 | big		102400 | 
 | sub/small	10 | 
 | sub/big		102400 | 
 | # | 
 | sub/a		1 | 
 | sub/b		2 | 
 | sub/c		4 | 
 | sub/d		8 | 
 | sub/e		16 | 
 | sub/f		32 | 
 | sub/g		64 | 
 | sub/h		128 | 
 | sub/i		256 | 
 | sub/j		512 | 
 | sub/k		1024 | 
 | sub/l		2048 | 
 | sub/m		4096 | 
 | sub/n		8192 | 
 | # | 
 | sub/a00		100 | 
 | sub/b00		200 | 
 | sub/c00		400 | 
 | sub/d00		800 | 
 | sub/e00		1600 | 
 | sub/f00		3200 | 
 | sub/g00		6400 | 
 | sub/h00		12800 | 
 | sub/i00		25600 | 
 | sub/j00		51200 | 
 | sub/k00		102400 | 
 | sub/l00		204800 | 
 | sub/m00		409600 | 
 | sub/n00		819200 | 
 | # | 
 | sub/a000	1000 | 
 | sub/e000	16000 | 
 | sub/h000	128000 | 
 | sub/k000	1024000 | 
 | End-of-File | 
 | elif [ $# -eq 1 ] | 
 | then | 
 |     if [ -f $1 ] | 
 |     then | 
 | 	cp $1 $tmp.config | 
 |     else | 
 | 	echo "Error: cannot open config \"$1\"" | 
 | 	exit 1 | 
 |     fi | 
 | else | 
 |     echo "Usage: run [config]" | 
 |     exit 1 | 
 | fi | 
 |  | 
 | ncopy=200		# number of file copies in the chain step | 
 | udf_fsize=20240		# number of sectors for UDF | 
 |  | 
 | _setup() | 
 | { | 
 |     if mkdir -p $TEST_DIR/$$ | 
 |     then | 
 | 	: | 
 |     else | 
 | 	echo "Error: cannot mkdir \"$TEST_DIR/$$\"" | 
 | 	exit 1 | 
 |     fi | 
 |     cd $TEST_DIR/$$ | 
 |  | 
 |     $verbose && echo -n "setup " | 
 |     sed -e '/^#/d' $tmp.config \ | 
 |     | while read file nbytes | 
 |     do | 
 | 	dir=`dirname $file` | 
 | 	if [ "$dir" != "." ] | 
 | 	then | 
 | 	    if [ ! -d $dir ] | 
 | 	    then | 
 | 		if mkdir $dir | 
 | 		then | 
 | 		    : | 
 | 		else | 
 | 		    $verbose && echo | 
 | 		    echo "Error: cannot mkdir \"$dir\"" | 
 | 		    exit 1 | 
 | 		fi | 
 | 	    fi | 
 | 	fi | 
 | 	rm -f $file | 
 | 	if $here/src/fill $file $file $nbytes | 
 | 	then | 
 | 	    : | 
 | 	else | 
 | 	    $verbose && echo | 
 | 	    echo "Error: cannot create \"$file\"" | 
 | 	    exit 1 | 
 | 	fi | 
 | 	$verbose && echo -n "." | 
 |     done | 
 |     $verbose && echo | 
 | } | 
 |  | 
 | _mark_iteration() | 
 | { | 
 |     $verbose && echo -n "mark_iteration " | 
 |     sed -e '/^#/d' $tmp.config \ | 
 |     | while read file nbytes | 
 |     do | 
 | 	if [ ! -f $file ] | 
 | 	then | 
 | 	    $verbose && echo | 
 | 	    echo "Error: $file vanished!" | 
 | 	    touch $tmp.bad | 
 | 	    continue | 
 | 	fi | 
 | 	sed -e "s/ [0-9][0-9]* / $1 /" <$file >$file.tmp | 
 | 	mv $file.tmp $file | 
 | 	$verbose && echo -n "." | 
 |     done | 
 |     $verbose && echo | 
 | } | 
 |  | 
 | # for each file, make a number of copies forming a chain like foo.0, | 
 | # foo.1, foo.2, ... foo.N | 
 | # | 
 | # files are chosen at random, so the lengths of the chains are different | 
 | # | 
 | # then rename foo.N to foo.last and remove all of the other files in | 
 | # the chain | 
 | # | 
 | _chain() | 
 | { | 
 |     $AWK_PROG -v full_file=$seqres.full -v verify=$verify <$tmp.config ' | 
 | BEGIN	{ nfile = 0 } | 
 | /^#/	{ next } | 
 | 	{ file[nfile] = $1 | 
 | 	  size[nfile] = $2 | 
 | 	  link[nfile] = 0 | 
 | 	  nfile++ | 
 | 	  total_size += $2 | 
 | 	} | 
 | END	{ srand('$iter') | 
 | 	  for (i=0; i < '$ncopy'; i++) { | 
 | 	    # choose a file at random, and add one copy to that chain | 
 | 	    j = -1 | 
 | 	    while (j < 0 || j >= nfile) | 
 | 		j = int(rand() * nfile) | 
 | 	    if (link[j] == 0) { | 
 | 		# previous should already exist and next one should not exist | 
 | 		printf "if [ ! -f %s ]; then echo \"%s missing!\"; exit; fi\n",file[j],file[j] | 
 | 		printf "if [ -f %s.0 ]; then echo \"%s.0 already present!\"; exit; fi\n",file[j],file[j] | 
 | 		printf "cp %s %s.0 || exit 1\n",file[j],file[j] | 
 | 		printf "ls -i %s.0\n", file[j] >full_file; | 
 | 		total_size += size[j] | 
 | 		printf "# total size = %d\n", total_size  | 
 | 	    } | 
 | 	    else { | 
 | 		# previous should already exist and next one should not exist | 
 | 		printf "if [ ! -f %s.%d ]; then echo \"%s.%d missing!\"; exit; fi\n",file[j],link[j]-1,file[j],link[j]-1 | 
 | 		printf "if [ -f %s.%d ]; then echo \"%s.%d already present!\"; exit; fi\n",file[j],link[j],file[j],link[j] | 
 | 		printf "cp %s.%d %s.%d || exit 1\n",file[j],link[j]-1,file[j],link[j] | 
 | 		printf "ls -i %s.%d\n", file[j], link[j] >full_file; | 
 | 		total_size += size[j] | 
 | 		printf "# total size = %d\n", total_size  | 
 | 	    } | 
 | 	    link[j]++ | 
 | 	  } | 
 | 	  # close all the chains,  | 
 | 	  # if have at least one copy then move the last copy to "file[j].last" | 
 | 	  # and remove all of the other files except the head of the chain | 
 | 	  for (j=0; j<nfile; j++) { | 
 | 	    if (link[j] > 0) { | 
 | 		printf "mv %s.%d %s.last\n",file[j],link[j]-1,file[j] | 
 | 		printf "ls -i %s.last\n", file[j] >full_file; | 
 | 	    } | 
 | 	    for (i=0; i<link[j]-1; i++) { | 
 | 		printf "rm -f %s.%d\n",file[j],i | 
 | 	    } | 
 | 	  } | 
 | 	}' \ | 
 | 	| tee -a $seqres.full | sh | 
 | } | 
 |  | 
 | _check() | 
 | { | 
 |     rm -f $tmp.bad | 
 |     $verbose && echo -n "check " | 
 |     sed -e '/^#/d' $tmp.config \ | 
 |     | while read file nbytes | 
 |     do | 
 | 	# the file is never removed so it should exist | 
 | 	if [ ! -f $file ] | 
 | 	then | 
 | 	    $verbose && echo | 
 | 	    echo "Error: $file vanished!" | 
 | 	    touch $tmp.bad | 
 | 	    continue | 
 | 	fi | 
 | 	# checks that the file and its last copy are the same | 
 | 	if [ -f $file.last ] | 
 | 	then | 
 | 	    if cmp $file $file.last >/dev/null 2>&1 | 
 | 	    then | 
 | 		$verbose && echo -n "." | 
 | 	    else | 
 | 		$verbose && echo | 
 | 		echo "Error: corruption for $file ..." | 
 | 		diff -c $file $file.last | 
 | 		touch $tmp.bad | 
 | 	    fi | 
 | 	else | 
 | 	    $verbose && echo -n "." | 
 | 	fi | 
 |     done | 
 |     $verbose && echo | 
 | } | 
 |  | 
 | # Override the default cleanup function. | 
 | _cleanup() | 
 | { | 
 |     # cleanup | 
 |     # | 
 |     if $done_cleanup | 
 |     then | 
 | 	: | 
 |     elif [ $status -eq 0 ] | 
 |     then | 
 | 	$verbose && echo "cleanup" | 
 | 	cd / | 
 | 	rm -rf $TEST_DIR/$$ | 
 | 	done_cleanup=true | 
 |     fi | 
 | } | 
 |  | 
 | status=0 | 
 | _cleanup | 
 | status=1 | 
 | done_cleanup=false | 
 |  | 
 | _setup | 
 |  | 
 | # do the test | 
 | # | 
 | for iter in 1 2 3 4 5 | 
 | do | 
 |     echo -n "iter $iter chain ... " | 
 |     echo "iter $iter" >> $seqres.full | 
 |     _chain | 
 |     _check | 
 |     if [ -f $tmp.bad ] | 
 |     then | 
 | 	echo "Fatal error: test abandoned without changes" | 
 | 	exit 1 | 
 |     fi | 
 | done | 
 |  | 
 | status=0 | 
 | exit |