| // SPDX-License-Identifier: GPL-2.0 | |
| /* | |
| * | |
| * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved. | |
| * | |
| */ | |
| #include <linux/kernel.h> | |
| #include <linux/types.h> | |
| #include "ntfs_fs.h" | |
| static inline u16 upcase_unicode_char(const u16 *upcase, u16 chr) | |
| { | |
| if (chr < 'a') | |
| return chr; | |
| if (chr <= 'z') | |
| return chr - ('a' - 'A'); | |
| return upcase[chr]; | |
| } | |
| /* | |
| * ntfs_cmp_names | |
| * | |
| * Thanks Kari Argillander <kari.argillander@gmail.com> for idea and implementation 'bothcase' | |
| * | |
| * Straight way to compare names: | |
| * - Case insensitive | |
| * - If name equals and 'bothcases' then | |
| * - Case sensitive | |
| * 'Straight way' code scans input names twice in worst case. | |
| * Optimized code scans input names only once. | |
| */ | |
| int ntfs_cmp_names(const __le16 *s1, size_t l1, const __le16 *s2, size_t l2, | |
| const u16 *upcase, bool bothcase) | |
| { | |
| int diff1 = 0; | |
| int diff2; | |
| size_t len = min(l1, l2); | |
| if (!bothcase && upcase) | |
| goto case_insentive; | |
| for (; len; s1++, s2++, len--) { | |
| diff1 = le16_to_cpu(*s1) - le16_to_cpu(*s2); | |
| if (diff1) { | |
| if (bothcase && upcase) | |
| goto case_insentive; | |
| return diff1; | |
| } | |
| } | |
| return l1 - l2; | |
| case_insentive: | |
| for (; len; s1++, s2++, len--) { | |
| diff2 = upcase_unicode_char(upcase, le16_to_cpu(*s1)) - | |
| upcase_unicode_char(upcase, le16_to_cpu(*s2)); | |
| if (diff2) | |
| return diff2; | |
| } | |
| diff2 = l1 - l2; | |
| return diff2 ? diff2 : diff1; | |
| } | |
| int ntfs_cmp_names_cpu(const struct cpu_str *uni1, const struct le_str *uni2, | |
| const u16 *upcase, bool bothcase) | |
| { | |
| const u16 *s1 = uni1->name; | |
| const __le16 *s2 = uni2->name; | |
| size_t l1 = uni1->len; | |
| size_t l2 = uni2->len; | |
| size_t len = min(l1, l2); | |
| int diff1 = 0; | |
| int diff2; | |
| if (!bothcase && upcase) | |
| goto case_insentive; | |
| for (; len; s1++, s2++, len--) { | |
| diff1 = *s1 - le16_to_cpu(*s2); | |
| if (diff1) { | |
| if (bothcase && upcase) | |
| goto case_insentive; | |
| return diff1; | |
| } | |
| } | |
| return l1 - l2; | |
| case_insentive: | |
| for (; len; s1++, s2++, len--) { | |
| diff2 = upcase_unicode_char(upcase, *s1) - | |
| upcase_unicode_char(upcase, le16_to_cpu(*s2)); | |
| if (diff2) | |
| return diff2; | |
| } | |
| diff2 = l1 - l2; | |
| return diff2 ? diff2 : diff1; | |
| } | |
| /* Helper function for ntfs_d_hash. */ | |
| unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase, | |
| unsigned long hash) | |
| { | |
| while (len--) { | |
| unsigned int c = upcase_unicode_char(upcase, *name++); | |
| hash = partial_name_hash(c, hash); | |
| } | |
| return hash; | |
| } |