1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 /* 2 /* 3 * 3 * 4 * Copyright (C) 2019-2021 Paragon Software Gm 4 * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved. 5 * 5 * 6 */ 6 */ 7 7 8 #include <linux/kernel.h> 8 #include <linux/kernel.h> 9 #include <linux/types.h> 9 #include <linux/types.h> 10 10 11 #include "ntfs_fs.h" 11 #include "ntfs_fs.h" 12 12 13 static inline u16 upcase_unicode_char(const u1 13 static inline u16 upcase_unicode_char(const u16 *upcase, u16 chr) 14 { 14 { 15 if (chr < 'a') 15 if (chr < 'a') 16 return chr; 16 return chr; 17 17 18 if (chr <= 'z') 18 if (chr <= 'z') 19 return chr - ('a' - 'A'); 19 return chr - ('a' - 'A'); 20 20 21 return upcase[chr]; 21 return upcase[chr]; 22 } 22 } 23 23 24 /* 24 /* 25 * ntfs_cmp_names 25 * ntfs_cmp_names 26 * 26 * 27 * Thanks Kari Argillander <kari.argillander@g 27 * Thanks Kari Argillander <kari.argillander@gmail.com> for idea and implementation 'bothcase' 28 * 28 * 29 * Straight way to compare names: 29 * Straight way to compare names: 30 * - Case insensitive 30 * - Case insensitive 31 * - If name equals and 'bothcases' then 31 * - If name equals and 'bothcases' then 32 * - Case sensitive 32 * - Case sensitive 33 * 'Straight way' code scans input names twice 33 * 'Straight way' code scans input names twice in worst case. 34 * Optimized code scans input names only once. 34 * Optimized code scans input names only once. 35 */ 35 */ 36 int ntfs_cmp_names(const __le16 *s1, size_t l1 36 int ntfs_cmp_names(const __le16 *s1, size_t l1, const __le16 *s2, size_t l2, 37 const u16 *upcase, bool bot 37 const u16 *upcase, bool bothcase) 38 { 38 { 39 int diff1 = 0; 39 int diff1 = 0; 40 int diff2; 40 int diff2; 41 size_t len = min(l1, l2); 41 size_t len = min(l1, l2); 42 42 43 if (!bothcase && upcase) 43 if (!bothcase && upcase) 44 goto case_insentive; 44 goto case_insentive; 45 45 46 for (; len; s1++, s2++, len--) { 46 for (; len; s1++, s2++, len--) { 47 diff1 = le16_to_cpu(*s1) - le1 47 diff1 = le16_to_cpu(*s1) - le16_to_cpu(*s2); 48 if (diff1) { 48 if (diff1) { 49 if (bothcase && upcase 49 if (bothcase && upcase) 50 goto case_inse 50 goto case_insentive; 51 51 52 return diff1; 52 return diff1; 53 } 53 } 54 } 54 } 55 return l1 - l2; 55 return l1 - l2; 56 56 57 case_insentive: 57 case_insentive: 58 for (; len; s1++, s2++, len--) { 58 for (; len; s1++, s2++, len--) { 59 diff2 = upcase_unicode_char(up 59 diff2 = upcase_unicode_char(upcase, le16_to_cpu(*s1)) - 60 upcase_unicode_char(up 60 upcase_unicode_char(upcase, le16_to_cpu(*s2)); 61 if (diff2) 61 if (diff2) 62 return diff2; 62 return diff2; 63 } 63 } 64 64 65 diff2 = l1 - l2; 65 diff2 = l1 - l2; 66 return diff2 ? diff2 : diff1; 66 return diff2 ? diff2 : diff1; 67 } 67 } 68 68 69 int ntfs_cmp_names_cpu(const struct cpu_str *u 69 int ntfs_cmp_names_cpu(const struct cpu_str *uni1, const struct le_str *uni2, 70 const u16 *upcase, bool 70 const u16 *upcase, bool bothcase) 71 { 71 { 72 const u16 *s1 = uni1->name; 72 const u16 *s1 = uni1->name; 73 const __le16 *s2 = uni2->name; 73 const __le16 *s2 = uni2->name; 74 size_t l1 = uni1->len; 74 size_t l1 = uni1->len; 75 size_t l2 = uni2->len; 75 size_t l2 = uni2->len; 76 size_t len = min(l1, l2); 76 size_t len = min(l1, l2); 77 int diff1 = 0; 77 int diff1 = 0; 78 int diff2; 78 int diff2; 79 79 80 if (!bothcase && upcase) 80 if (!bothcase && upcase) 81 goto case_insentive; 81 goto case_insentive; 82 82 83 for (; len; s1++, s2++, len--) { 83 for (; len; s1++, s2++, len--) { 84 diff1 = *s1 - le16_to_cpu(*s2) 84 diff1 = *s1 - le16_to_cpu(*s2); 85 if (diff1) { 85 if (diff1) { 86 if (bothcase && upcase 86 if (bothcase && upcase) 87 goto case_inse 87 goto case_insentive; 88 88 89 return diff1; 89 return diff1; 90 } 90 } 91 } 91 } 92 return l1 - l2; 92 return l1 - l2; 93 93 94 case_insentive: 94 case_insentive: 95 for (; len; s1++, s2++, len--) { 95 for (; len; s1++, s2++, len--) { 96 diff2 = upcase_unicode_char(up 96 diff2 = upcase_unicode_char(upcase, *s1) - 97 upcase_unicode_char(up 97 upcase_unicode_char(upcase, le16_to_cpu(*s2)); 98 if (diff2) 98 if (diff2) 99 return diff2; 99 return diff2; 100 } 100 } 101 101 102 diff2 = l1 - l2; 102 diff2 = l1 - l2; 103 return diff2 ? diff2 : diff1; 103 return diff2 ? diff2 : diff1; 104 } 104 } 105 105 106 /* Helper function for ntfs_d_hash. */ 106 /* Helper function for ntfs_d_hash. */ 107 unsigned long ntfs_names_hash(const u16 *name, 107 unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase, 108 unsigned long ha 108 unsigned long hash) 109 { 109 { 110 while (len--) { 110 while (len--) { 111 unsigned int c = upcase_unicod 111 unsigned int c = upcase_unicode_char(upcase, *name++); 112 hash = partial_name_hash(c, ha 112 hash = partial_name_hash(c, hash); 113 } 113 } 114 114 115 return hash; 115 return hash; 116 } 116 } 117 117
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.