Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
[linux-2.6-microblaze.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/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 }