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 } 117