xref: /openbmc/linux/fs/ntfs3/upcase.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
14534a70bSKonstantin Komarov // SPDX-License-Identifier: GPL-2.0
24534a70bSKonstantin Komarov /*
34534a70bSKonstantin Komarov  *
44534a70bSKonstantin Komarov  * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
54534a70bSKonstantin Komarov  *
64534a70bSKonstantin Komarov  */
7e8b8e97fSKari Argillander 
8f9767661SKari Argillander #include <linux/kernel.h>
9f9767661SKari Argillander #include <linux/types.h>
104534a70bSKonstantin Komarov 
114534a70bSKonstantin Komarov #include "ntfs_fs.h"
124534a70bSKonstantin Komarov 
upcase_unicode_char(const u16 * upcase,u16 chr)134534a70bSKonstantin Komarov static inline u16 upcase_unicode_char(const u16 *upcase, u16 chr)
144534a70bSKonstantin Komarov {
154534a70bSKonstantin Komarov 	if (chr < 'a')
164534a70bSKonstantin Komarov 		return chr;
174534a70bSKonstantin Komarov 
184534a70bSKonstantin Komarov 	if (chr <= 'z')
194534a70bSKonstantin Komarov 		return chr - ('a' - 'A');
204534a70bSKonstantin Komarov 
214534a70bSKonstantin Komarov 	return upcase[chr];
224534a70bSKonstantin Komarov }
234534a70bSKonstantin Komarov 
244534a70bSKonstantin Komarov /*
25e8b8e97fSKari Argillander  * ntfs_cmp_names
26e8b8e97fSKari Argillander  *
274534a70bSKonstantin Komarov  * Thanks Kari Argillander <kari.argillander@gmail.com> for idea and implementation 'bothcase'
284534a70bSKonstantin Komarov  *
29f8d87ed9SColin Ian King  * Straight way to compare names:
30e8b8e97fSKari Argillander  * - Case insensitive
31e8b8e97fSKari Argillander  * - If name equals and 'bothcases' then
32e8b8e97fSKari Argillander  * - Case sensitive
33d3624466SKonstantin Komarov  * 'Straight way' code scans input names twice in worst case.
34e8b8e97fSKari Argillander  * Optimized code scans input names only once.
354534a70bSKonstantin Komarov  */
ntfs_cmp_names(const __le16 * s1,size_t l1,const __le16 * s2,size_t l2,const u16 * upcase,bool bothcase)364534a70bSKonstantin Komarov int ntfs_cmp_names(const __le16 *s1, size_t l1, const __le16 *s2, size_t l2,
374534a70bSKonstantin Komarov 		   const u16 *upcase, bool bothcase)
384534a70bSKonstantin Komarov {
394534a70bSKonstantin Komarov 	int diff1 = 0;
404534a70bSKonstantin Komarov 	int diff2;
414534a70bSKonstantin Komarov 	size_t len = min(l1, l2);
424534a70bSKonstantin Komarov 
434534a70bSKonstantin Komarov 	if (!bothcase && upcase)
444534a70bSKonstantin Komarov 		goto case_insentive;
454534a70bSKonstantin Komarov 
464534a70bSKonstantin Komarov 	for (; len; s1++, s2++, len--) {
474534a70bSKonstantin Komarov 		diff1 = le16_to_cpu(*s1) - le16_to_cpu(*s2);
484534a70bSKonstantin Komarov 		if (diff1) {
494534a70bSKonstantin Komarov 			if (bothcase && upcase)
504534a70bSKonstantin Komarov 				goto case_insentive;
514534a70bSKonstantin Komarov 
524534a70bSKonstantin Komarov 			return diff1;
534534a70bSKonstantin Komarov 		}
544534a70bSKonstantin Komarov 	}
554534a70bSKonstantin Komarov 	return l1 - l2;
564534a70bSKonstantin Komarov 
574534a70bSKonstantin Komarov case_insentive:
584534a70bSKonstantin Komarov 	for (; len; s1++, s2++, len--) {
594534a70bSKonstantin Komarov 		diff2 = upcase_unicode_char(upcase, le16_to_cpu(*s1)) -
604534a70bSKonstantin Komarov 			upcase_unicode_char(upcase, le16_to_cpu(*s2));
614534a70bSKonstantin Komarov 		if (diff2)
624534a70bSKonstantin Komarov 			return diff2;
634534a70bSKonstantin Komarov 	}
644534a70bSKonstantin Komarov 
654534a70bSKonstantin Komarov 	diff2 = l1 - l2;
664534a70bSKonstantin Komarov 	return diff2 ? diff2 : diff1;
674534a70bSKonstantin Komarov }
684534a70bSKonstantin Komarov 
ntfs_cmp_names_cpu(const struct cpu_str * uni1,const struct le_str * uni2,const u16 * upcase,bool bothcase)694534a70bSKonstantin Komarov int ntfs_cmp_names_cpu(const struct cpu_str *uni1, const struct le_str *uni2,
704534a70bSKonstantin Komarov 		       const u16 *upcase, bool bothcase)
714534a70bSKonstantin Komarov {
724534a70bSKonstantin Komarov 	const u16 *s1 = uni1->name;
734534a70bSKonstantin Komarov 	const __le16 *s2 = uni2->name;
744534a70bSKonstantin Komarov 	size_t l1 = uni1->len;
754534a70bSKonstantin Komarov 	size_t l2 = uni2->len;
764534a70bSKonstantin Komarov 	size_t len = min(l1, l2);
774534a70bSKonstantin Komarov 	int diff1 = 0;
784534a70bSKonstantin Komarov 	int diff2;
794534a70bSKonstantin Komarov 
804534a70bSKonstantin Komarov 	if (!bothcase && upcase)
814534a70bSKonstantin Komarov 		goto case_insentive;
824534a70bSKonstantin Komarov 
834534a70bSKonstantin Komarov 	for (; len; s1++, s2++, len--) {
844534a70bSKonstantin Komarov 		diff1 = *s1 - le16_to_cpu(*s2);
854534a70bSKonstantin Komarov 		if (diff1) {
864534a70bSKonstantin Komarov 			if (bothcase && upcase)
874534a70bSKonstantin Komarov 				goto case_insentive;
884534a70bSKonstantin Komarov 
894534a70bSKonstantin Komarov 			return diff1;
904534a70bSKonstantin Komarov 		}
914534a70bSKonstantin Komarov 	}
924534a70bSKonstantin Komarov 	return l1 - l2;
934534a70bSKonstantin Komarov 
944534a70bSKonstantin Komarov case_insentive:
954534a70bSKonstantin Komarov 	for (; len; s1++, s2++, len--) {
964534a70bSKonstantin Komarov 		diff2 = upcase_unicode_char(upcase, *s1) -
974534a70bSKonstantin Komarov 			upcase_unicode_char(upcase, le16_to_cpu(*s2));
984534a70bSKonstantin Komarov 		if (diff2)
994534a70bSKonstantin Komarov 			return diff2;
1004534a70bSKonstantin Komarov 	}
1014534a70bSKonstantin Komarov 
1024534a70bSKonstantin Komarov 	diff2 = l1 - l2;
1034534a70bSKonstantin Komarov 	return diff2 ? diff2 : diff1;
1044534a70bSKonstantin Komarov }
105*a3a956c7SKonstantin Komarov 
106*a3a956c7SKonstantin Komarov /* Helper function for ntfs_d_hash. */
ntfs_names_hash(const u16 * name,size_t len,const u16 * upcase,unsigned long hash)107*a3a956c7SKonstantin Komarov unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase,
108*a3a956c7SKonstantin Komarov 			      unsigned long hash)
109*a3a956c7SKonstantin Komarov {
110*a3a956c7SKonstantin Komarov 	while (len--) {
111*a3a956c7SKonstantin Komarov 		unsigned int c = upcase_unicode_char(upcase, *name++);
112*a3a956c7SKonstantin Komarov 		hash = partial_name_hash(c, hash);
113*a3a956c7SKonstantin Komarov 	}
114*a3a956c7SKonstantin Komarov 
115*a3a956c7SKonstantin Komarov 	return hash;
116*a3a956c7SKonstantin Komarov }
117