1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   *
4   * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
5   *
6   */
7  
8  #include <linux/kernel.h>
9  #include <linux/types.h>
10  
11  #include "ntfs_fs.h"
12  
upcase_unicode_char(const u16 * upcase,u16 chr)13  static inline u16 upcase_unicode_char(const u16 *upcase, u16 chr)
14  {
15  	if (chr < 'a')
16  		return chr;
17  
18  	if (chr <= 'z')
19  		return chr - ('a' - 'A');
20  
21  	return upcase[chr];
22  }
23  
24  /*
25   * ntfs_cmp_names
26   *
27   * Thanks Kari Argillander <kari.argillander@gmail.com> for idea and implementation 'bothcase'
28   *
29   * Straight way to compare names:
30   * - Case insensitive
31   * - If name equals and 'bothcases' then
32   * - Case sensitive
33   * 'Straight way' code scans input names twice in worst case.
34   * Optimized code scans input names only once.
35   */
ntfs_cmp_names(const __le16 * s1,size_t l1,const __le16 * s2,size_t l2,const u16 * upcase,bool bothcase)36  int ntfs_cmp_names(const __le16 *s1, size_t l1, const __le16 *s2, size_t l2,
37  		   const u16 *upcase, bool bothcase)
38  {
39  	int diff1 = 0;
40  	int diff2;
41  	size_t len = min(l1, l2);
42  
43  	if (!bothcase && upcase)
44  		goto case_insentive;
45  
46  	for (; len; s1++, s2++, len--) {
47  		diff1 = le16_to_cpu(*s1) - le16_to_cpu(*s2);
48  		if (diff1) {
49  			if (bothcase && upcase)
50  				goto case_insentive;
51  
52  			return diff1;
53  		}
54  	}
55  	return l1 - l2;
56  
57  case_insentive:
58  	for (; len; s1++, s2++, len--) {
59  		diff2 = upcase_unicode_char(upcase, le16_to_cpu(*s1)) -
60  			upcase_unicode_char(upcase, le16_to_cpu(*s2));
61  		if (diff2)
62  			return diff2;
63  	}
64  
65  	diff2 = l1 - l2;
66  	return diff2 ? diff2 : diff1;
67  }
68  
ntfs_cmp_names_cpu(const struct cpu_str * uni1,const struct le_str * uni2,const u16 * upcase,bool bothcase)69  int ntfs_cmp_names_cpu(const struct cpu_str *uni1, const struct le_str *uni2,
70  		       const u16 *upcase, bool bothcase)
71  {
72  	const u16 *s1 = uni1->name;
73  	const __le16 *s2 = uni2->name;
74  	size_t l1 = uni1->len;
75  	size_t l2 = uni2->len;
76  	size_t len = min(l1, l2);
77  	int diff1 = 0;
78  	int diff2;
79  
80  	if (!bothcase && upcase)
81  		goto case_insentive;
82  
83  	for (; len; s1++, s2++, len--) {
84  		diff1 = *s1 - le16_to_cpu(*s2);
85  		if (diff1) {
86  			if (bothcase && upcase)
87  				goto case_insentive;
88  
89  			return diff1;
90  		}
91  	}
92  	return l1 - l2;
93  
94  case_insentive:
95  	for (; len; s1++, s2++, len--) {
96  		diff2 = upcase_unicode_char(upcase, *s1) -
97  			upcase_unicode_char(upcase, le16_to_cpu(*s2));
98  		if (diff2)
99  			return diff2;
100  	}
101  
102  	diff2 = l1 - l2;
103  	return diff2 ? diff2 : diff1;
104  }
105  
106  /* Helper function for ntfs_d_hash. */
ntfs_names_hash(const u16 * name,size_t len,const u16 * upcase,unsigned long hash)107  unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase,
108  			      unsigned long hash)
109  {
110  	while (len--) {
111  		unsigned int c = upcase_unicode_char(upcase, *name++);
112  		hash = partial_name_hash(c, hash);
113  	}
114  
115  	return hash;
116  }
117