generic: Add tests for filename casefolding feature
authorLakshmipathi.G <lakshmipathi.ganapathi@collabora.co.uk>
Wed, 12 Jun 2019 18:40:33 +0000 (14:40 -0400)
committerEryu Guan <guaneryu@gmail.com>
Sun, 16 Jun 2019 14:47:24 +0000 (22:47 +0800)
This new test implements verification for the per-directory
case-insensitive feature, as supported by the reference
implementation in Ext4.

Signed-off-by: Lakshmipathi.G <lakshmipathi.ganapathi@collabora.co.uk>
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.com>
  [Rewrite to support feature design]
  [Refactor to simplify implementation]
Reviewed-by: Eryu Guan <guaneryu@gmail.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
tests/generic/556 [new file with mode: 0755]
tests/generic/556.out [new file with mode: 0644]
tests/generic/group

diff --git a/tests/generic/556 b/tests/generic/556
new file mode 100755 (executable)
index 0000000..b7239e3
--- /dev/null
@@ -0,0 +1,509 @@
+# 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_os Linux
+_supported_fs generic
+_require_scratch_nocheck
+_require_scratch_casefold
+_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}
+
+       # 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
diff --git a/tests/generic/556.out b/tests/generic/556.out
new file mode 100644 (file)
index 0000000..1573c8b
--- /dev/null
@@ -0,0 +1,16 @@
+QA output created by 556
+SCRATCH_MNT/basic Extents, Casefold
+SCRATCH_MNT/basic Extents
+SCRATCH_MNT/casefold_flag_removal Extents, Casefold
+SCRATCH_MNT/casefold_flag_removal Extents, Casefold
+SCRATCH_MNT/flag_inheritance/d1/d2/d3 Extents, Casefold
+SCRATCH_MNT/symlink/ind1/TARGET
+mv: cannot stat 'SCRATCH_MNT/rename/rename': No such file or directory
+# file: SCRATCH_MNT/xattrs/x
+user.foo="bar"
+
+# file: SCRATCH_MNT/xattrs/x/f1
+user.foo="bar"
+
+touch: setting times of 'SCRATCH_MNT/strict/corac'$'\314\247\303': Invalid argument
+touch: setting times of 'SCRATCH_MNT/strict/cora'$'\303\247\303': Invalid argument
index 8262b09c1c9c9415c5e986eedea8a0745963611d..0867e455c7c75d26985b57d231f80b2683df8ad9 100644 (file)
 553 auto quick copy_range
 554 auto quick copy_range swap
 555 auto quick cap
+556 auto quick casefold