mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
1fc1737959
Casefold rename test should check if renaming a file to an equivalent
name fails as expect (e.g. renaming from "file.txt" to "FILE.TXT") and
`mv` correctly identifies that those names refers to the same file.
Currently, the test doesn't do what is expected given that it doesn't
have the file to be renamed, and `mv` returns "No such file or
directory". Fix that by creating test files and checking the correct
output.
Fixes: 12b7dddbc2 ("generic: Add tests for filename casefolding feature")
Signed-off-by: André Almeida <andrealmeid@collabora.com>
Reviewed-by: Gabriel Krisman Bertazi <krisman@collabora.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
512 lines
12 KiB
Plaintext
Executable File
512 lines
12 KiB
Plaintext
Executable File
# 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
|