projects/linux·blob master · refs

754 lines · 18.6 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3 * linux/fs/hfsplus/unicode.c
4 *
5 * Copyright (C) 2001
6 * Brad Boyer ([email protected])
7 * (C) 2003 Ardis Technologies <[email protected]>
8 *
9 * Handler routines for unicode strings
10 */
11
12#include <linux/types.h>
13#include <linux/nls.h>
14
15#include <kunit/visibility.h>
16
17#include "hfsplus_fs.h"
18#include "hfsplus_raw.h"
19#include "unicode.h"
20
21/* Fold the case of a unicode char, given the 16 bit value */
22/* Returns folded char, or 0 if ignorable */
23static inline u16 case_fold(u16 c)
24{
25 u16 tmp;
26
27 tmp = hfsplus_case_fold_table[c >> 8];
28 if (tmp)
29 tmp = hfsplus_case_fold_table[tmp + (c & 0xff)];
30 else
31 tmp = c;
32 return tmp;
33}
34
35/* Compare unicode strings, return values like normal strcmp */
36int hfsplus_strcasecmp(const struct hfsplus_unistr *s1,
37 const struct hfsplus_unistr *s2)
38{
39 u16 len1, len2, c1, c2;
40 const hfsplus_unichr *p1, *p2;
41
42 len1 = be16_to_cpu(s1->length);
43 len2 = be16_to_cpu(s2->length);
44 p1 = s1->unicode;
45 p2 = s2->unicode;
46
47 if (len1 > HFSPLUS_MAX_STRLEN) {
48 len1 = HFSPLUS_MAX_STRLEN;
49 pr_err("invalid length %u has been corrected to %d\n",
50 be16_to_cpu(s1->length), len1);
51 }
52
53 if (len2 > HFSPLUS_MAX_STRLEN) {
54 len2 = HFSPLUS_MAX_STRLEN;
55 pr_err("invalid length %u has been corrected to %d\n",
56 be16_to_cpu(s2->length), len2);
57 }
58
59 while (1) {
60 c1 = c2 = 0;
61
62 while (len1 && !c1) {
63 c1 = case_fold(be16_to_cpu(*p1));
64 p1++;
65 len1--;
66 }
67 while (len2 && !c2) {
68 c2 = case_fold(be16_to_cpu(*p2));
69 p2++;
70 len2--;
71 }
72
73 if (c1 != c2)
74 return (c1 < c2) ? -1 : 1;
75 if (!c1 && !c2)
76 return 0;
77 }
78}
79EXPORT_SYMBOL_IF_KUNIT(hfsplus_strcasecmp);
80
81/* Compare names as a sequence of 16-bit unsigned integers */
82int hfsplus_strcmp(const struct hfsplus_unistr *s1,
83 const struct hfsplus_unistr *s2)
84{
85 u16 len1, len2, c1, c2;
86 const hfsplus_unichr *p1, *p2;
87 int len;
88
89 len1 = be16_to_cpu(s1->length);
90 len2 = be16_to_cpu(s2->length);
91 p1 = s1->unicode;
92 p2 = s2->unicode;
93
94 if (len1 > HFSPLUS_MAX_STRLEN) {
95 len1 = HFSPLUS_MAX_STRLEN;
96 pr_err("invalid length %u has been corrected to %d\n",
97 be16_to_cpu(s1->length), len1);
98 }
99
100 if (len2 > HFSPLUS_MAX_STRLEN) {
101 len2 = HFSPLUS_MAX_STRLEN;
102 pr_err("invalid length %u has been corrected to %d\n",
103 be16_to_cpu(s2->length), len2);
104 }
105
106 for (len = min(len1, len2); len > 0; len--) {
107 c1 = be16_to_cpu(*p1);
108 c2 = be16_to_cpu(*p2);
109 if (c1 != c2)
110 return c1 < c2 ? -1 : 1;
111 p1++;
112 p2++;
113 }
114
115 return len1 < len2 ? -1 :
116 len1 > len2 ? 1 : 0;
117}
118EXPORT_SYMBOL_IF_KUNIT(hfsplus_strcmp);
119
120#define Hangul_SBase 0xac00
121#define Hangul_LBase 0x1100
122#define Hangul_VBase 0x1161
123#define Hangul_TBase 0x11a7
124#define Hangul_SCount 11172
125#define Hangul_LCount 19
126#define Hangul_VCount 21
127#define Hangul_TCount 28
128#define Hangul_NCount (Hangul_VCount * Hangul_TCount)
129
130
131static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
132{
133 int i, s, e;
134
135 s = 1;
136 e = p[1];
137 if (!e || cc < p[s * 2] || cc > p[e * 2])
138 return NULL;
139 do {
140 i = (s + e) / 2;
141 if (cc > p[i * 2])
142 s = i + 1;
143 else if (cc < p[i * 2])
144 e = i - 1;
145 else
146 return hfsplus_compose_table + p[i * 2 + 1];
147 } while (s <= e);
148 return NULL;
149}
150
151/*
152 * In HFS+, a filename can contain / because : is the separator.
153 * The slash is a valid filename character on macOS.
154 * But on Linux, / is the path separator and
155 * it cannot appear in a filename component.
156 * There's a parallel mapping for the NUL character (0 -> U+2400).
157 * NUL terminates strings in C/POSIX but is valid in HFS+ filenames.
158 */
159static inline
160void hfsplus_mac2linux_compatibility_check(u16 symbol, u16 *conversion,
161 int name_type)
162{
163 *conversion = symbol;
164
165 switch (name_type) {
166 case HFS_XATTR_NAME:
167 /* ignore conversion */
168 return;
169
170 default:
171 /* continue logic */
172 break;
173 }
174
175 switch (symbol) {
176 case 0:
177 *conversion = 0x2400;
178 break;
179 case '/':
180 *conversion = ':';
181 break;
182 }
183}
184
185static int hfsplus_uni2asc(struct super_block *sb,
186 const struct hfsplus_unistr *ustr,
187 int max_len, char *astr, int *len_p,
188 int name_type)
189{
190 const hfsplus_unichr *ip;
191 struct nls_table *nls = HFSPLUS_SB(sb)->nls;
192 u8 *op;
193 u16 cc, c0, c1;
194 u16 *ce1, *ce2;
195 int i, len, ustrlen, res, compose;
196
197 op = astr;
198 ip = ustr->unicode;
199
200 ustrlen = be16_to_cpu(ustr->length);
201 if (ustrlen > max_len) {
202 ustrlen = max_len;
203 pr_err("invalid length %u has been corrected to %d\n",
204 be16_to_cpu(ustr->length), ustrlen);
205 }
206
207 len = *len_p;
208 ce1 = NULL;
209 compose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
210
211 while (ustrlen > 0) {
212 c0 = be16_to_cpu(*ip++);
213 ustrlen--;
214 /* search for single decomposed char */
215 if (likely(compose))
216 ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c0);
217 if (ce1)
218 cc = ce1[0];
219 else
220 cc = 0;
221 if (cc) {
222 /* start of a possibly decomposed Hangul char */
223 if (cc != 0xffff)
224 goto done;
225 if (!ustrlen)
226 goto same;
227 c1 = be16_to_cpu(*ip) - Hangul_VBase;
228 if (c1 < Hangul_VCount) {
229 /* compose the Hangul char */
230 cc = (c0 - Hangul_LBase) * Hangul_VCount;
231 cc = (cc + c1) * Hangul_TCount;
232 cc += Hangul_SBase;
233 ip++;
234 ustrlen--;
235 if (!ustrlen)
236 goto done;
237 c1 = be16_to_cpu(*ip) - Hangul_TBase;
238 if (c1 > 0 && c1 < Hangul_TCount) {
239 cc += c1;
240 ip++;
241 ustrlen--;
242 }
243 goto done;
244 }
245 }
246 while (1) {
247 /* main loop for common case of not composed chars */
248 if (!ustrlen)
249 goto same;
250 c1 = be16_to_cpu(*ip);
251 if (likely(compose))
252 ce1 = hfsplus_compose_lookup(
253 hfsplus_compose_table, c1);
254 if (ce1)
255 break;
256 hfsplus_mac2linux_compatibility_check(c0, &c0,
257 name_type);
258 res = nls->uni2char(c0, op, len);
259 if (res < 0) {
260 if (res == -ENAMETOOLONG)
261 goto out;
262 *op = '?';
263 res = 1;
264 }
265 op += res;
266 len -= res;
267 c0 = c1;
268 ip++;
269 ustrlen--;
270 }
271 ce2 = hfsplus_compose_lookup(ce1, c0);
272 if (ce2) {
273 i = 1;
274 while (i < ustrlen) {
275 ce1 = hfsplus_compose_lookup(ce2,
276 be16_to_cpu(ip[i]));
277 if (!ce1)
278 break;
279 i++;
280 ce2 = ce1;
281 }
282 cc = ce2[0];
283 if (cc) {
284 ip += i;
285 ustrlen -= i;
286 goto done;
287 }
288 }
289same:
290 hfsplus_mac2linux_compatibility_check(c0, &cc,
291 name_type);
292done:
293 res = nls->uni2char(cc, op, len);
294 if (res < 0) {
295 if (res == -ENAMETOOLONG)
296 goto out;
297 *op = '?';
298 res = 1;
299 }
300 op += res;
301 len -= res;
302 }
303 res = 0;
304out:
305 *len_p = (char *)op - astr;
306 return res;
307}
308
309inline int hfsplus_uni2asc_str(struct super_block *sb,
310 const struct hfsplus_unistr *ustr, char *astr,
311 int *len_p)
312{
313 return hfsplus_uni2asc(sb,
314 ustr, HFSPLUS_MAX_STRLEN,
315 astr, len_p,
316 HFS_REGULAR_NAME);
317}
318EXPORT_SYMBOL_IF_KUNIT(hfsplus_uni2asc_str);
319
320inline int hfsplus_uni2asc_xattr_str(struct super_block *sb,
321 const struct hfsplus_attr_unistr *ustr,
322 char *astr, int *len_p)
323{
324 return hfsplus_uni2asc(sb, (const struct hfsplus_unistr *)ustr,
325 HFSPLUS_ATTR_MAX_STRLEN, astr, len_p,
326 HFS_XATTR_NAME);
327}
328EXPORT_SYMBOL_IF_KUNIT(hfsplus_uni2asc_xattr_str);
329
330/*
331 * In HFS+, a filename can contain / because : is the separator.
332 * The slash is a valid filename character on macOS.
333 * But on Linux, / is the path separator and
334 * it cannot appear in a filename component.
335 * There's a parallel mapping for the NUL character (0 -> U+2400).
336 * NUL terminates strings in C/POSIX but is valid in HFS+ filenames.
337 */
338static inline
339void hfsplus_linux2mac_compatibility_check(wchar_t *uc, int name_type)
340{
341 switch (name_type) {
342 case HFS_XATTR_NAME:
343 /* ignore conversion */
344 return;
345
346 default:
347 /* continue logic */
348 break;
349 }
350
351 switch (*uc) {
352 case 0x2400:
353 *uc = 0;
354 break;
355 case ':':
356 *uc = '/';
357 break;
358 }
359}
360
361/*
362 * Convert one or more ASCII characters into a single unicode character.
363 * Returns the number of ASCII characters corresponding to the unicode char.
364 */
365static inline int asc2unichar(struct super_block *sb, const char *astr, int len,
366 wchar_t *uc, int name_type)
367{
368 int size = HFSPLUS_SB(sb)->nls->char2uni(astr, len, uc);
369
370 if (size <= 0) {
371 *uc = '?';
372 size = 1;
373 }
374
375 hfsplus_linux2mac_compatibility_check(uc, name_type);
376 return size;
377}
378
379/* Decomposes a non-Hangul unicode character. */
380static u16 *hfsplus_decompose_nonhangul(wchar_t uc, int *size)
381{
382 int off;
383
384 off = hfsplus_decompose_table[(uc >> 12) & 0xf];
385 if (off == 0 || off == 0xffff)
386 return NULL;
387
388 off = hfsplus_decompose_table[off + ((uc >> 8) & 0xf)];
389 if (!off)
390 return NULL;
391
392 off = hfsplus_decompose_table[off + ((uc >> 4) & 0xf)];
393 if (!off)
394 return NULL;
395
396 off = hfsplus_decompose_table[off + (uc & 0xf)];
397 *size = off & 3;
398 if (*size == 0)
399 return NULL;
400 return hfsplus_decompose_table + (off / 4);
401}
402
403/*
404 * Try to decompose a unicode character as Hangul. Return 0 if @uc is not
405 * precomposed Hangul, otherwise return the length of the decomposition.
406 *
407 * This function was adapted from sample code from the Unicode Standard
408 * Annex #15: Unicode Normalization Forms, version 3.2.0.
409 *
410 * Copyright (C) 1991-2018 Unicode, Inc. All rights reserved. Distributed
411 * under the Terms of Use in http://www.unicode.org/copyright.html.
412 */
413static int hfsplus_try_decompose_hangul(wchar_t uc, u16 *result)
414{
415 int index;
416 int l, v, t;
417
418 index = uc - Hangul_SBase;
419 if (index < 0 || index >= Hangul_SCount)
420 return 0;
421
422 l = Hangul_LBase + index / Hangul_NCount;
423 v = Hangul_VBase + (index % Hangul_NCount) / Hangul_TCount;
424 t = Hangul_TBase + index % Hangul_TCount;
425
426 result[0] = l;
427 result[1] = v;
428 if (t != Hangul_TBase) {
429 result[2] = t;
430 return 3;
431 }
432 return 2;
433}
434
435/* Decomposes a single unicode character. */
436static u16 *decompose_unichar(wchar_t uc, int *size, u16 *hangul_buffer)
437{
438 u16 *result;
439
440 /* Hangul is handled separately */
441 result = hangul_buffer;
442 *size = hfsplus_try_decompose_hangul(uc, result);
443 if (*size == 0)
444 result = hfsplus_decompose_nonhangul(uc, size);
445 if (!result) {
446 /*
447 * Not every character with a canonical decomposition is in
448 * Apple Technote #1150's own table above; a small, fixed
449 * set was only added to the decomposition standard (or had
450 * its decomposition corrected) after that table was
451 * generated. hfsplus_legacy_decompose() covers those.
452 */
453 const u16 *legacy = hfsplus_legacy_decompose(uc, size);
454
455 if (legacy)
456 result = memcpy(hangul_buffer, legacy,
457 *size * sizeof(*legacy));
458 }
459 return result;
460}
461
462/*
463 * Apply the Unicode Canonical Ordering Algorithm to a decomposed name held
464 * as plain host-order code units: within each maximal run of characters
465 * that have a nonzero combining class, stable-sort the run into ascending
466 * combining-class order. A character with combining class 0 always starts
467 * a new run and is never itself reordered.
468 *
469 * hfsplus_decompose_table decomposes each source character on its own; it
470 * says nothing about how the decompositions of two different source
471 * characters should be ordered relative to each other when both produce
472 * combining marks that end up adjacent. Without this pass, such a
473 * sequence can be stored in an order that macOS's own fsck_hfs
474 * (FixDecomps() in CatalogCheck.c) considers illegal, even though every
475 * individual character was decomposed correctly.
476 */
477static void hfsplus_canonical_reorder(u16 *ustr, int len)
478{
479 int i;
480
481 for (i = 1; i < len; i++) {
482 u8 cls = hfsplus_combining_class(ustr[i]);
483 int j = i;
484
485 if (!cls)
486 continue;
487
488 while (j > 0) {
489 u8 prev_cls = hfsplus_combining_class(ustr[j - 1]);
490 u16 tmp;
491
492 if (!prev_cls || prev_cls <= cls)
493 break;
494
495 tmp = ustr[j];
496 ustr[j] = ustr[j - 1];
497 ustr[j - 1] = tmp;
498 j--;
499 }
500 }
501}
502
503#define HFSPLUS_HANGUL_MAX_JAMO (3) /* L + V + optional T */
504
505static_assert(HFSPLUS_HANGUL_MAX_JAMO >= HFSPLUS_LEGACY_DECOMP_MAX_LEN,
506 "hangul_buffer must fit the longest legacy decomposition too");
507
508/*
509 * Decompose and canonically reorder an entire Linux name, as plain
510 * host-order code units. hfsplus_asc2uni(), hfsplus_hash_dentry() and
511 * hfsplus_compare_dentry() all go through this so that storage, hashing
512 * and comparison always agree on what a given name canonicalizes to.
513 *
514 * @out must hold at least @max_len entries, which must not exceed
515 * HFSPLUS_MAX_STRLEN. Returns the number of code units written. If
516 * @consumed is non-NULL, it is set to the number of input bytes actually
517 * consumed, which is less than @len when @out fills up first.
518 */
519static int hfsplus_decompose_str(struct super_block *sb, const char *astr,
520 int len, int max_len, int name_type,
521 u16 *out, int *consumed)
522{
523 int decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
524 const char *start = astr;
525 int outlen = 0;
526
527 while (outlen < max_len && len > 0) {
528 u16 *dstr;
529 u16 dhangul[HFSPLUS_HANGUL_MAX_JAMO];
530 int dsize, size;
531 wchar_t c;
532
533 size = asc2unichar(sb, astr, len, &c, name_type);
534
535 dstr = decompose ? decompose_unichar(c, &dsize, dhangul) : NULL;
536 if (dstr) {
537 if (outlen + dsize > max_len)
538 break;
539 do {
540 out[outlen++] = *dstr++;
541 } while (--dsize > 0);
542 } else {
543 out[outlen++] = c;
544 }
545
546 astr += size;
547 len -= size;
548 }
549
550 hfsplus_canonical_reorder(out, outlen);
551 hfsplus_fixup_legacy_sequences(out, &outlen);
552 if (consumed)
553 *consumed = astr - start;
554 return outlen;
555}
556
557int hfsplus_asc2uni(struct super_block *sb,
558 struct hfsplus_unistr *ustr, int max_unistr_len,
559 const char *astr, int len, int name_type)
560{
561 u16 buf[HFSPLUS_MAX_STRLEN];
562 int outlen, i, consumed;
563
564 if (max_unistr_len > HFSPLUS_MAX_STRLEN)
565 max_unistr_len = HFSPLUS_MAX_STRLEN;
566
567 outlen = hfsplus_decompose_str(sb, astr, len, max_unistr_len,
568 name_type, buf, &consumed);
569 for (i = 0; i < outlen; i++)
570 ustr->unicode[i] = cpu_to_be16(buf[i]);
571 ustr->length = cpu_to_be16(outlen);
572
573 if (consumed < len)
574 return -ENAMETOOLONG;
575 return 0;
576}
577EXPORT_SYMBOL_IF_KUNIT(hfsplus_asc2uni);
578
579/*
580 * Maximum length of a single maximal run of nonzero-combining-class code
581 * units that hfsplus_decompose_iter_next() below will canonically
582 * reorder. Every code unit with combining class 0 starts a new run, so
583 * this only bounds how many *consecutive* combining marks between two
584 * base characters get sorted - real text, and even deliberately
585 * adversarial "Zalgo" text, essentially never approaches this. Keeping
586 * it small means hfsplus_hash_dentry() and hfsplus_compare_dentry() only
587 * ever need a tiny amount of lookahead state, rather than buffering an
588 * entire (up to 255-unit) name.
589 */
590#define HFSPLUS_CCC_RUN_MAX 32
591
592/*
593 * Iterator that produces the canonically-ordered, decomposed code units
594 * of a Linux name one at a time, without materializing the whole name.
595 * hfsplus_hash_dentry() and hfsplus_compare_dentry() use this so that
596 * hashing and comparison always agree with what hfsplus_asc2uni() would
597 * actually store, while still comparing lazily (stopping at the first
598 * difference) the way this code did before canonical reordering existed.
599 */
600struct hfsplus_decompose_iter {
601 struct super_block *sb;
602 const char *astr;
603 int len;
604 int name_type;
605 int decompose;
606
607 u16 run[HFSPLUS_CCC_RUN_MAX];
608 int run_len;
609 int run_pos;
610};
611
612static void hfsplus_decompose_iter_init(struct hfsplus_decompose_iter *it,
613 struct super_block *sb,
614 const char *astr, int len,
615 int name_type)
616{
617 it->sb = sb;
618 it->astr = astr;
619 it->len = len;
620 it->name_type = name_type;
621 it->decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
622 it->run_len = 0;
623 it->run_pos = 0;
624}
625
626/*
627 * Gather the next maximal run of nonzero-combining-class code units
628 * (starting with whatever character comes next, base or not) and
629 * canonically reorder just that run. A character is only included once
630 * we know the class of the first unit it produces, so decoding it is
631 * speculative until that's decided.
632 */
633static bool hfsplus_decompose_iter_refill(struct hfsplus_decompose_iter *it)
634{
635 it->run_pos = 0;
636 it->run_len = 0;
637
638 while (it->len > 0) {
639 u16 *dstr;
640 u16 dhangul[HFSPLUS_HANGUL_MAX_JAMO];
641 int dsize, size;
642 wchar_t c;
643
644 size = asc2unichar(it->sb, it->astr, it->len, &c,
645 it->name_type);
646
647 dstr = it->decompose ?
648 decompose_unichar(c, &dsize, dhangul) : NULL;
649 if (!dstr) {
650 dhangul[0] = c;
651 dstr = dhangul;
652 dsize = 1;
653 }
654
655 if (it->run_len > 0 && !hfsplus_combining_class(dstr[0]))
656 break;
657
658 if (it->run_len + dsize > HFSPLUS_CCC_RUN_MAX)
659 break;
660
661 it->astr += size;
662 it->len -= size;
663
664 do {
665 it->run[it->run_len++] = *dstr++;
666 } while (--dsize > 0);
667 }
668
669 hfsplus_canonical_reorder(it->run, it->run_len);
670 hfsplus_fixup_legacy_sequences(it->run, &it->run_len);
671 return it->run_len > 0;
672}
673
674/* Returns the next code unit, or a negative value once @it is exhausted. */
675static int hfsplus_decompose_iter_next(struct hfsplus_decompose_iter *it)
676{
677 if (it->run_pos >= it->run_len && !hfsplus_decompose_iter_refill(it))
678 return -1;
679 return it->run[it->run_pos++];
680}
681
682/*
683 * Returns the next code unit that matters for comparison/hashing: folded
684 * if @casefold, with any character folding to 0 ("ignorable") skipped
685 * entirely. Returns a negative value once @it is exhausted.
686 */
687static int hfsplus_decompose_iter_next_folded(struct hfsplus_decompose_iter *it,
688 int casefold)
689{
690 int c;
691
692 do {
693 c = hfsplus_decompose_iter_next(it);
694 if (c < 0)
695 return -1;
696 if (casefold)
697 c = case_fold(c);
698 } while (casefold && !c);
699
700 return c;
701}
702
703/*
704 * Hash a string to an integer as appropriate for the HFS+ filesystem.
705 * Composed unicode characters are decomposed and case-folding is performed
706 * if the appropriate bits are (un)set on the superblock.
707 */
708int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
709{
710 struct super_block *sb = dentry->d_sb;
711 int casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
712 struct hfsplus_decompose_iter it;
713 unsigned long hash;
714 int c;
715
716 hfsplus_decompose_iter_init(&it, sb, str->name, str->len,
717 HFS_REGULAR_NAME);
718
719 hash = init_name_hash(dentry);
720 while ((c = hfsplus_decompose_iter_next_folded(&it, casefold)) >= 0)
721 hash = partial_name_hash(c, hash);
722 str->hash = end_name_hash(hash);
723
724 return 0;
725}
726EXPORT_SYMBOL_IF_KUNIT(hfsplus_hash_dentry);
727
728/*
729 * Compare strings with HFS+ filename ordering.
730 * Composed unicode characters are decomposed and case-folding is performed
731 * if the appropriate bits are (un)set on the superblock.
732 */
733int hfsplus_compare_dentry(const struct dentry *dentry,
734 unsigned int len, const char *str, const struct qstr *name)
735{
736 struct super_block *sb = dentry->d_sb;
737 int casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
738 struct hfsplus_decompose_iter it1, it2;
739
740 hfsplus_decompose_iter_init(&it1, sb, str, len, HFS_REGULAR_NAME);
741 hfsplus_decompose_iter_init(&it2, sb, name->name, name->len,
742 HFS_REGULAR_NAME);
743
744 while (1) {
745 int c1 = hfsplus_decompose_iter_next_folded(&it1, casefold);
746 int c2 = hfsplus_decompose_iter_next_folded(&it2, casefold);
747
748 if (c1 < 0 || c2 < 0)
749 return c1 == c2 ? 0 : (c1 < 0 ? -1 : 1);
750 if (c1 != c2)
751 return c1 < c2 ? -1 : 1;
752 }
753}
754EXPORT_SYMBOL_IF_KUNIT(hfsplus_compare_dentry);