utf8-core.c 4.4 KB

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