217 lines · c
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/stringhash.h>9 10#include "utf8n.h"11 12int utf8_validate(const struct unicode_map *um, const struct qstr *str)13{14 if (utf8nlen(um, UTF8_NFDI, str->name, str->len) < 0)15 return -1;16 return 0;17}18EXPORT_SYMBOL(utf8_validate);19 20int utf8_strncmp(const struct unicode_map *um,21 const struct qstr *s1, const struct qstr *s2)22{23 struct utf8cursor cur1, cur2;24 int c1, c2;25 26 if (utf8ncursor(&cur1, um, UTF8_NFDI, s1->name, s1->len) < 0)27 return -EINVAL;28 29 if (utf8ncursor(&cur2, um, UTF8_NFDI, s2->name, s2->len) < 0)30 return -EINVAL;31 32 do {33 c1 = utf8byte(&cur1);34 c2 = utf8byte(&cur2);35 36 if (c1 < 0 || c2 < 0)37 return -EINVAL;38 if (c1 != c2)39 return 1;40 } while (c1);41 42 return 0;43}44EXPORT_SYMBOL(utf8_strncmp);45 46int utf8_strncasecmp(const struct unicode_map *um,47 const struct qstr *s1, const struct qstr *s2)48{49 struct utf8cursor cur1, cur2;50 int c1, c2;51 52 if (utf8ncursor(&cur1, um, UTF8_NFDICF, s1->name, s1->len) < 0)53 return -EINVAL;54 55 if (utf8ncursor(&cur2, um, UTF8_NFDICF, s2->name, s2->len) < 0)56 return -EINVAL;57 58 do {59 c1 = utf8byte(&cur1);60 c2 = utf8byte(&cur2);61 62 if (c1 < 0 || c2 < 0)63 return -EINVAL;64 if (c1 != c2)65 return 1;66 } while (c1);67 68 return 0;69}70EXPORT_SYMBOL(utf8_strncasecmp);71 72/* String cf is expected to be a valid UTF-8 casefolded73 * string.74 */75int utf8_strncasecmp_folded(const struct unicode_map *um,76 const struct qstr *cf,77 const struct qstr *s1)78{79 struct utf8cursor cur1;80 int c1, c2;81 int i = 0;82 83 if (utf8ncursor(&cur1, um, UTF8_NFDICF, s1->name, s1->len) < 0)84 return -EINVAL;85 86 do {87 c1 = utf8byte(&cur1);88 c2 = cf->name[i++];89 if (c1 < 0)90 return -EINVAL;91 if (c1 != c2)92 return 1;93 } while (c1);94 95 return 0;96}97EXPORT_SYMBOL(utf8_strncasecmp_folded);98 99int utf8_casefold(const struct unicode_map *um, const struct qstr *str,100 unsigned char *dest, size_t dlen)101{102 struct utf8cursor cur;103 size_t nlen = 0;104 105 if (utf8ncursor(&cur, um, UTF8_NFDICF, str->name, str->len) < 0)106 return -EINVAL;107 108 for (nlen = 0; nlen < dlen; nlen++) {109 int c = utf8byte(&cur);110 111 dest[nlen] = c;112 if (!c)113 return nlen;114 if (c == -1)115 break;116 }117 return -EINVAL;118}119EXPORT_SYMBOL(utf8_casefold);120 121int utf8_casefold_hash(const struct unicode_map *um, const void *salt,122 struct qstr *str)123{124 struct utf8cursor cur;125 int c;126 unsigned long hash = init_name_hash(salt);127 128 if (utf8ncursor(&cur, um, UTF8_NFDICF, str->name, str->len) < 0)129 return -EINVAL;130 131 while ((c = utf8byte(&cur))) {132 if (c < 0)133 return -EINVAL;134 hash = partial_name_hash((unsigned char)c, hash);135 }136 str->hash = end_name_hash(hash);137 return 0;138}139EXPORT_SYMBOL(utf8_casefold_hash);140 141int utf8_normalize(const struct unicode_map *um, const struct qstr *str,142 unsigned char *dest, size_t dlen)143{144 struct utf8cursor cur;145 ssize_t nlen = 0;146 147 if (utf8ncursor(&cur, um, UTF8_NFDI, str->name, str->len) < 0)148 return -EINVAL;149 150 for (nlen = 0; nlen < dlen; nlen++) {151 int c = utf8byte(&cur);152 153 dest[nlen] = c;154 if (!c)155 return nlen;156 if (c == -1)157 break;158 }159 return -EINVAL;160}161EXPORT_SYMBOL(utf8_normalize);162 163static const struct utf8data *find_table_version(const struct utf8data *table,164 size_t nr_entries, unsigned int version)165{166 size_t i = nr_entries - 1;167 168 while (version < table[i].maxage)169 i--;170 if (version > table[i].maxage)171 return NULL;172 return &table[i];173}174 175struct unicode_map *utf8_load(unsigned int version)176{177 struct unicode_map *um;178 179 um = kzalloc(sizeof(struct unicode_map), GFP_KERNEL);180 if (!um)181 return ERR_PTR(-ENOMEM);182 um->version = version;183 184 um->tables = symbol_request(utf8_data_table);185 if (!um->tables)186 goto out_free_um;187 188 if (!utf8version_is_supported(um, version))189 goto out_symbol_put;190 um->ntab[UTF8_NFDI] = find_table_version(um->tables->utf8nfdidata,191 um->tables->utf8nfdidata_size, um->version);192 if (!um->ntab[UTF8_NFDI])193 goto out_symbol_put;194 um->ntab[UTF8_NFDICF] = find_table_version(um->tables->utf8nfdicfdata,195 um->tables->utf8nfdicfdata_size, um->version);196 if (!um->ntab[UTF8_NFDICF])197 goto out_symbol_put;198 return um;199 200out_symbol_put:201 symbol_put(um->tables);202out_free_um:203 kfree(um);204 return ERR_PTR(-EINVAL);205}206EXPORT_SYMBOL(utf8_load);207 208void utf8_unload(struct unicode_map *um)209{210 if (um) {211 symbol_put(utf8_data_table);212 kfree(um);213 }214}215EXPORT_SYMBOL(utf8_unload);216 217