xref: /linux/fs/ntfs3/upcase.c (revision 9052e9c95d908d6c3d7570aadc8898e1d871c8bb)
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/blkdev.h>
9 #include <linux/buffer_head.h>
10 #include <linux/module.h>
11 #include <linux/nls.h>
12 
13 #include "debug.h"
14 #include "ntfs.h"
15 #include "ntfs_fs.h"
16 
17 static inline u16 upcase_unicode_char(const u16 *upcase, u16 chr)
18 {
19 	if (chr < 'a')
20 		return chr;
21 
22 	if (chr <= 'z')
23 		return chr - ('a' - 'A');
24 
25 	return upcase[chr];
26 }
27 
28 /*
29  * ntfs_cmp_names
30  *
31  * Thanks Kari Argillander <kari.argillander@gmail.com> for idea and implementation 'bothcase'
32  *
33  * Straight way to compare names:
34  * - Case insensitive
35  * - If name equals and 'bothcases' then
36  * - Case sensitive
37  * 'Straight way' code scans input names twice in worst case.
38  * Optimized code scans input names only once.
39  */
40 int ntfs_cmp_names(const __le16 *s1, size_t l1, const __le16 *s2, size_t l2,
41 		   const u16 *upcase, bool bothcase)
42 {
43 	int diff1 = 0;
44 	int diff2;
45 	size_t len = min(l1, l2);
46 
47 	if (!bothcase && upcase)
48 		goto case_insentive;
49 
50 	for (; len; s1++, s2++, len--) {
51 		diff1 = le16_to_cpu(*s1) - le16_to_cpu(*s2);
52 		if (diff1) {
53 			if (bothcase && upcase)
54 				goto case_insentive;
55 
56 			return diff1;
57 		}
58 	}
59 	return l1 - l2;
60 
61 case_insentive:
62 	for (; len; s1++, s2++, len--) {
63 		diff2 = upcase_unicode_char(upcase, le16_to_cpu(*s1)) -
64 			upcase_unicode_char(upcase, le16_to_cpu(*s2));
65 		if (diff2)
66 			return diff2;
67 	}
68 
69 	diff2 = l1 - l2;
70 	return diff2 ? diff2 : diff1;
71 }
72 
73 int ntfs_cmp_names_cpu(const struct cpu_str *uni1, const struct le_str *uni2,
74 		       const u16 *upcase, bool bothcase)
75 {
76 	const u16 *s1 = uni1->name;
77 	const __le16 *s2 = uni2->name;
78 	size_t l1 = uni1->len;
79 	size_t l2 = uni2->len;
80 	size_t len = min(l1, l2);
81 	int diff1 = 0;
82 	int diff2;
83 
84 	if (!bothcase && upcase)
85 		goto case_insentive;
86 
87 	for (; len; s1++, s2++, len--) {
88 		diff1 = *s1 - le16_to_cpu(*s2);
89 		if (diff1) {
90 			if (bothcase && upcase)
91 				goto case_insentive;
92 
93 			return diff1;
94 		}
95 	}
96 	return l1 - l2;
97 
98 case_insentive:
99 	for (; len; s1++, s2++, len--) {
100 		diff2 = upcase_unicode_char(upcase, *s1) -
101 			upcase_unicode_char(upcase, le16_to_cpu(*s2));
102 		if (diff2)
103 			return diff2;
104 	}
105 
106 	diff2 = l1 - l2;
107 	return diff2 ? diff2 : diff1;
108 }
109