unistr.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project.
  4. *
  5. * Copyright (c) 2001-2006 Anton Altaparmakov
  6. */
  7. #include <linux/slab.h>
  8. #include "types.h"
  9. #include "debug.h"
  10. #include "ntfs.h"
  11. /*
  12. * IMPORTANT
  13. * =========
  14. *
  15. * All these routines assume that the Unicode characters are in little endian
  16. * encoding inside the strings!!!
  17. */
  18. /*
  19. * This is used by the name collation functions to quickly determine what
  20. * characters are (in)valid.
  21. */
  22. static const u8 legal_ansi_char_array[0x40] = {
  23. 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
  24. 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
  25. 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
  26. 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
  27. 0x17, 0x07, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17,
  28. 0x17, 0x17, 0x18, 0x16, 0x16, 0x17, 0x07, 0x00,
  29. 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
  30. 0x17, 0x17, 0x04, 0x16, 0x18, 0x16, 0x18, 0x18,
  31. };
  32. /**
  33. * ntfs_are_names_equal - compare two Unicode names for equality
  34. * @s1: name to compare to @s2
  35. * @s1_len: length in Unicode characters of @s1
  36. * @s2: name to compare to @s1
  37. * @s2_len: length in Unicode characters of @s2
  38. * @ic: ignore case bool
  39. * @upcase: upcase table (only if @ic == IGNORE_CASE)
  40. * @upcase_size: length in Unicode characters of @upcase (if present)
  41. *
  42. * Compare the names @s1 and @s2 and return 'true' (1) if the names are
  43. * identical, or 'false' (0) if they are not identical. If @ic is IGNORE_CASE,
  44. * the @upcase table is used to performa a case insensitive comparison.
  45. */
  46. bool ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
  47. const ntfschar *s2, size_t s2_len, const IGNORE_CASE_BOOL ic,
  48. const ntfschar *upcase, const u32 upcase_size)
  49. {
  50. if (s1_len != s2_len)
  51. return false;
  52. if (ic == CASE_SENSITIVE)
  53. return !ntfs_ucsncmp(s1, s2, s1_len);
  54. return !ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size);
  55. }
  56. /**
  57. * ntfs_collate_names - collate two Unicode names
  58. * @name1: first Unicode name to compare
  59. * @name2: second Unicode name to compare
  60. * @err_val: if @name1 contains an invalid character return this value
  61. * @ic: either CASE_SENSITIVE or IGNORE_CASE
  62. * @upcase: upcase table (ignored if @ic is CASE_SENSITIVE)
  63. * @upcase_len: upcase table size (ignored if @ic is CASE_SENSITIVE)
  64. *
  65. * ntfs_collate_names collates two Unicode names and returns:
  66. *
  67. * -1 if the first name collates before the second one,
  68. * 0 if the names match,
  69. * 1 if the second name collates before the first one, or
  70. * @err_val if an invalid character is found in @name1 during the comparison.
  71. *
  72. * The following characters are considered invalid: '"', '*', '<', '>' and '?'.
  73. */
  74. int ntfs_collate_names(const ntfschar *name1, const u32 name1_len,
  75. const ntfschar *name2, const u32 name2_len,
  76. const int err_val, const IGNORE_CASE_BOOL ic,
  77. const ntfschar *upcase, const u32 upcase_len)
  78. {
  79. u32 cnt, min_len;
  80. u16 c1, c2;
  81. min_len = name1_len;
  82. if (name1_len > name2_len)
  83. min_len = name2_len;
  84. for (cnt = 0; cnt < min_len; ++cnt) {
  85. c1 = le16_to_cpu(*name1++);
  86. c2 = le16_to_cpu(*name2++);
  87. if (ic) {
  88. if (c1 < upcase_len)
  89. c1 = le16_to_cpu(upcase[c1]);
  90. if (c2 < upcase_len)
  91. c2 = le16_to_cpu(upcase[c2]);
  92. }
  93. if (c1 < 64 && legal_ansi_char_array[c1] & 8)
  94. return err_val;
  95. if (c1 < c2)
  96. return -1;
  97. if (c1 > c2)
  98. return 1;
  99. }
  100. if (name1_len < name2_len)
  101. return -1;
  102. if (name1_len == name2_len)
  103. return 0;
  104. /* name1_len > name2_len */
  105. c1 = le16_to_cpu(*name1);
  106. if (c1 < 64 && legal_ansi_char_array[c1] & 8)
  107. return err_val;
  108. return 1;
  109. }
  110. /**
  111. * ntfs_ucsncmp - compare two little endian Unicode strings
  112. * @s1: first string
  113. * @s2: second string
  114. * @n: maximum unicode characters to compare
  115. *
  116. * Compare the first @n characters of the Unicode strings @s1 and @s2,
  117. * The strings in little endian format and appropriate le16_to_cpu()
  118. * conversion is performed on non-little endian machines.
  119. *
  120. * The function returns an integer less than, equal to, or greater than zero
  121. * if @s1 (or the first @n Unicode characters thereof) is found, respectively,
  122. * to be less than, to match, or be greater than @s2.
  123. */
  124. int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n)
  125. {
  126. u16 c1, c2;
  127. size_t i;
  128. for (i = 0; i < n; ++i) {
  129. c1 = le16_to_cpu(s1[i]);
  130. c2 = le16_to_cpu(s2[i]);
  131. if (c1 < c2)
  132. return -1;
  133. if (c1 > c2)
  134. return 1;
  135. if (!c1)
  136. break;
  137. }
  138. return 0;
  139. }
  140. /**
  141. * ntfs_ucsncasecmp - compare two little endian Unicode strings, ignoring case
  142. * @s1: first string
  143. * @s2: second string
  144. * @n: maximum unicode characters to compare
  145. * @upcase: upcase table
  146. * @upcase_size: upcase table size in Unicode characters
  147. *
  148. * Compare the first @n characters of the Unicode strings @s1 and @s2,
  149. * ignoring case. The strings in little endian format and appropriate
  150. * le16_to_cpu() conversion is performed on non-little endian machines.
  151. *
  152. * Each character is uppercased using the @upcase table before the comparison.
  153. *
  154. * The function returns an integer less than, equal to, or greater than zero
  155. * if @s1 (or the first @n Unicode characters thereof) is found, respectively,
  156. * to be less than, to match, or be greater than @s2.
  157. */
  158. int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
  159. const ntfschar *upcase, const u32 upcase_size)
  160. {
  161. size_t i;
  162. u16 c1, c2;
  163. for (i = 0; i < n; ++i) {
  164. if ((c1 = le16_to_cpu(s1[i])) < upcase_size)
  165. c1 = le16_to_cpu(upcase[c1]);
  166. if ((c2 = le16_to_cpu(s2[i])) < upcase_size)
  167. c2 = le16_to_cpu(upcase[c2]);
  168. if (c1 < c2)
  169. return -1;
  170. if (c1 > c2)
  171. return 1;
  172. if (!c1)
  173. break;
  174. }
  175. return 0;
  176. }
  177. void ntfs_upcase_name(ntfschar *name, u32 name_len, const ntfschar *upcase,
  178. const u32 upcase_len)
  179. {
  180. u32 i;
  181. u16 u;
  182. for (i = 0; i < name_len; i++)
  183. if ((u = le16_to_cpu(name[i])) < upcase_len)
  184. name[i] = upcase[u];
  185. }
  186. void ntfs_file_upcase_value(FILE_NAME_ATTR *file_name_attr,
  187. const ntfschar *upcase, const u32 upcase_len)
  188. {
  189. ntfs_upcase_name((ntfschar*)&file_name_attr->file_name,
  190. file_name_attr->file_name_length, upcase, upcase_len);
  191. }
  192. int ntfs_file_compare_values(FILE_NAME_ATTR *file_name_attr1,
  193. FILE_NAME_ATTR *file_name_attr2,
  194. const int err_val, const IGNORE_CASE_BOOL ic,
  195. const ntfschar *upcase, const u32 upcase_len)
  196. {
  197. return ntfs_collate_names((ntfschar*)&file_name_attr1->file_name,
  198. file_name_attr1->file_name_length,
  199. (ntfschar*)&file_name_attr2->file_name,
  200. file_name_attr2->file_name_length,
  201. err_val, ic, upcase, upcase_len);
  202. }
  203. /**
  204. * ntfs_nlstoucs - convert NLS string to little endian Unicode string
  205. * @vol: ntfs volume which we are working with
  206. * @ins: input NLS string buffer
  207. * @ins_len: length of input string in bytes
  208. * @outs: on return contains the allocated output Unicode string buffer
  209. *
  210. * Convert the input string @ins, which is in whatever format the loaded NLS
  211. * map dictates, into a little endian, 2-byte Unicode string.
  212. *
  213. * This function allocates the string and the caller is responsible for
  214. * calling kmem_cache_free(ntfs_name_cache, *@outs); when finished with it.
  215. *
  216. * On success the function returns the number of Unicode characters written to
  217. * the output string *@outs (>= 0), not counting the terminating Unicode NULL
  218. * character. *@outs is set to the allocated output string buffer.
  219. *
  220. * On error, a negative number corresponding to the error code is returned. In
  221. * that case the output string is not allocated. Both *@outs and *@outs_len
  222. * are then undefined.
  223. *
  224. * This might look a bit odd due to fast path optimization...
  225. */
  226. int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
  227. const int ins_len, ntfschar **outs)
  228. {
  229. struct nls_table *nls = vol->nls_map;
  230. ntfschar *ucs;
  231. wchar_t wc;
  232. int i, o, wc_len;
  233. /* We do not trust outside sources. */
  234. if (likely(ins)) {
  235. ucs = kmem_cache_alloc(ntfs_name_cache, GFP_NOFS);
  236. if (likely(ucs)) {
  237. for (i = o = 0; i < ins_len; i += wc_len) {
  238. wc_len = nls->char2uni(ins + i, ins_len - i,
  239. &wc);
  240. if (likely(wc_len >= 0 &&
  241. o < NTFS_MAX_NAME_LEN)) {
  242. if (likely(wc)) {
  243. ucs[o++] = cpu_to_le16(wc);
  244. continue;
  245. } /* else if (!wc) */
  246. break;
  247. } /* else if (wc_len < 0 ||
  248. o >= NTFS_MAX_NAME_LEN) */
  249. goto name_err;
  250. }
  251. ucs[o] = 0;
  252. *outs = ucs;
  253. return o;
  254. } /* else if (!ucs) */
  255. ntfs_error(vol->sb, "Failed to allocate buffer for converted "
  256. "name from ntfs_name_cache.");
  257. return -ENOMEM;
  258. } /* else if (!ins) */
  259. ntfs_error(vol->sb, "Received NULL pointer.");
  260. return -EINVAL;
  261. name_err:
  262. kmem_cache_free(ntfs_name_cache, ucs);
  263. if (wc_len < 0) {
  264. ntfs_error(vol->sb, "Name using character set %s contains "
  265. "characters that cannot be converted to "
  266. "Unicode.", nls->charset);
  267. i = -EILSEQ;
  268. } else /* if (o >= NTFS_MAX_NAME_LEN) */ {
  269. ntfs_error(vol->sb, "Name is too long (maximum length for a "
  270. "name on NTFS is %d Unicode characters.",
  271. NTFS_MAX_NAME_LEN);
  272. i = -ENAMETOOLONG;
  273. }
  274. return i;
  275. }
  276. /**
  277. * ntfs_ucstonls - convert little endian Unicode string to NLS string
  278. * @vol: ntfs volume which we are working with
  279. * @ins: input Unicode string buffer
  280. * @ins_len: length of input string in Unicode characters
  281. * @outs: on return contains the (allocated) output NLS string buffer
  282. * @outs_len: length of output string buffer in bytes
  283. *
  284. * Convert the input little endian, 2-byte Unicode string @ins, of length
  285. * @ins_len into the string format dictated by the loaded NLS.
  286. *
  287. * If *@outs is NULL, this function allocates the string and the caller is
  288. * responsible for calling kfree(*@outs); when finished with it. In this case
  289. * @outs_len is ignored and can be 0.
  290. *
  291. * On success the function returns the number of bytes written to the output
  292. * string *@outs (>= 0), not counting the terminating NULL byte. If the output
  293. * string buffer was allocated, *@outs is set to it.
  294. *
  295. * On error, a negative number corresponding to the error code is returned. In
  296. * that case the output string is not allocated. The contents of *@outs are
  297. * then undefined.
  298. *
  299. * This might look a bit odd due to fast path optimization...
  300. */
  301. int ntfs_ucstonls(const ntfs_volume *vol, const ntfschar *ins,
  302. const int ins_len, unsigned char **outs, int outs_len)
  303. {
  304. struct nls_table *nls = vol->nls_map;
  305. unsigned char *ns;
  306. int i, o, ns_len, wc;
  307. /* We don't trust outside sources. */
  308. if (ins) {
  309. ns = *outs;
  310. ns_len = outs_len;
  311. if (ns && !ns_len) {
  312. wc = -ENAMETOOLONG;
  313. goto conversion_err;
  314. }
  315. if (!ns) {
  316. ns_len = ins_len * NLS_MAX_CHARSET_SIZE;
  317. ns = kmalloc(ns_len + 1, GFP_NOFS);
  318. if (!ns)
  319. goto mem_err_out;
  320. }
  321. for (i = o = 0; i < ins_len; i++) {
  322. retry: wc = nls->uni2char(le16_to_cpu(ins[i]), ns + o,
  323. ns_len - o);
  324. if (wc > 0) {
  325. o += wc;
  326. continue;
  327. } else if (!wc)
  328. break;
  329. else if (wc == -ENAMETOOLONG && ns != *outs) {
  330. unsigned char *tc;
  331. /* Grow in multiples of 64 bytes. */
  332. tc = kmalloc((ns_len + 64) &
  333. ~63, GFP_NOFS);
  334. if (tc) {
  335. memcpy(tc, ns, ns_len);
  336. ns_len = ((ns_len + 64) & ~63) - 1;
  337. kfree(ns);
  338. ns = tc;
  339. goto retry;
  340. } /* No memory so goto conversion_error; */
  341. } /* wc < 0, real error. */
  342. goto conversion_err;
  343. }
  344. ns[o] = 0;
  345. *outs = ns;
  346. return o;
  347. } /* else (!ins) */
  348. ntfs_error(vol->sb, "Received NULL pointer.");
  349. return -EINVAL;
  350. conversion_err:
  351. ntfs_error(vol->sb, "Unicode name contains characters that cannot be "
  352. "converted to character set %s. You might want to "
  353. "try to use the mount option nls=utf8.", nls->charset);
  354. if (ns != *outs)
  355. kfree(ns);
  356. if (wc != -ENAMETOOLONG)
  357. wc = -EILSEQ;
  358. return wc;
  359. mem_err_out:
  360. ntfs_error(vol->sb, "Failed to allocate name!");
  361. return -ENOMEM;
  362. }