# SPDX-License-Identifier: GPL-2.0+ #!/bin/bash # FS QA Test No. 556 # # Test the basic functionality of filesystems with case-insensitive # support. seq=`basename $0` seqres=$RESULT_DIR/$seq echo "QA output created by $seq" status=1 # failure is thea default . ./common/rc . ./common/filter . ./common/casefold . ./common/attr _supported_fs generic _require_scratch_nocheck _require_scratch_casefold _require_symlinks _require_check_dmesg _require_attrs sdev=$(_short_dev ${SCRATCH_DEV}) filename1="file.txt" filename2="FILE.TXT" pt_file1=$(echo -e "coração") pt_file2=$(echo -e "corac\xcc\xa7\xc3\xa3o" | tr a-z A-Z) fr_file2=$(echo -e "french_caf\xc3\xa9.txt") fr_file1=$(echo -e "french_cafe\xcc\x81.txt") ar_file1=$(echo -e "arabic_\xdb\x92\xd9\x94.txt") ar_file2=$(echo -e "arabic_\xdb\x93.txt" | tr a-z A-Z) jp_file1=$(echo -e "japanese_\xe3\x82\xb2.txt") jp_file2=$(echo -e "japanese_\xe3\x82\xb1\xe3\x82\x99.txt") # '\xc3\x00' is an invalid sequence. Despite that, the sequences # below could match, if we ignored the error. But we don't want # to be greedy at normalization, so at the first error we treat # the entire sequence as an opaque blob. Therefore, these two # must NOT match. blob_file1=$(echo -e "corac\xcc\xa7\xc3") blob_file2=$(echo -e "coraç\xc3") # Test helpers basic_create_lookup() { local basedir=${1} local exact=${2} local lookup=${3} touch "${basedir}/${exact}" [ -f "${basedir}/${lookup}" ] || \ echo "lookup of ${exact} using ${lookup} failed" _casefold_check_exact_name "${basedir}" "${exact}" || \ echo "Created file ${exact} with wrong name." } # CI search should fail. bad_basic_create_lookup() { local basedir=${1} local exact=${2} local lookup=${3} touch "${basedir}/${exact}" [ -f "${basedir}/${lookup}" ] && \ echo "Lookup of ${exact} using ${lookup} should fail" } # Testcases test_casefold_lookup() { local basedir=${SCRATCH_MNT}/casefold_lookup mkdir -p ${basedir} _casefold_set_attr ${basedir} basic_create_lookup "${basedir}" "${filename1}" "${filename2}" basic_create_lookup "${basedir}" "${pt_file1}" "${pt_file2}" basic_create_lookup "${basedir}" "${fr_file1}" "${fr_file2}" basic_create_lookup "${basedir}" "${ar_file1}" "${ar_file2}" basic_create_lookup "${basedir}" "${jp_file1}" "${jp_file2}" } test_bad_casefold_lookup() { local basedir=${SCRATCH_MNT}/casefold_lookup mkdir -p ${basedir} bad_basic_create_lookup ${basedir} ${blob_file1} ${blob_file2} } do_create_and_remove() { local basedir=${1} local exact=${2} local casefold=${3} basic_create_lookup ${basedir} ${exact} ${casefold} rm -f ${basedir}/${exact} [ -f ${basedir}/${exact} ] && \ echo "File ${exact} was not removed using exact name" basic_create_lookup ${basedir} ${exact} ${casefold} rm -f ${basedir}/${casefold} [ -f ${basedir}/${exact} ] && \ echo "File ${exact} was not removed using inexact name" } # remove and recreate test_create_and_remove() { local basedir=${SCRATCH_MNT}/create_and_remove mkdir -p ${basedir} _casefold_set_attr ${basedir} do_create_and_remove "${basedir}" "${pt_file1}" "${pt_file2}" do_create_and_remove "${basedir}" "${jp_file1}" "${jp_file2}" do_create_and_remove "${basedir}" "${ar_file1}" "${ar_file2}" do_create_and_remove "${basedir}" "${fr_file1}" "${fr_file2}" } test_casefold_flag_basic() { local basedir=${SCRATCH_MNT}/basic mkdir -p ${basedir} _casefold_set_attr ${basedir} _casefold_lsattr_dir ${basedir} | _filter_scratch _casefold_unset_attr ${basedir} _casefold_lsattr_dir ${basedir} | _filter_scratch } test_casefold_flag_removal() { local basedir=${SCRATCH_MNT}/casefold_flag_removal mkdir -p ${basedir} _casefold_set_attr ${basedir} _casefold_lsattr_dir ${basedir} | _filter_scratch # Try to remove +F attribute on non empty directory touch ${basedir}/${filename1} _casefold_unset_attr ${basedir} &>/dev/null _casefold_lsattr_dir ${basedir} | _filter_scratch } # Test Inheritance of casefold flag test_casefold_flag_inheritance() { local basedir=${SCRATCH_MNT}/flag_inheritance local dirpath1="d1/d2/d3" local dirpath2="D1/D2/D3" mkdir -p ${basedir} _casefold_set_attr ${basedir} mkdir -p ${basedir}/${dirpath1} _casefold_lsattr_dir ${basedir}/${dirpath1} | _filter_scratch [ -d ${basedir}/${dirpath2} ] || \ echo "Directory CI Lookup failed." _casefold_check_exact_name "${basedir}" "${dirpath1}" || \ echo "Created directory with wrong name." touch ${basedir}/${dirpath2}/${filename1} [ -f ${basedir}/${dirpath1}/${filename2} ] || \ echo "Couldn't create file on casefolded parent." } # Test nesting of sensitive directory inside insensitive directory. test_nesting_sensitive_insensitive_tree_simple() { local basedir=${SCRATCH_MNT}/sd1 mkdir -p ${basedir} _casefold_set_attr ${basedir} mkdir -p ${basedir}/sd1 _casefold_set_attr ${basedir}/sd1 mkdir ${basedir}/sd1/sd2 _casefold_unset_attr ${basedir}/sd1/sd2 touch ${basedir}/sd1/sd2/${filename1} [ -f ${basedir}/sd1/sd2/${filename1} ] || \ echo "Exact nested file lookup failed." [ -f ${basedir}/sd1/SD2/${filename1} ] || \ echo "Nested file lookup failed." [ -f ${basedir}/sd1/SD2/${filename2} ] && \ echo "Wrong file lookup passed, should have fail." } test_nesting_sensitive_insensitive_tree_complex() { # Test nested-directories local basedir=${SCRATCH_MNT}/nesting mkdir -p ${basedir} _casefold_set_attr ${basedir} mkdir ${basedir}/nd1 _casefold_set_attr ${basedir}/nd1 mkdir ${basedir}/nd1/nd2 _casefold_unset_attr ${basedir}/nd1/nd2 mkdir ${basedir}/nd1/nd2/nd3 _casefold_set_attr ${basedir}/nd1/nd2/nd3 mkdir ${basedir}/nd1/nd2/nd3/nd4 _casefold_unset_attr ${basedir}/nd1/nd2/nd3/nd4 mkdir ${basedir}/nd1/nd2/nd3/nd4/nd5 _casefold_set_attr ${basedir}/nd1/nd2/nd3/nd4/nd5 [ -d ${basedir}/ND1/ND2/nd3/ND4/nd5 ] || \ echo "Nest-dir Lookup failed." [ -d ${basedir}/nd1/nd2/nd3/nd4/ND5 ] && \ echo "ND5: Nest-dir Lookup passed, it should fail." [ -d ${basedir}/nd1/nd2/nd3/ND4/nd5 ] || \ echo "Nest-dir Lookup failed." [ -d ${basedir}/nd1/nd2/ND3/nd4/ND5 ] && \ echo "ND3: Nest-dir Lookup passed, it should fail." } test_symlink_with_inexact_name() { local basedir=${SCRATCH_MNT}/symlink mkdir -p ${basedir} _casefold_set_attr ${basedir} mkdir ${basedir}/ind1 mkdir ${basedir}/ind2 _casefold_set_attr ${basedir}/ind1 touch ${basedir}/ind1/target ln -s ${basedir}/ind1/TARGET ${basedir}/ind2/link [ -L ${basedir}/ind2/link ] || echo "Not a symlink." readlink -e ${basedir}/ind2/link | _filter_scratch } do_test_name_preserve() { local basedir=${1} local exact=${2} local casefold=${3} touch ${basedir}/${exact} rm ${basedir}/${exact} touch ${basedir}/${casefold} _casefold_check_exact_name ${basedir} ${casefold} || echo "${casefold} was not created with exact name" } # Name-preserving tests # We create a file with a name, delete it and create again with an # equivalent name. If the negative dentry wasn't invalidated, the # file might be created using $1 instead of $2. test_name_preserve() { local basedir=${SCRATCH_MNT}/test_name_preserve mkdir -p ${basedir} _casefold_set_attr ${basedir} do_test_name_preserve "${basedir}" "${pt_file1}" "${pt_file2}" do_test_name_preserve "${basedir}" "${jp_file1}" "${jp_file2}" do_test_name_preserve "${basedir}" "${ar_file1}" "${ar_file2}" do_test_name_preserve "${basedir}" "${fr_file1}" "${fr_file2}" } do_test_dir_name_preserve() { local basedir=${1} local exact=${2} local casefold=${3} mkdir ${basedir}/${exact} rmdir ${basedir}/${exact} mkdir ${basedir}/${casefold} _casefold_check_exact_name ${basedir} ${casefold} || echo "${casefold} was not created with exact name" } test_dir_name_preserve() { local basedir=${SCRATCH_MNT}/"dir-test_name_preserve" mkdir -p ${basedir} _casefold_set_attr ${basedir} do_test_dir_name_preserve "${basedir}" "${pt_file1}" "${pt_file2}" do_test_dir_name_preserve "${basedir}" "${jp_file1}" "${jp_file2}" do_test_dir_name_preserve "${basedir}" "${ar_file1}" "${ar_file2}" do_test_dir_name_preserve "${basedir}" "${fr_file1}" "${fr_file2}" } test_name_reuse() { local basedir=${SCRATCH_MNT}/reuse local reuse1=fileX local reuse2=FILEX mkdir ${basedir} _casefold_set_attr ${basedir} touch ${basedir}/${reuse1} rm -f ${basedir}/${reuse1} || echo "File lookup failed." touch ${basedir}/${reuse2} _casefold_check_exact_name "${basedir}" "${reuse2}" || \ echo "File created with wrong name" _casefold_check_exact_name "${basedir}" "${reuse1}" && \ echo "File created with the old name" } test_create_with_same_name() { local basedir=${SCRATCH_MNT}/same_name mkdir ${basedir} _casefold_set_attr ${basedir} mkdir -p ${basedir}/same1/same1 touch ${basedir}/SAME1/sAME1/sAMe1 touch -c ${basedir}/SAME1/sAME1/same1 || echo "Would create a new file instead of using old one" } test_file_rename() { local basedir=${SCRATCH_MNT}/rename mkdir -p ${basedir} _casefold_set_attr ${basedir} touch ${basedir}/rename # Move to an equivalent name should not work mv ${basedir}/rename ${basedir}/RENAME 2>&1 | \ _filter_scratch _casefold_check_exact_name ${basedir} "rename" || \ echo "Name shouldn't change." } # Test openfd with casefold. # 1. Delete a file after gettings its fd. # 2. Then create new dir with same name test_casefold_openfd() { local basedir=${SCRATCH_MNT}/openfd local ofd1="openfd" local ofd2="OPENFD" mkdir -p ${basedir} _casefold_set_attr ${basedir} exec 3<> ${basedir}/${ofd1} rm -rf ${basedir}/${ofd1} mkdir ${basedir}/${ofd2} [ -d ${basedir}/${ofd2} ] || echo "Not a directory" _casefold_check_exact_name ${basedir} "${ofd2}" || echo "openfd file was created using old name" rm -rf ${basedir}/${ofd2} exec 3>&- } # Test openfd with casefold. # 1. Delete a file after gettings its fd. # 2. Then create new file with same name # 3. Read from open-fd and write into new file. test_casefold_openfd2() { local basedir=${SCRATCH_MNT}/openfd2 local ofd1="openfd" local ofd2="OPENFD" mkdir ${basedir} _casefold_set_attr ${basedir} date > ${basedir}/${ofd1} exec 3<> ${basedir}/${ofd1} rm -rf ${basedir}/${ofd1} touch ${basedir}/${ofd1} [ -f ${basedir}/${ofd2} ] || echo "Not a file" read data <&3 echo $data >> ${basedir}/${ofd1} exec 3>&- } test_hard_link_lookups() { local basedir=${SCRATCH_MNT}/hard_link mkdir ${basedir} _casefold_set_attr ${basedir} touch ${basedir}/h1 ln ${basedir}/H1 ${SCRATCH_MNT}/h1 cnt=`stat -c %h ${basedir}/h1` [ $cnt -eq 1 ] && echo "Unable to create hardlink" # Create hardlink for casefold dir file and inside regular dir. touch ${SCRATCH_MNT}/h2 ln ${SCRATCH_MNT}/h2 ${basedir}/H2 cnt=`stat -c %h ${basedir}/h2` [ $cnt -eq 1 ] && echo "Unable to create hardlink" } test_xattrs_lookups() { local basedir=${SCRATCH_MNT}/xattrs mkdir ${basedir} _casefold_set_attr ${basedir} mkdir -p ${basedir}/x ${SETFATTR_PROG} -n user.foo -v bar ${basedir}/x ${GETFATTR_PROG} --absolute-names -n user.foo \ ${basedir}/x | _filter_scratch touch ${basedir}/x/f1 ${SETFATTR_PROG} -n user.foo -v bar ${basedir}/x/f1 ${GETFATTR_PROG} --absolute-names -n user.foo \ ${basedir}/x/f1 | _filter_scratch } test_lookup_large_directory() { local basedir=${SCRATCH_MNT}/large mkdir -p ${basedir} _casefold_set_attr ${basedir} touch $(seq -f "${basedir}/file%g" 0 2000) # We really want to spawn a single process here, to speed up the # test, but we don't want the output of 2k files, except for # errors. cat $(seq -f "${basedir}/FILE%g" 0 2000) || \ echo "Case on large dir failed" } test_strict_mode_invalid_filename() { local basedir=${SCRATCH_MNT}/strict mkdir -p ${basedir} _casefold_set_attr ${basedir} # These creation commands should fail, since we are on strict # mode. touch "${basedir}/${blob_file1}" 2>&1 | _filter_scratch touch "${basedir}/${blob_file2}" 2>&1 | _filter_scratch } ############# # Run tests # ############# _scratch_mkfs_casefold >>$seqres.full 2>&1 _scratch_mount _check_dmesg_for \ "\(${sdev}\): Using encoding defined by superblock: utf8" || \ _fail "Could not mount with encoding: utf8" test_casefold_flag_basic test_casefold_lookup test_bad_casefold_lookup test_create_and_remove test_casefold_flag_removal test_casefold_flag_inheritance test_nesting_sensitive_insensitive_tree_simple test_nesting_sensitive_insensitive_tree_complex test_symlink_with_inexact_name test_name_preserve test_dir_name_preserve test_name_reuse test_create_with_same_name test_file_rename test_casefold_openfd test_casefold_openfd2 test_hard_link_lookups test_xattrs_lookups test_lookup_large_directory _scratch_unmount _check_scratch_fs # Test Strict Mode _scratch_mkfs_casefold_strict >>$seqres.full 2>&1 _scratch_mount test_strict_mode_invalid_filename _scratch_unmount _check_scratch_fs status=0 exit