Merge tag 'char-misc-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[platform/kernel/linux-starfive.git] / fs / ntfs3 / upcase.c
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
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  */
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
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. */
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 }