generic: Add tests for filename casefolding feature
[xfstests-dev.git] / tests / generic / 556
1 # SPDX-License-Identifier: GPL-2.0+
2 #!/bin/bash
3 # FS QA Test No. 556
4 #
5 # Test the basic functionality of filesystems with case-insensitive
6 # support.
7
8 seq=`basename $0`
9 seqres=$RESULT_DIR/$seq
10 echo "QA output created by $seq"
11 status=1 # failure is thea default
12
13 . ./common/rc
14 . ./common/filter
15 . ./common/casefold
16 . ./common/attr
17
18 _supported_os Linux
19 _supported_fs generic
20 _require_scratch_nocheck
21 _require_scratch_casefold
22 _require_check_dmesg
23 _require_attrs
24
25 sdev=$(_short_dev ${SCRATCH_DEV})
26
27 filename1="file.txt"
28 filename2="FILE.TXT"
29
30 pt_file1=$(echo -e "coração")
31 pt_file2=$(echo -e "corac\xcc\xa7\xc3\xa3o" | tr a-z A-Z)
32
33 fr_file2=$(echo -e "french_caf\xc3\xa9.txt")
34 fr_file1=$(echo -e "french_cafe\xcc\x81.txt")
35
36 ar_file1=$(echo -e "arabic_\xdb\x92\xd9\x94.txt")
37 ar_file2=$(echo -e "arabic_\xdb\x93.txt" | tr a-z A-Z)
38
39 jp_file1=$(echo -e "japanese_\xe3\x82\xb2.txt")
40 jp_file2=$(echo -e "japanese_\xe3\x82\xb1\xe3\x82\x99.txt")
41
42 # '\xc3\x00' is an invalid sequence. Despite that, the sequences
43 # below could match, if we ignored the error.  But we don't want
44 # to be greedy at normalization, so at the first error we treat
45 # the entire sequence as an opaque blob.  Therefore, these two
46 # must NOT match.
47 blob_file1=$(echo -e "corac\xcc\xa7\xc3")
48 blob_file2=$(echo -e "coraç\xc3")
49
50 # Test helpers
51 basic_create_lookup()
52 {
53         local basedir=${1}
54         local exact=${2}
55         local lookup=${3}
56
57         touch "${basedir}/${exact}"
58         [ -f "${basedir}/${lookup}" ] || \
59                 echo "lookup of ${exact} using ${lookup} failed"
60         _casefold_check_exact_name "${basedir}" "${exact}" || \
61                 echo "Created file ${exact} with wrong name."
62 }
63
64 # CI search should fail.
65 bad_basic_create_lookup()
66 {
67         local basedir=${1}
68         local exact=${2}
69         local lookup=${3}
70
71         touch "${basedir}/${exact}"
72         [ -f "${basedir}/${lookup}" ] && \
73                 echo "Lookup of ${exact} using ${lookup} should fail"
74 }
75
76 # Testcases
77 test_casefold_lookup()
78 {
79         local basedir=${SCRATCH_MNT}/casefold_lookup
80
81         mkdir -p ${basedir}
82         _casefold_set_attr ${basedir}
83
84         basic_create_lookup "${basedir}" "${filename1}" "${filename2}"
85         basic_create_lookup "${basedir}" "${pt_file1}" "${pt_file2}"
86         basic_create_lookup "${basedir}" "${fr_file1}" "${fr_file2}"
87         basic_create_lookup "${basedir}" "${ar_file1}" "${ar_file2}"
88         basic_create_lookup "${basedir}" "${jp_file1}" "${jp_file2}"
89 }
90
91 test_bad_casefold_lookup()
92 {
93         local basedir=${SCRATCH_MNT}/casefold_lookup
94
95         mkdir -p ${basedir}
96
97         bad_basic_create_lookup ${basedir} ${blob_file1} ${blob_file2}
98 }
99
100 do_create_and_remove()
101 {
102         local basedir=${1}
103         local exact=${2}
104         local casefold=${3}
105
106         basic_create_lookup ${basedir} ${exact} ${casefold}
107         rm -f ${basedir}/${exact}
108         [ -f ${basedir}/${exact} ] && \
109                 echo "File ${exact} was not removed using exact name"
110
111         basic_create_lookup ${basedir} ${exact} ${casefold}
112         rm -f ${basedir}/${casefold}
113         [ -f ${basedir}/${exact} ] && \
114                 echo "File ${exact} was not removed using inexact name"
115 }
116
117 # remove and recreate
118 test_create_and_remove()
119 {
120         local basedir=${SCRATCH_MNT}/create_and_remove
121         mkdir -p ${basedir}
122
123         _casefold_set_attr ${basedir}
124         do_create_and_remove "${basedir}" "${pt_file1}" "${pt_file2}"
125         do_create_and_remove "${basedir}" "${jp_file1}" "${jp_file2}"
126         do_create_and_remove "${basedir}" "${ar_file1}" "${ar_file2}"
127         do_create_and_remove "${basedir}" "${fr_file1}" "${fr_file2}"
128 }
129
130 test_casefold_flag_basic()
131 {
132         local basedir=${SCRATCH_MNT}/basic
133
134         mkdir -p ${basedir}
135         _casefold_set_attr ${basedir}
136         _casefold_lsattr_dir ${basedir} | _filter_scratch
137
138         _casefold_unset_attr ${basedir}
139         _casefold_lsattr_dir ${basedir} | _filter_scratch
140 }
141
142 test_casefold_flag_removal()
143 {
144         local basedir=${SCRATCH_MNT}/casefold_flag_removal
145
146         mkdir -p ${basedir}
147         _casefold_set_attr ${basedir}
148         _casefold_lsattr_dir ${basedir} | _filter_scratch
149
150         # Try to remove +F attribute on non empty directory
151         touch ${basedir}/${filename1}
152         _casefold_unset_attr ${basedir} &>/dev/null
153         _casefold_lsattr_dir ${basedir} | _filter_scratch
154 }
155
156 # Test Inheritance of casefold flag
157 test_casefold_flag_inheritance()
158 {
159         local basedir=${SCRATCH_MNT}/flag_inheritance
160         local dirpath1="d1/d2/d3"
161         local dirpath2="D1/D2/D3"
162
163         mkdir -p ${basedir}
164         _casefold_set_attr ${basedir}
165
166         mkdir -p ${basedir}/${dirpath1}
167         _casefold_lsattr_dir ${basedir}/${dirpath1} | _filter_scratch
168
169         [ -d ${basedir}/${dirpath2} ] || \
170                 echo "Directory CI Lookup failed."
171         _casefold_check_exact_name "${basedir}" "${dirpath1}" || \
172                 echo "Created directory with wrong name."
173
174         touch ${basedir}/${dirpath2}/${filename1}
175         [ -f ${basedir}/${dirpath1}/${filename2} ] || \
176                 echo "Couldn't create file on casefolded parent."
177 }
178
179 # Test nesting of sensitive directory inside insensitive directory.
180 test_nesting_sensitive_insensitive_tree_simple()
181 {
182         local basedir=${SCRATCH_MNT}/sd1
183
184         mkdir -p ${basedir}
185         _casefold_set_attr ${basedir}
186
187         mkdir -p ${basedir}/sd1
188         _casefold_set_attr ${basedir}/sd1
189
190         mkdir ${basedir}/sd1/sd2
191         _casefold_unset_attr ${basedir}/sd1/sd2
192
193         touch ${basedir}/sd1/sd2/${filename1}
194         [ -f ${basedir}/sd1/sd2/${filename1} ] || \
195                 echo "Exact nested file lookup failed."
196         [ -f ${basedir}/sd1/SD2/${filename1} ] || \
197                 echo "Nested file lookup failed."
198         [ -f ${basedir}/sd1/SD2/${filename2} ] && \
199                 echo "Wrong file lookup passed, should have fail."
200 }
201
202 test_nesting_sensitive_insensitive_tree_complex()
203 {
204         # Test nested-directories
205         local basedir=${SCRATCH_MNT}/nesting
206
207         mkdir -p ${basedir}
208         _casefold_set_attr ${basedir}
209
210         mkdir ${basedir}/nd1
211         _casefold_set_attr ${basedir}/nd1
212         mkdir ${basedir}/nd1/nd2
213         _casefold_unset_attr ${basedir}/nd1/nd2
214         mkdir ${basedir}/nd1/nd2/nd3
215         _casefold_set_attr ${basedir}/nd1/nd2/nd3
216         mkdir ${basedir}/nd1/nd2/nd3/nd4
217         _casefold_unset_attr ${basedir}/nd1/nd2/nd3/nd4
218         mkdir ${basedir}/nd1/nd2/nd3/nd4/nd5
219         _casefold_set_attr ${basedir}/nd1/nd2/nd3/nd4/nd5
220
221         [ -d ${basedir}/ND1/ND2/nd3/ND4/nd5 ] || \
222                 echo "Nest-dir Lookup failed."
223         [ -d ${basedir}/nd1/nd2/nd3/nd4/ND5 ] && \
224                 echo "ND5: Nest-dir Lookup passed, it should fail."
225         [ -d ${basedir}/nd1/nd2/nd3/ND4/nd5 ] || \
226                 echo "Nest-dir Lookup failed."
227         [ -d ${basedir}/nd1/nd2/ND3/nd4/ND5 ] && \
228                 echo "ND3: Nest-dir Lookup passed, it should fail."
229 }
230
231 test_symlink_with_inexact_name()
232 {
233         local basedir=${SCRATCH_MNT}/symlink
234
235         mkdir -p ${basedir}
236         _casefold_set_attr ${basedir}
237
238         mkdir ${basedir}/ind1
239         mkdir ${basedir}/ind2
240         _casefold_set_attr ${basedir}/ind1
241         touch ${basedir}/ind1/target
242
243         ln -s ${basedir}/ind1/TARGET ${basedir}/ind2/link
244         [ -L ${basedir}/ind2/link ] || echo "Not a symlink."
245         readlink -e ${basedir}/ind2/link | _filter_scratch
246 }
247
248 do_test_name_preserve()
249 {
250         local basedir=${1}
251         local exact=${2}
252         local casefold=${3}
253
254         touch ${basedir}/${exact}
255         rm ${basedir}/${exact}
256
257         touch ${basedir}/${casefold}
258         _casefold_check_exact_name ${basedir} ${casefold} ||
259                 echo "${casefold} was not created with exact name"
260 }
261
262 # Name-preserving tests
263 # We create a file with a name, delete it and create again with an
264 # equivalent name.  If the negative dentry wasn't invalidated, the
265 # file might be created using $1 instead of $2.
266 test_name_preserve()
267 {
268         local basedir=${SCRATCH_MNT}/test_name_preserve
269
270         mkdir -p ${basedir}
271         _casefold_set_attr ${basedir}
272
273         do_test_name_preserve "${basedir}" "${pt_file1}" "${pt_file2}"
274         do_test_name_preserve "${basedir}" "${jp_file1}" "${jp_file2}"
275         do_test_name_preserve "${basedir}" "${ar_file1}" "${ar_file2}"
276         do_test_name_preserve "${basedir}" "${fr_file1}" "${fr_file2}"
277 }
278
279 do_test_dir_name_preserve()
280 {
281         local basedir=${1}
282         local exact=${2}
283         local casefold=${3}
284
285         mkdir ${basedir}/${exact}
286         rmdir ${basedir}/${exact}
287
288         mkdir ${basedir}/${casefold}
289         _casefold_check_exact_name ${basedir} ${casefold} ||
290                 echo "${casefold} was not created with exact name"
291 }
292
293 test_dir_name_preserve()
294 {
295         local basedir=${SCRATCH_MNT}/"dir-test_name_preserve"
296
297         mkdir -p ${basedir}
298         _casefold_set_attr ${basedir}
299
300         do_test_dir_name_preserve "${basedir}" "${pt_file1}" "${pt_file2}"
301         do_test_dir_name_preserve "${basedir}" "${jp_file1}" "${jp_file2}"
302         do_test_dir_name_preserve "${basedir}" "${ar_file1}" "${ar_file2}"
303         do_test_dir_name_preserve "${basedir}" "${fr_file1}" "${fr_file2}"
304 }
305
306 test_name_reuse()
307 {
308         local basedir=${SCRATCH_MNT}/reuse
309         local reuse1=fileX
310         local reuse2=FILEX
311
312         mkdir ${basedir}
313         _casefold_set_attr ${basedir}
314
315         touch ${basedir}/${reuse1}
316         rm -f ${basedir}/${reuse1} || echo "File lookup failed."
317         touch ${basedir}/${reuse2}
318         _casefold_check_exact_name "${basedir}" "${reuse2}" || \
319                 echo "File created with wrong name"
320         _casefold_check_exact_name "${basedir}" "${reuse1}" && \
321                 echo "File created with the old name"
322 }
323
324 test_create_with_same_name()
325 {
326         local basedir=${SCRATCH_MNT}/same_name
327
328         mkdir ${basedir}
329         _casefold_set_attr ${basedir}
330
331         mkdir -p ${basedir}/same1/same1
332         touch ${basedir}/SAME1/sAME1/sAMe1
333         touch -c ${basedir}/SAME1/sAME1/same1 ||
334                 echo "Would create a new file instead of using old one"
335 }
336
337 test_file_rename()
338 {
339         local basedir=${SCRATCH_MNT}/rename
340
341         mkdir -p ${basedir}
342         _casefold_set_attr ${basedir}
343
344         # Move to an equivalent name should not work
345         mv ${basedir}/rename ${basedir}/rename 2>&1 | \
346                 _filter_scratch
347
348         _casefold_check_exact_name ${basedir} "rename" || \
349                 echo "Name shouldn't change."
350 }
351
352 # Test openfd with casefold.
353 # 1. Delete a file after gettings its fd.
354 # 2. Then create new dir with same name
355 test_casefold_openfd()
356 {
357         local basedir=${SCRATCH_MNT}/openfd
358         local ofd1="openfd"
359         local ofd2="OPENFD"
360
361         mkdir -p ${basedir}
362         _casefold_set_attr ${basedir}
363
364         exec 3<> ${basedir}/${ofd1}
365         rm -rf ${basedir}/${ofd1}
366         mkdir ${basedir}/${ofd2}
367         [ -d ${basedir}/${ofd2} ] || echo "Not a directory"
368         _casefold_check_exact_name ${basedir} "${ofd2}" ||
369                 echo "openfd file was created using old name"
370         rm -rf ${basedir}/${ofd2}
371         exec 3>&-
372 }
373
374 # Test openfd with casefold.
375 # 1. Delete a file after gettings its fd.
376 # 2. Then create new file with same name
377 # 3. Read from open-fd and write into new file.
378 test_casefold_openfd2()
379 {
380         local basedir=${SCRATCH_MNT}/openfd2
381         local ofd1="openfd"
382         local ofd2="OPENFD"
383
384         mkdir ${basedir}
385         _casefold_set_attr ${basedir}
386
387         date > ${basedir}/${ofd1}
388         exec 3<> ${basedir}/${ofd1}
389         rm -rf ${basedir}/${ofd1}
390         touch ${basedir}/${ofd1}
391         [ -f ${basedir}/${ofd2} ] || echo "Not a file"
392         read data <&3
393         echo $data >> ${basedir}/${ofd1}
394         exec 3>&-
395 }
396
397 test_hard_link_lookups()
398 {
399         local basedir=${SCRATCH_MNT}/hard_link
400
401         mkdir ${basedir}
402         _casefold_set_attr ${basedir}
403
404         touch ${basedir}/h1
405         ln ${basedir}/H1 ${SCRATCH_MNT}/h1
406         cnt=`stat -c %h ${basedir}/h1`
407         [ $cnt -eq 1 ] && echo "Unable to create hardlink"
408
409         # Create hardlink for casefold dir file and inside regular dir.
410         touch ${SCRATCH_MNT}/h2
411         ln ${SCRATCH_MNT}/h2 ${basedir}/H2
412         cnt=`stat -c %h ${basedir}/h2`
413         [ $cnt -eq 1 ] && echo "Unable to create hardlink"
414 }
415
416 test_xattrs_lookups()
417 {
418         local basedir=${SCRATCH_MNT}/xattrs
419
420         mkdir ${basedir}
421         _casefold_set_attr ${basedir}
422
423         mkdir -p ${basedir}/x
424
425         ${SETFATTR_PROG} -n user.foo -v bar ${basedir}/x
426         ${GETFATTR_PROG} --absolute-names -n user.foo \
427                 ${basedir}/x | _filter_scratch
428
429         touch ${basedir}/x/f1
430         ${SETFATTR_PROG} -n user.foo -v bar ${basedir}/x/f1
431         ${GETFATTR_PROG} --absolute-names -n user.foo \
432                 ${basedir}/x/f1 | _filter_scratch
433 }
434
435 test_lookup_large_directory()
436 {
437         local basedir=${SCRATCH_MNT}/large
438
439         mkdir -p ${basedir}
440         _casefold_set_attr ${basedir}
441
442         touch $(seq -f "${basedir}/file%g" 0 2000)
443
444         # We really want to spawn a single process here, to speed up the
445         # test, but we don't want the output of 2k files, except for
446         # errors.
447         cat $(seq -f "${basedir}/FILE%g" 0 2000) || \
448                 echo "Case on large dir failed"
449 }
450
451 test_strict_mode_invalid_filename()
452 {
453         local basedir=${SCRATCH_MNT}/strict
454
455         mkdir -p ${basedir}
456         _casefold_set_attr ${basedir}
457
458         # These creation commands should fail, since we are on strict
459         # mode.
460         touch "${basedir}/${blob_file1}" 2>&1 | _filter_scratch
461         touch "${basedir}/${blob_file2}" 2>&1 | _filter_scratch
462 }
463
464 #############
465 # Run tests #
466 #############
467
468 _scratch_mkfs_casefold >>$seqres.full 2>&1
469
470 _scratch_mount
471
472 _check_dmesg_for \
473         "\(${sdev}\): Using encoding defined by superblock: utf8" || \
474         _fail "Could not mount with encoding: utf8"
475
476 test_casefold_flag_basic
477 test_casefold_lookup
478 test_bad_casefold_lookup
479 test_create_and_remove
480 test_casefold_flag_removal
481 test_casefold_flag_inheritance
482 test_nesting_sensitive_insensitive_tree_simple
483 test_nesting_sensitive_insensitive_tree_complex
484 test_symlink_with_inexact_name
485 test_name_preserve
486 test_dir_name_preserve
487 test_name_reuse
488 test_create_with_same_name
489 test_file_rename
490 test_casefold_openfd
491 test_casefold_openfd2
492 test_hard_link_lookups
493 test_xattrs_lookups
494 test_lookup_large_directory
495
496 _scratch_unmount
497 _check_scratch_fs
498
499 # Test Strict Mode
500 _scratch_mkfs_casefold_strict >>$seqres.full 2>&1
501 _scratch_mount
502
503 test_strict_mode_invalid_filename
504
505 _scratch_unmount
506 _check_scratch_fs
507
508 status=0
509 exit