1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #include <linux/module.h> 3 #include <linux/kernel.h> 4 #include <linux/string.h> 5 #include <linux/slab.h> 6 #include <linux/parser.h> 7 #include <linux/errno.h> 8 #include <linux/unicode.h> 9 #include <linux/stringhash.h> 10 11 #include "utf8n.h" 12 13 int utf8_validate(const struct unicode_map *um, const struct qstr *str) 14 { 15 const struct utf8data *data = utf8nfdi(um->version); 16 17 if (utf8nlen(data, str->name, str->len) < 0) 18 return -1; 19 return 0; 20 } 21 EXPORT_SYMBOL(utf8_validate); 22 23 int utf8_strncmp(const struct unicode_map *um, 24 const struct qstr *s1, const struct qstr *s2) 25 { 26 const struct utf8data *data = utf8nfdi(um->version); 27 struct utf8cursor cur1, cur2; 28 int c1, c2; 29 30 if (utf8ncursor(&cur1, data, s1->name, s1->len) < 0) 31 return -EINVAL; 32 33 if (utf8ncursor(&cur2, data, s2->name, s2->len) < 0) 34 return -EINVAL; 35 36 do { 37 c1 = utf8byte(&cur1); 38 c2 = utf8byte(&cur2); 39 40 if (c1 < 0 || c2 < 0) 41 return -EINVAL; 42 if (c1 != c2) 43 return 1; 44 } while (c1); 45 46 return 0; 47 } 48 EXPORT_SYMBOL(utf8_strncmp); 49 50 int utf8_strncasecmp(const struct unicode_map *um, 51 const struct qstr *s1, const struct qstr *s2) 52 { 53 const struct utf8data *data = utf8nfdicf(um->version); 54 struct utf8cursor cur1, cur2; 55 int c1, c2; 56 57 if (utf8ncursor(&cur1, data, s1->name, s1->len) < 0) 58 return -EINVAL; 59 60 if (utf8ncursor(&cur2, data, s2->name, s2->len) < 0) 61 return -EINVAL; 62 63 do { 64 c1 = utf8byte(&cur1); 65 c2 = utf8byte(&cur2); 66 67 if (c1 < 0 || c2 < 0) 68 return -EINVAL; 69 if (c1 != c2) 70 return 1; 71 } while (c1); 72 73 return 0; 74 } 75 EXPORT_SYMBOL(utf8_strncasecmp); 76 77 /* String cf is expected to be a valid UTF-8 casefolded 78 * string. 79 */ 80 int utf8_strncasecmp_folded(const struct unicode_map *um, 81 const struct qstr *cf, 82 const struct qstr *s1) 83 { 84 const struct utf8data *data = utf8nfdicf(um->version); 85 struct utf8cursor cur1; 86 int c1, c2; 87 int i = 0; 88 89 if (utf8ncursor(&cur1, data, s1->name, s1->len) < 0) 90 return -EINVAL; 91 92 do { 93 c1 = utf8byte(&cur1); 94 c2 = cf->name[i++]; 95 if (c1 < 0) 96 return -EINVAL; 97 if (c1 != c2) 98 return 1; 99 } while (c1); 100 101 return 0; 102 } 103 EXPORT_SYMBOL(utf8_strncasecmp_folded); 104 105 int utf8_casefold(const struct unicode_map *um, const struct qstr *str, 106 unsigned char *dest, size_t dlen) 107 { 108 const struct utf8data *data = utf8nfdicf(um->version); 109 struct utf8cursor cur; 110 size_t nlen = 0; 111 112 if (utf8ncursor(&cur, data, str->name, str->len) < 0) 113 return -EINVAL; 114 115 for (nlen = 0; nlen < dlen; nlen++) { 116 int c = utf8byte(&cur); 117 118 dest[nlen] = c; 119 if (!c) 120 return nlen; 121 if (c == -1) 122 break; 123 } 124 return -EINVAL; 125 } 126 EXPORT_SYMBOL(utf8_casefold); 127 128 int utf8_casefold_hash(const struct unicode_map *um, const void *salt, 129 struct qstr *str) 130 { 131 const struct utf8data *data = utf8nfdicf(um->version); 132 struct utf8cursor cur; 133 int c; 134 unsigned long hash = init_name_hash(salt); 135 136 if (utf8ncursor(&cur, data, str->name, str->len) < 0) 137 return -EINVAL; 138 139 while ((c = utf8byte(&cur))) { 140 if (c < 0) 141 return -EINVAL; 142 hash = partial_name_hash((unsigned char)c, hash); 143 } 144 str->hash = end_name_hash(hash); 145 return 0; 146 } 147 EXPORT_SYMBOL(utf8_casefold_hash); 148 149 int utf8_normalize(const struct unicode_map *um, const struct qstr *str, 150 unsigned char *dest, size_t dlen) 151 { 152 const struct utf8data *data = utf8nfdi(um->version); 153 struct utf8cursor cur; 154 ssize_t nlen = 0; 155 156 if (utf8ncursor(&cur, data, str->name, str->len) < 0) 157 return -EINVAL; 158 159 for (nlen = 0; nlen < dlen; nlen++) { 160 int c = utf8byte(&cur); 161 162 dest[nlen] = c; 163 if (!c) 164 return nlen; 165 if (c == -1) 166 break; 167 } 168 return -EINVAL; 169 } 170 171 EXPORT_SYMBOL(utf8_normalize); 172 173 static int utf8_parse_version(const char *version, unsigned int *maj, 174 unsigned int *min, unsigned int *rev) 175 { 176 substring_t args[3]; 177 char version_string[12]; 178 static const struct match_token token[] = { 179 {1, "%d.%d.%d"}, 180 {0, NULL} 181 }; 182 183 strncpy(version_string, version, sizeof(version_string)); 184 185 if (match_token(version_string, token, args) != 1) 186 return -EINVAL; 187 188 if (match_int(&args[0], maj) || match_int(&args[1], min) || 189 match_int(&args[2], rev)) 190 return -EINVAL; 191 192 return 0; 193 } 194 195 struct unicode_map *utf8_load(const char *version) 196 { 197 struct unicode_map *um = NULL; 198 int unicode_version; 199 200 if (version) { 201 unsigned int maj, min, rev; 202 203 if (utf8_parse_version(version, &maj, &min, &rev) < 0) 204 return ERR_PTR(-EINVAL); 205 206 if (!utf8version_is_supported(maj, min, rev)) 207 return ERR_PTR(-EINVAL); 208 209 unicode_version = UNICODE_AGE(maj, min, rev); 210 } else { 211 unicode_version = utf8version_latest(); 212 printk(KERN_WARNING"UTF-8 version not specified. " 213 "Assuming latest supported version (%d.%d.%d).", 214 (unicode_version >> 16) & 0xff, 215 (unicode_version >> 8) & 0xff, 216 (unicode_version & 0xff)); 217 } 218 219 um = kzalloc(sizeof(struct unicode_map), GFP_KERNEL); 220 if (!um) 221 return ERR_PTR(-ENOMEM); 222 223 um->charset = "UTF-8"; 224 um->version = unicode_version; 225 226 return um; 227 } 228 EXPORT_SYMBOL(utf8_load); 229 230 void utf8_unload(struct unicode_map *um) 231 { 232 kfree(um); 233 } 234 EXPORT_SYMBOL(utf8_unload); 235 236 MODULE_LICENSE("GPL v2"); 237