14534a70bSKonstantin Komarov // SPDX-License-Identifier: GPL-2.0
24534a70bSKonstantin Komarov /*
34534a70bSKonstantin Komarov *
44534a70bSKonstantin Komarov * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
54534a70bSKonstantin Komarov *
64534a70bSKonstantin Komarov */
7e8b8e97fSKari Argillander
8f9767661SKari Argillander #include <linux/kernel.h>
9f9767661SKari Argillander #include <linux/types.h>
104534a70bSKonstantin Komarov
114534a70bSKonstantin Komarov #include "ntfs_fs.h"
124534a70bSKonstantin Komarov
upcase_unicode_char(const u16 * upcase,u16 chr)134534a70bSKonstantin Komarov static inline u16 upcase_unicode_char(const u16 *upcase, u16 chr)
144534a70bSKonstantin Komarov {
154534a70bSKonstantin Komarov if (chr < 'a')
164534a70bSKonstantin Komarov return chr;
174534a70bSKonstantin Komarov
184534a70bSKonstantin Komarov if (chr <= 'z')
194534a70bSKonstantin Komarov return chr - ('a' - 'A');
204534a70bSKonstantin Komarov
214534a70bSKonstantin Komarov return upcase[chr];
224534a70bSKonstantin Komarov }
234534a70bSKonstantin Komarov
244534a70bSKonstantin Komarov /*
25e8b8e97fSKari Argillander * ntfs_cmp_names
26e8b8e97fSKari Argillander *
274534a70bSKonstantin Komarov * Thanks Kari Argillander <kari.argillander@gmail.com> for idea and implementation 'bothcase'
284534a70bSKonstantin Komarov *
29f8d87ed9SColin Ian King * Straight way to compare names:
30e8b8e97fSKari Argillander * - Case insensitive
31e8b8e97fSKari Argillander * - If name equals and 'bothcases' then
32e8b8e97fSKari Argillander * - Case sensitive
33d3624466SKonstantin Komarov * 'Straight way' code scans input names twice in worst case.
34e8b8e97fSKari Argillander * Optimized code scans input names only once.
354534a70bSKonstantin Komarov */
ntfs_cmp_names(const __le16 * s1,size_t l1,const __le16 * s2,size_t l2,const u16 * upcase,bool bothcase)364534a70bSKonstantin Komarov int ntfs_cmp_names(const __le16 *s1, size_t l1, const __le16 *s2, size_t l2,
374534a70bSKonstantin Komarov const u16 *upcase, bool bothcase)
384534a70bSKonstantin Komarov {
394534a70bSKonstantin Komarov int diff1 = 0;
404534a70bSKonstantin Komarov int diff2;
414534a70bSKonstantin Komarov size_t len = min(l1, l2);
424534a70bSKonstantin Komarov
434534a70bSKonstantin Komarov if (!bothcase && upcase)
444534a70bSKonstantin Komarov goto case_insentive;
454534a70bSKonstantin Komarov
464534a70bSKonstantin Komarov for (; len; s1++, s2++, len--) {
474534a70bSKonstantin Komarov diff1 = le16_to_cpu(*s1) - le16_to_cpu(*s2);
484534a70bSKonstantin Komarov if (diff1) {
494534a70bSKonstantin Komarov if (bothcase && upcase)
504534a70bSKonstantin Komarov goto case_insentive;
514534a70bSKonstantin Komarov
524534a70bSKonstantin Komarov return diff1;
534534a70bSKonstantin Komarov }
544534a70bSKonstantin Komarov }
554534a70bSKonstantin Komarov return l1 - l2;
564534a70bSKonstantin Komarov
574534a70bSKonstantin Komarov case_insentive:
584534a70bSKonstantin Komarov for (; len; s1++, s2++, len--) {
594534a70bSKonstantin Komarov diff2 = upcase_unicode_char(upcase, le16_to_cpu(*s1)) -
604534a70bSKonstantin Komarov upcase_unicode_char(upcase, le16_to_cpu(*s2));
614534a70bSKonstantin Komarov if (diff2)
624534a70bSKonstantin Komarov return diff2;
634534a70bSKonstantin Komarov }
644534a70bSKonstantin Komarov
654534a70bSKonstantin Komarov diff2 = l1 - l2;
664534a70bSKonstantin Komarov return diff2 ? diff2 : diff1;
674534a70bSKonstantin Komarov }
684534a70bSKonstantin Komarov
ntfs_cmp_names_cpu(const struct cpu_str * uni1,const struct le_str * uni2,const u16 * upcase,bool bothcase)694534a70bSKonstantin Komarov int ntfs_cmp_names_cpu(const struct cpu_str *uni1, const struct le_str *uni2,
704534a70bSKonstantin Komarov const u16 *upcase, bool bothcase)
714534a70bSKonstantin Komarov {
724534a70bSKonstantin Komarov const u16 *s1 = uni1->name;
734534a70bSKonstantin Komarov const __le16 *s2 = uni2->name;
744534a70bSKonstantin Komarov size_t l1 = uni1->len;
754534a70bSKonstantin Komarov size_t l2 = uni2->len;
764534a70bSKonstantin Komarov size_t len = min(l1, l2);
774534a70bSKonstantin Komarov int diff1 = 0;
784534a70bSKonstantin Komarov int diff2;
794534a70bSKonstantin Komarov
804534a70bSKonstantin Komarov if (!bothcase && upcase)
814534a70bSKonstantin Komarov goto case_insentive;
824534a70bSKonstantin Komarov
834534a70bSKonstantin Komarov for (; len; s1++, s2++, len--) {
844534a70bSKonstantin Komarov diff1 = *s1 - le16_to_cpu(*s2);
854534a70bSKonstantin Komarov if (diff1) {
864534a70bSKonstantin Komarov if (bothcase && upcase)
874534a70bSKonstantin Komarov goto case_insentive;
884534a70bSKonstantin Komarov
894534a70bSKonstantin Komarov return diff1;
904534a70bSKonstantin Komarov }
914534a70bSKonstantin Komarov }
924534a70bSKonstantin Komarov return l1 - l2;
934534a70bSKonstantin Komarov
944534a70bSKonstantin Komarov case_insentive:
954534a70bSKonstantin Komarov for (; len; s1++, s2++, len--) {
964534a70bSKonstantin Komarov diff2 = upcase_unicode_char(upcase, *s1) -
974534a70bSKonstantin Komarov upcase_unicode_char(upcase, le16_to_cpu(*s2));
984534a70bSKonstantin Komarov if (diff2)
994534a70bSKonstantin Komarov return diff2;
1004534a70bSKonstantin Komarov }
1014534a70bSKonstantin Komarov
1024534a70bSKonstantin Komarov diff2 = l1 - l2;
1034534a70bSKonstantin Komarov return diff2 ? diff2 : diff1;
1044534a70bSKonstantin Komarov }
105*a3a956c7SKonstantin Komarov
106*a3a956c7SKonstantin Komarov /* Helper function for ntfs_d_hash. */
ntfs_names_hash(const u16 * name,size_t len,const u16 * upcase,unsigned long hash)107*a3a956c7SKonstantin Komarov unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase,
108*a3a956c7SKonstantin Komarov unsigned long hash)
109*a3a956c7SKonstantin Komarov {
110*a3a956c7SKonstantin Komarov while (len--) {
111*a3a956c7SKonstantin Komarov unsigned int c = upcase_unicode_char(upcase, *name++);
112*a3a956c7SKonstantin Komarov hash = partial_name_hash(c, hash);
113*a3a956c7SKonstantin Komarov }
114*a3a956c7SKonstantin Komarov
115*a3a956c7SKonstantin Komarov return hash;
116*a3a956c7SKonstantin Komarov }
117