xref: /openbmc/linux/fs/hfsplus/unicode.c (revision 324ef39a)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/fs/hfsplus/unicode.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (C) 2001
51da177e4SLinus Torvalds  * Brad Boyer (flar@allandria.com)
61da177e4SLinus Torvalds  * (C) 2003 Ardis Technologies <roman@ardistech.com>
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Handler routines for unicode strings
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds #include <linux/types.h>
121da177e4SLinus Torvalds #include <linux/nls.h>
131da177e4SLinus Torvalds #include "hfsplus_fs.h"
141da177e4SLinus Torvalds #include "hfsplus_raw.h"
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds /* Fold the case of a unicode char, given the 16 bit value */
171da177e4SLinus Torvalds /* Returns folded char, or 0 if ignorable */
181da177e4SLinus Torvalds static inline u16 case_fold(u16 c)
191da177e4SLinus Torvalds {
201da177e4SLinus Torvalds 	u16 tmp;
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds 	tmp = hfsplus_case_fold_table[c >> 8];
231da177e4SLinus Torvalds 	if (tmp)
241da177e4SLinus Torvalds 		tmp = hfsplus_case_fold_table[tmp + (c & 0xff)];
251da177e4SLinus Torvalds 	else
261da177e4SLinus Torvalds 		tmp = c;
271da177e4SLinus Torvalds 	return tmp;
281da177e4SLinus Torvalds }
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds /* Compare unicode strings, return values like normal strcmp */
312179d372SDavid Elliott int hfsplus_strcasecmp(const struct hfsplus_unistr *s1,
322179d372SDavid Elliott 		       const struct hfsplus_unistr *s2)
331da177e4SLinus Torvalds {
341da177e4SLinus Torvalds 	u16 len1, len2, c1, c2;
351da177e4SLinus Torvalds 	const hfsplus_unichr *p1, *p2;
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds 	len1 = be16_to_cpu(s1->length);
381da177e4SLinus Torvalds 	len2 = be16_to_cpu(s2->length);
391da177e4SLinus Torvalds 	p1 = s1->unicode;
401da177e4SLinus Torvalds 	p2 = s2->unicode;
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds 	while (1) {
431da177e4SLinus Torvalds 		c1 = c2 = 0;
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds 		while (len1 && !c1) {
461da177e4SLinus Torvalds 			c1 = case_fold(be16_to_cpu(*p1));
471da177e4SLinus Torvalds 			p1++;
481da177e4SLinus Torvalds 			len1--;
491da177e4SLinus Torvalds 		}
501da177e4SLinus Torvalds 		while (len2 && !c2) {
511da177e4SLinus Torvalds 			c2 = case_fold(be16_to_cpu(*p2));
521da177e4SLinus Torvalds 			p2++;
531da177e4SLinus Torvalds 			len2--;
541da177e4SLinus Torvalds 		}
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds 		if (c1 != c2)
571da177e4SLinus Torvalds 			return (c1 < c2) ? -1 : 1;
581da177e4SLinus Torvalds 		if (!c1 && !c2)
591da177e4SLinus Torvalds 			return 0;
601da177e4SLinus Torvalds 	}
611da177e4SLinus Torvalds }
621da177e4SLinus Torvalds 
632179d372SDavid Elliott /* Compare names as a sequence of 16-bit unsigned integers */
642179d372SDavid Elliott int hfsplus_strcmp(const struct hfsplus_unistr *s1,
652179d372SDavid Elliott 		   const struct hfsplus_unistr *s2)
662179d372SDavid Elliott {
672179d372SDavid Elliott 	u16 len1, len2, c1, c2;
682179d372SDavid Elliott 	const hfsplus_unichr *p1, *p2;
692179d372SDavid Elliott 	int len;
702179d372SDavid Elliott 
712179d372SDavid Elliott 	len1 = be16_to_cpu(s1->length);
722179d372SDavid Elliott 	len2 = be16_to_cpu(s2->length);
732179d372SDavid Elliott 	p1 = s1->unicode;
742179d372SDavid Elliott 	p2 = s2->unicode;
752179d372SDavid Elliott 
762179d372SDavid Elliott 	for (len = min(len1, len2); len > 0; len--) {
772179d372SDavid Elliott 		c1 = be16_to_cpu(*p1);
782179d372SDavid Elliott 		c2 = be16_to_cpu(*p2);
792179d372SDavid Elliott 		if (c1 != c2)
802179d372SDavid Elliott 			return c1 < c2 ? -1 : 1;
812179d372SDavid Elliott 		p1++;
822179d372SDavid Elliott 		p2++;
832179d372SDavid Elliott 	}
842179d372SDavid Elliott 
852179d372SDavid Elliott 	return len1 < len2 ? -1 :
862179d372SDavid Elliott 	       len1 > len2 ? 1 : 0;
872179d372SDavid Elliott }
882179d372SDavid Elliott 
892179d372SDavid Elliott 
901da177e4SLinus Torvalds #define Hangul_SBase	0xac00
911da177e4SLinus Torvalds #define Hangul_LBase	0x1100
921da177e4SLinus Torvalds #define Hangul_VBase	0x1161
931da177e4SLinus Torvalds #define Hangul_TBase	0x11a7
941da177e4SLinus Torvalds #define Hangul_SCount	11172
951da177e4SLinus Torvalds #define Hangul_LCount	19
961da177e4SLinus Torvalds #define Hangul_VCount	21
971da177e4SLinus Torvalds #define Hangul_TCount	28
981da177e4SLinus Torvalds #define Hangul_NCount	(Hangul_VCount * Hangul_TCount)
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
1021da177e4SLinus Torvalds {
1031da177e4SLinus Torvalds 	int i, s, e;
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 	s = 1;
1061da177e4SLinus Torvalds 	e = p[1];
1071da177e4SLinus Torvalds 	if (!e || cc < p[s * 2] || cc > p[e * 2])
1081da177e4SLinus Torvalds 		return NULL;
1091da177e4SLinus Torvalds 	do {
1101da177e4SLinus Torvalds 		i = (s + e) / 2;
1111da177e4SLinus Torvalds 		if (cc > p[i * 2])
1121da177e4SLinus Torvalds 			s = i + 1;
1131da177e4SLinus Torvalds 		else if (cc < p[i * 2])
1141da177e4SLinus Torvalds 			e = i - 1;
1151da177e4SLinus Torvalds 		else
1161da177e4SLinus Torvalds 			return hfsplus_compose_table + p[i * 2 + 1];
1171da177e4SLinus Torvalds 	} while (s <= e);
1181da177e4SLinus Torvalds 	return NULL;
1191da177e4SLinus Torvalds }
1201da177e4SLinus Torvalds 
1212753cc28SAnton Salikhmetov int hfsplus_uni2asc(struct super_block *sb,
1222753cc28SAnton Salikhmetov 		const struct hfsplus_unistr *ustr,
1232753cc28SAnton Salikhmetov 		char *astr, int *len_p)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds 	const hfsplus_unichr *ip;
126dd73a01aSChristoph Hellwig 	struct nls_table *nls = HFSPLUS_SB(sb)->nls;
1271da177e4SLinus Torvalds 	u8 *op;
1281da177e4SLinus Torvalds 	u16 cc, c0, c1;
1291da177e4SLinus Torvalds 	u16 *ce1, *ce2;
1301da177e4SLinus Torvalds 	int i, len, ustrlen, res, compose;
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 	op = astr;
1331da177e4SLinus Torvalds 	ip = ustr->unicode;
1341da177e4SLinus Torvalds 	ustrlen = be16_to_cpu(ustr->length);
1351da177e4SLinus Torvalds 	len = *len_p;
1361da177e4SLinus Torvalds 	ce1 = NULL;
13784adede3SChristoph Hellwig 	compose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	while (ustrlen > 0) {
1401da177e4SLinus Torvalds 		c0 = be16_to_cpu(*ip++);
1411da177e4SLinus Torvalds 		ustrlen--;
1421da177e4SLinus Torvalds 		/* search for single decomposed char */
1431da177e4SLinus Torvalds 		if (likely(compose))
1441da177e4SLinus Torvalds 			ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c0);
1452b4f9ca8SAnton Salikhmetov 		if (ce1)
1462b4f9ca8SAnton Salikhmetov 			cc = ce1[0];
1472b4f9ca8SAnton Salikhmetov 		else
1482b4f9ca8SAnton Salikhmetov 			cc = 0;
1492b4f9ca8SAnton Salikhmetov 		if (cc) {
1501da177e4SLinus Torvalds 			/* start of a possibly decomposed Hangul char */
1511da177e4SLinus Torvalds 			if (cc != 0xffff)
1521da177e4SLinus Torvalds 				goto done;
1531da177e4SLinus Torvalds 			if (!ustrlen)
1541da177e4SLinus Torvalds 				goto same;
1551da177e4SLinus Torvalds 			c1 = be16_to_cpu(*ip) - Hangul_VBase;
1561da177e4SLinus Torvalds 			if (c1 < Hangul_VCount) {
1571da177e4SLinus Torvalds 				/* compose the Hangul char */
1581da177e4SLinus Torvalds 				cc = (c0 - Hangul_LBase) * Hangul_VCount;
1591da177e4SLinus Torvalds 				cc = (cc + c1) * Hangul_TCount;
1601da177e4SLinus Torvalds 				cc += Hangul_SBase;
1611da177e4SLinus Torvalds 				ip++;
1621da177e4SLinus Torvalds 				ustrlen--;
1631da177e4SLinus Torvalds 				if (!ustrlen)
1641da177e4SLinus Torvalds 					goto done;
1651da177e4SLinus Torvalds 				c1 = be16_to_cpu(*ip) - Hangul_TBase;
1661da177e4SLinus Torvalds 				if (c1 > 0 && c1 < Hangul_TCount) {
1671da177e4SLinus Torvalds 					cc += c1;
1681da177e4SLinus Torvalds 					ip++;
1691da177e4SLinus Torvalds 					ustrlen--;
1701da177e4SLinus Torvalds 				}
1711da177e4SLinus Torvalds 				goto done;
1721da177e4SLinus Torvalds 			}
1731da177e4SLinus Torvalds 		}
1741da177e4SLinus Torvalds 		while (1) {
1751da177e4SLinus Torvalds 			/* main loop for common case of not composed chars */
1761da177e4SLinus Torvalds 			if (!ustrlen)
1771da177e4SLinus Torvalds 				goto same;
1781da177e4SLinus Torvalds 			c1 = be16_to_cpu(*ip);
1791da177e4SLinus Torvalds 			if (likely(compose))
1802753cc28SAnton Salikhmetov 				ce1 = hfsplus_compose_lookup(
1812753cc28SAnton Salikhmetov 					hfsplus_compose_table, c1);
1821da177e4SLinus Torvalds 			if (ce1)
1831da177e4SLinus Torvalds 				break;
1841da177e4SLinus Torvalds 			switch (c0) {
1851da177e4SLinus Torvalds 			case 0:
1861da177e4SLinus Torvalds 				c0 = 0x2400;
1871da177e4SLinus Torvalds 				break;
1881da177e4SLinus Torvalds 			case '/':
1891da177e4SLinus Torvalds 				c0 = ':';
1901da177e4SLinus Torvalds 				break;
1911da177e4SLinus Torvalds 			}
1921da177e4SLinus Torvalds 			res = nls->uni2char(c0, op, len);
1931da177e4SLinus Torvalds 			if (res < 0) {
1941da177e4SLinus Torvalds 				if (res == -ENAMETOOLONG)
1951da177e4SLinus Torvalds 					goto out;
1961da177e4SLinus Torvalds 				*op = '?';
1971da177e4SLinus Torvalds 				res = 1;
1981da177e4SLinus Torvalds 			}
1991da177e4SLinus Torvalds 			op += res;
2001da177e4SLinus Torvalds 			len -= res;
2011da177e4SLinus Torvalds 			c0 = c1;
2021da177e4SLinus Torvalds 			ip++;
2031da177e4SLinus Torvalds 			ustrlen--;
2041da177e4SLinus Torvalds 		}
2051da177e4SLinus Torvalds 		ce2 = hfsplus_compose_lookup(ce1, c0);
2061da177e4SLinus Torvalds 		if (ce2) {
2071da177e4SLinus Torvalds 			i = 1;
2081da177e4SLinus Torvalds 			while (i < ustrlen) {
2092753cc28SAnton Salikhmetov 				ce1 = hfsplus_compose_lookup(ce2,
2102753cc28SAnton Salikhmetov 					be16_to_cpu(ip[i]));
2111da177e4SLinus Torvalds 				if (!ce1)
2121da177e4SLinus Torvalds 					break;
2131da177e4SLinus Torvalds 				i++;
2141da177e4SLinus Torvalds 				ce2 = ce1;
2151da177e4SLinus Torvalds 			}
2162b4f9ca8SAnton Salikhmetov 			cc = ce2[0];
2172b4f9ca8SAnton Salikhmetov 			if (cc) {
2181da177e4SLinus Torvalds 				ip += i;
2191da177e4SLinus Torvalds 				ustrlen -= i;
2201da177e4SLinus Torvalds 				goto done;
2211da177e4SLinus Torvalds 			}
2221da177e4SLinus Torvalds 		}
2231da177e4SLinus Torvalds same:
2241da177e4SLinus Torvalds 		switch (c0) {
2251da177e4SLinus Torvalds 		case 0:
2261da177e4SLinus Torvalds 			cc = 0x2400;
2271da177e4SLinus Torvalds 			break;
2281da177e4SLinus Torvalds 		case '/':
2291da177e4SLinus Torvalds 			cc = ':';
2301da177e4SLinus Torvalds 			break;
2311da177e4SLinus Torvalds 		default:
2321da177e4SLinus Torvalds 			cc = c0;
2331da177e4SLinus Torvalds 		}
2341da177e4SLinus Torvalds done:
2351da177e4SLinus Torvalds 		res = nls->uni2char(cc, op, len);
2361da177e4SLinus Torvalds 		if (res < 0) {
2371da177e4SLinus Torvalds 			if (res == -ENAMETOOLONG)
2381da177e4SLinus Torvalds 				goto out;
2391da177e4SLinus Torvalds 			*op = '?';
2401da177e4SLinus Torvalds 			res = 1;
2411da177e4SLinus Torvalds 		}
2421da177e4SLinus Torvalds 		op += res;
2431da177e4SLinus Torvalds 		len -= res;
2441da177e4SLinus Torvalds 	}
2451da177e4SLinus Torvalds 	res = 0;
2461da177e4SLinus Torvalds out:
2471da177e4SLinus Torvalds 	*len_p = (char *)op - astr;
2481da177e4SLinus Torvalds 	return res;
2491da177e4SLinus Torvalds }
2501da177e4SLinus Torvalds 
2511e96b7caSDuane Griffin /*
2521e96b7caSDuane Griffin  * Convert one or more ASCII characters into a single unicode character.
2531e96b7caSDuane Griffin  * Returns the number of ASCII characters corresponding to the unicode char.
2541e96b7caSDuane Griffin  */
2551e96b7caSDuane Griffin static inline int asc2unichar(struct super_block *sb, const char *astr, int len,
2561e96b7caSDuane Griffin 			      wchar_t *uc)
2571da177e4SLinus Torvalds {
258dd73a01aSChristoph Hellwig 	int size = HFSPLUS_SB(sb)->nls->char2uni(astr, len, uc);
2591da177e4SLinus Torvalds 	if (size <= 0) {
2601e96b7caSDuane Griffin 		*uc = '?';
2611da177e4SLinus Torvalds 		size = 1;
2621da177e4SLinus Torvalds 	}
2631e96b7caSDuane Griffin 	switch (*uc) {
2641da177e4SLinus Torvalds 	case 0x2400:
2651e96b7caSDuane Griffin 		*uc = 0;
2661da177e4SLinus Torvalds 		break;
2671da177e4SLinus Torvalds 	case ':':
2681e96b7caSDuane Griffin 		*uc = '/';
2691da177e4SLinus Torvalds 		break;
2701da177e4SLinus Torvalds 	}
2711e96b7caSDuane Griffin 	return size;
2721da177e4SLinus Torvalds }
2731e96b7caSDuane Griffin 
2741e96b7caSDuane Griffin /* Decomposes a single unicode character. */
2751e96b7caSDuane Griffin static inline u16 *decompose_unichar(wchar_t uc, int *size)
2761e96b7caSDuane Griffin {
2771e96b7caSDuane Griffin 	int off;
2781e96b7caSDuane Griffin 
2791e96b7caSDuane Griffin 	off = hfsplus_decompose_table[(uc >> 12) & 0xf];
2801e96b7caSDuane Griffin 	if (off == 0 || off == 0xffff)
2811e96b7caSDuane Griffin 		return NULL;
2821e96b7caSDuane Griffin 
2831e96b7caSDuane Griffin 	off = hfsplus_decompose_table[off + ((uc >> 8) & 0xf)];
2841da177e4SLinus Torvalds 	if (!off)
2851e96b7caSDuane Griffin 		return NULL;
2861e96b7caSDuane Griffin 
2871e96b7caSDuane Griffin 	off = hfsplus_decompose_table[off + ((uc >> 4) & 0xf)];
2881da177e4SLinus Torvalds 	if (!off)
2891e96b7caSDuane Griffin 		return NULL;
2901e96b7caSDuane Griffin 
2911e96b7caSDuane Griffin 	off = hfsplus_decompose_table[off + (uc & 0xf)];
2921e96b7caSDuane Griffin 	*size = off & 3;
2931e96b7caSDuane Griffin 	if (*size == 0)
2941e96b7caSDuane Griffin 		return NULL;
2951e96b7caSDuane Griffin 	return hfsplus_decompose_table + (off / 4);
2961e96b7caSDuane Griffin }
2971e96b7caSDuane Griffin 
298324ef39aSVyacheslav Dubeyko int hfsplus_asc2uni(struct super_block *sb,
299324ef39aSVyacheslav Dubeyko 		    struct hfsplus_unistr *ustr, int max_unistr_len,
3001e96b7caSDuane Griffin 		    const char *astr, int len)
3011e96b7caSDuane Griffin {
3021e96b7caSDuane Griffin 	int size, dsize, decompose;
3031e96b7caSDuane Griffin 	u16 *dstr, outlen = 0;
3041e96b7caSDuane Griffin 	wchar_t c;
3051e96b7caSDuane Griffin 
30684adede3SChristoph Hellwig 	decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
307324ef39aSVyacheslav Dubeyko 	while (outlen < max_unistr_len && len > 0) {
3081e96b7caSDuane Griffin 		size = asc2unichar(sb, astr, len, &c);
3091e96b7caSDuane Griffin 
3102b4f9ca8SAnton Salikhmetov 		if (decompose)
3112b4f9ca8SAnton Salikhmetov 			dstr = decompose_unichar(c, &dsize);
3122b4f9ca8SAnton Salikhmetov 		else
3132b4f9ca8SAnton Salikhmetov 			dstr = NULL;
3142b4f9ca8SAnton Salikhmetov 		if (dstr) {
315324ef39aSVyacheslav Dubeyko 			if (outlen + dsize > max_unistr_len)
3161da177e4SLinus Torvalds 				break;
3171da177e4SLinus Torvalds 			do {
3181e96b7caSDuane Griffin 				ustr->unicode[outlen++] = cpu_to_be16(*dstr++);
3191e96b7caSDuane Griffin 			} while (--dsize > 0);
3201e96b7caSDuane Griffin 		} else
3211da177e4SLinus Torvalds 			ustr->unicode[outlen++] = cpu_to_be16(c);
3221e96b7caSDuane Griffin 
3231e96b7caSDuane Griffin 		astr += size;
3241e96b7caSDuane Griffin 		len -= size;
3251da177e4SLinus Torvalds 	}
3261da177e4SLinus Torvalds 	ustr->length = cpu_to_be16(outlen);
3271da177e4SLinus Torvalds 	if (len > 0)
3281da177e4SLinus Torvalds 		return -ENAMETOOLONG;
3291da177e4SLinus Torvalds 	return 0;
3301da177e4SLinus Torvalds }
331d45bce8fSDuane Griffin 
332d45bce8fSDuane Griffin /*
333d45bce8fSDuane Griffin  * Hash a string to an integer as appropriate for the HFS+ filesystem.
334d45bce8fSDuane Griffin  * Composed unicode characters are decomposed and case-folding is performed
335d45bce8fSDuane Griffin  * if the appropriate bits are (un)set on the superblock.
336d45bce8fSDuane Griffin  */
337b1e6a015SNick Piggin int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode,
338b1e6a015SNick Piggin 		struct qstr *str)
339d45bce8fSDuane Griffin {
340d45bce8fSDuane Griffin 	struct super_block *sb = dentry->d_sb;
341d45bce8fSDuane Griffin 	const char *astr;
342d45bce8fSDuane Griffin 	const u16 *dstr;
3438aa84ab9SAndrew Morton 	int casefold, decompose, size, len;
344d45bce8fSDuane Griffin 	unsigned long hash;
345d45bce8fSDuane Griffin 	wchar_t c;
346d45bce8fSDuane Griffin 	u16 c2;
347d45bce8fSDuane Griffin 
34884adede3SChristoph Hellwig 	casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
34984adede3SChristoph Hellwig 	decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
350d45bce8fSDuane Griffin 	hash = init_name_hash();
351d45bce8fSDuane Griffin 	astr = str->name;
352d45bce8fSDuane Griffin 	len = str->len;
353d45bce8fSDuane Griffin 	while (len > 0) {
3548aa84ab9SAndrew Morton 		int uninitialized_var(dsize);
355d45bce8fSDuane Griffin 		size = asc2unichar(sb, astr, len, &c);
356d45bce8fSDuane Griffin 		astr += size;
357d45bce8fSDuane Griffin 		len -= size;
358d45bce8fSDuane Griffin 
3592b4f9ca8SAnton Salikhmetov 		if (decompose)
3602b4f9ca8SAnton Salikhmetov 			dstr = decompose_unichar(c, &dsize);
3612b4f9ca8SAnton Salikhmetov 		else
3622b4f9ca8SAnton Salikhmetov 			dstr = NULL;
3632b4f9ca8SAnton Salikhmetov 		if (dstr) {
364d45bce8fSDuane Griffin 			do {
365d45bce8fSDuane Griffin 				c2 = *dstr++;
3662b4f9ca8SAnton Salikhmetov 				if (casefold)
3672b4f9ca8SAnton Salikhmetov 					c2 = case_fold(c2);
3682b4f9ca8SAnton Salikhmetov 				if (!casefold || c2)
369d45bce8fSDuane Griffin 					hash = partial_name_hash(c2, hash);
370d45bce8fSDuane Griffin 			} while (--dsize > 0);
371d45bce8fSDuane Griffin 		} else {
372d45bce8fSDuane Griffin 			c2 = c;
3732b4f9ca8SAnton Salikhmetov 			if (casefold)
3742b4f9ca8SAnton Salikhmetov 				c2 = case_fold(c2);
3752b4f9ca8SAnton Salikhmetov 			if (!casefold || c2)
376d45bce8fSDuane Griffin 				hash = partial_name_hash(c2, hash);
377d45bce8fSDuane Griffin 		}
378d45bce8fSDuane Griffin 	}
379d45bce8fSDuane Griffin 	str->hash = end_name_hash(hash);
380d45bce8fSDuane Griffin 
381d45bce8fSDuane Griffin 	return 0;
382d45bce8fSDuane Griffin }
383d45bce8fSDuane Griffin 
384d45bce8fSDuane Griffin /*
385d45bce8fSDuane Griffin  * Compare strings with HFS+ filename ordering.
386d45bce8fSDuane Griffin  * Composed unicode characters are decomposed and case-folding is performed
387d45bce8fSDuane Griffin  * if the appropriate bits are (un)set on the superblock.
388d45bce8fSDuane Griffin  */
389621e155aSNick Piggin int hfsplus_compare_dentry(const struct dentry *parent,
390621e155aSNick Piggin 		const struct inode *pinode,
391621e155aSNick Piggin 		const struct dentry *dentry, const struct inode *inode,
392621e155aSNick Piggin 		unsigned int len, const char *str, const struct qstr *name)
393d45bce8fSDuane Griffin {
394621e155aSNick Piggin 	struct super_block *sb = parent->d_sb;
395d45bce8fSDuane Griffin 	int casefold, decompose, size;
396d45bce8fSDuane Griffin 	int dsize1, dsize2, len1, len2;
397d45bce8fSDuane Griffin 	const u16 *dstr1, *dstr2;
398d45bce8fSDuane Griffin 	const char *astr1, *astr2;
399d45bce8fSDuane Griffin 	u16 c1, c2;
400d45bce8fSDuane Griffin 	wchar_t c;
401d45bce8fSDuane Griffin 
40284adede3SChristoph Hellwig 	casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
40384adede3SChristoph Hellwig 	decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
404621e155aSNick Piggin 	astr1 = str;
405621e155aSNick Piggin 	len1 = len;
406621e155aSNick Piggin 	astr2 = name->name;
407621e155aSNick Piggin 	len2 = name->len;
408d45bce8fSDuane Griffin 	dsize1 = dsize2 = 0;
409d45bce8fSDuane Griffin 	dstr1 = dstr2 = NULL;
410d45bce8fSDuane Griffin 
411d45bce8fSDuane Griffin 	while (len1 > 0 && len2 > 0) {
412d45bce8fSDuane Griffin 		if (!dsize1) {
413d45bce8fSDuane Griffin 			size = asc2unichar(sb, astr1, len1, &c);
414d45bce8fSDuane Griffin 			astr1 += size;
415d45bce8fSDuane Griffin 			len1 -= size;
416d45bce8fSDuane Griffin 
4172753cc28SAnton Salikhmetov 			if (decompose)
4182753cc28SAnton Salikhmetov 				dstr1 = decompose_unichar(c, &dsize1);
4192753cc28SAnton Salikhmetov 			if (!decompose || !dstr1) {
420d45bce8fSDuane Griffin 				c1 = c;
421d45bce8fSDuane Griffin 				dstr1 = &c1;
422d45bce8fSDuane Griffin 				dsize1 = 1;
423d45bce8fSDuane Griffin 			}
424d45bce8fSDuane Griffin 		}
425d45bce8fSDuane Griffin 
426d45bce8fSDuane Griffin 		if (!dsize2) {
427d45bce8fSDuane Griffin 			size = asc2unichar(sb, astr2, len2, &c);
428d45bce8fSDuane Griffin 			astr2 += size;
429d45bce8fSDuane Griffin 			len2 -= size;
430d45bce8fSDuane Griffin 
4312753cc28SAnton Salikhmetov 			if (decompose)
4322753cc28SAnton Salikhmetov 				dstr2 = decompose_unichar(c, &dsize2);
4332753cc28SAnton Salikhmetov 			if (!decompose || !dstr2) {
434d45bce8fSDuane Griffin 				c2 = c;
435d45bce8fSDuane Griffin 				dstr2 = &c2;
436d45bce8fSDuane Griffin 				dsize2 = 1;
437d45bce8fSDuane Griffin 			}
438d45bce8fSDuane Griffin 		}
439d45bce8fSDuane Griffin 
440d45bce8fSDuane Griffin 		c1 = *dstr1;
441d45bce8fSDuane Griffin 		c2 = *dstr2;
442d45bce8fSDuane Griffin 		if (casefold) {
4432b4f9ca8SAnton Salikhmetov 			c1 = case_fold(c1);
4442b4f9ca8SAnton Salikhmetov 			if (!c1) {
445d45bce8fSDuane Griffin 				dstr1++;
446d45bce8fSDuane Griffin 				dsize1--;
447d45bce8fSDuane Griffin 				continue;
448d45bce8fSDuane Griffin 			}
4492b4f9ca8SAnton Salikhmetov 			c2 = case_fold(c2);
4502b4f9ca8SAnton Salikhmetov 			if (!c2) {
451d45bce8fSDuane Griffin 				dstr2++;
452d45bce8fSDuane Griffin 				dsize2--;
453d45bce8fSDuane Griffin 				continue;
454d45bce8fSDuane Griffin 			}
455d45bce8fSDuane Griffin 		}
456d45bce8fSDuane Griffin 		if (c1 < c2)
457d45bce8fSDuane Griffin 			return -1;
458d45bce8fSDuane Griffin 		else if (c1 > c2)
459d45bce8fSDuane Griffin 			return 1;
460d45bce8fSDuane Griffin 
461d45bce8fSDuane Griffin 		dstr1++;
462d45bce8fSDuane Griffin 		dsize1--;
463d45bce8fSDuane Griffin 		dstr2++;
464d45bce8fSDuane Griffin 		dsize2--;
465d45bce8fSDuane Griffin 	}
466d45bce8fSDuane Griffin 
467d45bce8fSDuane Griffin 	if (len1 < len2)
468d45bce8fSDuane Griffin 		return -1;
469d45bce8fSDuane Griffin 	if (len1 > len2)
470d45bce8fSDuane Griffin 		return 1;
471d45bce8fSDuane Griffin 	return 0;
472d45bce8fSDuane Griffin }
473