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