PageRenderTime 55ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/fs/exfat/exfat_nls.c

https://gitlab.com/LiquidSmooth-Devices/android_kernel_shooter
C | 446 lines | 309 code | 82 blank | 55 comment | 123 complexity | d34d44d2524bdefb6f4d88b5b4134bbf MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. */
  18. /************************************************************************/
  19. /* */
  20. /* PROJECT : exFAT & FAT12/16/32 File System */
  21. /* FILE : exfat_nls.c */
  22. /* PURPOSE : exFAT NLS Manager */
  23. /* */
  24. /*----------------------------------------------------------------------*/
  25. /* NOTES */
  26. /* */
  27. /*----------------------------------------------------------------------*/
  28. /* REVISION HISTORY (Ver 0.9) */
  29. /* */
  30. /* - 2010.11.15 [Joosun Hahn] : first writing */
  31. /* */
  32. /************************************************************************/
  33. #include "exfat_config.h"
  34. #include "exfat_data.h"
  35. #include "exfat_nls.h"
  36. #include "exfat_api.h"
  37. #include "exfat_super.h"
  38. #include "exfat_core.h"
  39. #include <linux/nls.h>
  40. /*----------------------------------------------------------------------*/
  41. /* Global Variable Definitions */
  42. /*----------------------------------------------------------------------*/
  43. /*----------------------------------------------------------------------*/
  44. /* Local Variable Definitions */
  45. /*----------------------------------------------------------------------*/
  46. static u16 bad_dos_chars[] = {
  47. /* + , ; = [ ] */
  48. 0x002B, 0x002C, 0x003B, 0x003D, 0x005B, 0x005D,
  49. 0xFF0B, 0xFF0C, 0xFF1B, 0xFF1D, 0xFF3B, 0xFF3D,
  50. 0
  51. };
  52. static u16 bad_uni_chars[] = {
  53. /* " * / : < > ? \ | */
  54. 0x0022, 0x002A, 0x002F, 0x003A,
  55. 0x003C, 0x003E, 0x003F, 0x005C, 0x007C,
  56. 0
  57. };
  58. /*----------------------------------------------------------------------*/
  59. /* Local Function Declarations */
  60. /*----------------------------------------------------------------------*/
  61. static s32 convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni, s32 *lossy);
  62. static s32 convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch, s32 *lossy);
  63. /*======================================================================*/
  64. /* Global Function Definitions */
  65. /*======================================================================*/
  66. u16 nls_upper(struct super_block *sb, u16 a)
  67. {
  68. FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
  69. if (EXFAT_SB(sb)->options.casesensitive)
  70. return a;
  71. if (p_fs->vol_utbl != NULL && (p_fs->vol_utbl)[get_col_index(a)] != NULL)
  72. return (p_fs->vol_utbl)[get_col_index(a)][get_row_index(a)];
  73. else
  74. return a;
  75. }
  76. u16 *nls_wstrchr(u16 *str, u16 wchar)
  77. {
  78. while (*str) {
  79. if (*(str++) == wchar)
  80. return str;
  81. }
  82. return 0;
  83. }
  84. s32 nls_dosname_cmp(struct super_block *sb, u8 *a, u8 *b)
  85. {
  86. return strncmp((void *) a, (void *) b, DOS_NAME_LENGTH);
  87. } /* end of nls_dosname_cmp */
  88. s32 nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b)
  89. {
  90. int i;
  91. for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) {
  92. if (nls_upper(sb, *a) != nls_upper(sb, *b))
  93. return 1;
  94. if (*a == 0x0)
  95. return 0;
  96. }
  97. return 0;
  98. } /* end of nls_uniname_cmp */
  99. void nls_uniname_to_dosname(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname, s32 *p_lossy)
  100. {
  101. int i, j, len, lossy = FALSE;
  102. u8 buf[MAX_CHARSET_SIZE];
  103. u8 lower = 0, upper = 0;
  104. u8 *dosname = p_dosname->name;
  105. u16 *uniname = p_uniname->name;
  106. u16 *p, *last_period;
  107. struct nls_table *nls = EXFAT_SB(sb)->nls_disk;
  108. for (i = 0; i < DOS_NAME_LENGTH; i++)
  109. *(dosname+i) = ' ';
  110. if (!nls_uniname_cmp(sb, uniname, (u16 *) UNI_CUR_DIR_NAME)) {
  111. *(dosname) = '.';
  112. p_dosname->name_case = 0x0;
  113. if (p_lossy != NULL)
  114. *p_lossy = FALSE;
  115. return;
  116. }
  117. if (!nls_uniname_cmp(sb, uniname, (u16 *) UNI_PAR_DIR_NAME)) {
  118. *(dosname) = '.';
  119. *(dosname+1) = '.';
  120. p_dosname->name_case = 0x0;
  121. if (p_lossy != NULL)
  122. *p_lossy = FALSE;
  123. return;
  124. }
  125. /* search for the last embedded period */
  126. last_period = NULL;
  127. for (p = uniname; *p; p++) {
  128. if (*p == (u16) '.')
  129. last_period = p;
  130. }
  131. i = 0;
  132. while (i < DOS_NAME_LENGTH) {
  133. if (i == 8) {
  134. if (last_period == NULL)
  135. break;
  136. if (uniname <= last_period) {
  137. if (uniname < last_period)
  138. lossy = TRUE;
  139. uniname = last_period + 1;
  140. }
  141. }
  142. if (*uniname == (u16) '\0') {
  143. break;
  144. } else if (*uniname == (u16) ' ') {
  145. lossy = TRUE;
  146. } else if (*uniname == (u16) '.') {
  147. if (uniname < last_period)
  148. lossy = TRUE;
  149. else
  150. i = 8;
  151. } else if (nls_wstrchr(bad_dos_chars, *uniname)) {
  152. lossy = TRUE;
  153. *(dosname+i) = '_';
  154. i++;
  155. } else {
  156. len = convert_uni_to_ch(nls, buf, *uniname, &lossy);
  157. if (len > 1) {
  158. if ((i >= 8) && ((i+len) > DOS_NAME_LENGTH))
  159. break;
  160. if ((i < 8) && ((i+len) > 8)) {
  161. i = 8;
  162. continue;
  163. }
  164. lower = 0xFF;
  165. for (j = 0; j < len; j++, i++)
  166. *(dosname+i) = *(buf+j);
  167. } else { /* len == 1 */
  168. if ((*buf >= 'a') && (*buf <= 'z')) {
  169. *(dosname+i) = *buf - ('a' - 'A');
  170. if (i < 8)
  171. lower |= 0x08;
  172. else
  173. lower |= 0x10;
  174. } else if ((*buf >= 'A') && (*buf <= 'Z')) {
  175. *(dosname+i) = *buf;
  176. if (i < 8)
  177. upper |= 0x08;
  178. else
  179. upper |= 0x10;
  180. } else {
  181. *(dosname+i) = *buf;
  182. }
  183. i++;
  184. }
  185. }
  186. uniname++;
  187. }
  188. if (*dosname == 0xE5)
  189. *dosname = 0x05;
  190. if (*uniname != 0x0)
  191. lossy = TRUE;
  192. if (upper & lower)
  193. p_dosname->name_case = 0xFF;
  194. else
  195. p_dosname->name_case = lower;
  196. if (p_lossy != NULL)
  197. *p_lossy = lossy;
  198. } /* end of nls_uniname_to_dosname */
  199. void nls_dosname_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname)
  200. {
  201. int i = 0, j, n = 0;
  202. u8 buf[DOS_NAME_LENGTH+2];
  203. u8 *dosname = p_dosname->name;
  204. u16 *uniname = p_uniname->name;
  205. struct nls_table *nls = EXFAT_SB(sb)->nls_disk;
  206. if (*dosname == 0x05) {
  207. *buf = 0xE5;
  208. i++;
  209. n++;
  210. }
  211. for (; i < 8; i++, n++) {
  212. if (*(dosname+i) == ' ')
  213. break;
  214. if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') && (p_dosname->name_case & 0x08))
  215. *(buf+n) = *(dosname+i) + ('a' - 'A');
  216. else
  217. *(buf+n) = *(dosname+i);
  218. }
  219. if (*(dosname+8) != ' ') {
  220. *(buf+n) = '.';
  221. n++;
  222. }
  223. for (i = 8; i < DOS_NAME_LENGTH; i++, n++) {
  224. if (*(dosname+i) == ' ')
  225. break;
  226. if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') && (p_dosname->name_case & 0x10))
  227. *(buf+n) = *(dosname+i) + ('a' - 'A');
  228. else
  229. *(buf+n) = *(dosname+i);
  230. }
  231. *(buf+n) = '\0';
  232. i = j = 0;
  233. while (j < (MAX_NAME_LENGTH-1)) {
  234. if (*(buf+i) == '\0')
  235. break;
  236. i += convert_ch_to_uni(nls, uniname, (buf+i), NULL);
  237. uniname++;
  238. j++;
  239. }
  240. *uniname = (u16) '\0';
  241. } /* end of nls_dosname_to_uniname */
  242. void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, UNI_NAME_T *p_uniname)
  243. {
  244. int i, j, len;
  245. u8 buf[MAX_CHARSET_SIZE];
  246. u16 *uniname = p_uniname->name;
  247. struct nls_table *nls = EXFAT_SB(sb)->nls_io;
  248. if (nls == NULL) {
  249. len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH, UTF16_HOST_ENDIAN, p_cstring, MAX_NAME_LENGTH);
  250. p_cstring[len] = 0;
  251. return;
  252. }
  253. i = 0;
  254. while (i < (MAX_NAME_LENGTH-1)) {
  255. if (*uniname == (u16) '\0')
  256. break;
  257. len = convert_uni_to_ch(nls, buf, *uniname, NULL);
  258. if (len > 1) {
  259. for (j = 0; j < len; j++)
  260. *p_cstring++ = (char) *(buf+j);
  261. } else { /* len == 1 */
  262. *p_cstring++ = (char) *buf;
  263. }
  264. uniname++;
  265. i++;
  266. }
  267. *p_cstring = '\0';
  268. } /* end of nls_uniname_to_cstring */
  269. void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, u8 *p_cstring, s32 *p_lossy)
  270. {
  271. int i, j, lossy = FALSE;
  272. u8 *end_of_name;
  273. u8 upname[MAX_NAME_LENGTH * 2];
  274. u16 *uniname = p_uniname->name;
  275. struct nls_table *nls = EXFAT_SB(sb)->nls_io;
  276. /* strip all trailing spaces */
  277. end_of_name = p_cstring + strlen((char *) p_cstring);
  278. while (*(--end_of_name) == ' ') {
  279. if (end_of_name < p_cstring)
  280. break;
  281. }
  282. *(++end_of_name) = '\0';
  283. if (strcmp((char *) p_cstring, ".") && strcmp((char *) p_cstring, "..")) {
  284. /* strip all trailing periods */
  285. while (*(--end_of_name) == '.') {
  286. if (end_of_name < p_cstring)
  287. break;
  288. }
  289. *(++end_of_name) = '\0';
  290. }
  291. if (*p_cstring == '\0')
  292. lossy = TRUE;
  293. if (nls == NULL) {
  294. i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH, UTF16_HOST_ENDIAN, uniname, MAX_NAME_LENGTH);
  295. for (j = 0; j < i; j++)
  296. SET16_A(upname + j * 2, nls_upper(sb, uniname[j]));
  297. uniname[i] = '\0';
  298. }
  299. else {
  300. i = j = 0;
  301. while (j < (MAX_NAME_LENGTH-1)) {
  302. if (*(p_cstring+i) == '\0')
  303. break;
  304. i += convert_ch_to_uni(nls, uniname, (u8 *)(p_cstring+i), &lossy);
  305. if ((*uniname < 0x0020) || nls_wstrchr(bad_uni_chars, *uniname))
  306. lossy = TRUE;
  307. SET16_A(upname + j * 2, nls_upper(sb, *uniname));
  308. uniname++;
  309. j++;
  310. }
  311. if (*(p_cstring+i) != '\0')
  312. lossy = TRUE;
  313. *uniname = (u16) '\0';
  314. }
  315. p_uniname->name_len = j;
  316. p_uniname->name_hash = calc_checksum_2byte((void *) upname, j<<1, 0, CS_DEFAULT);
  317. if (p_lossy != NULL)
  318. *p_lossy = lossy;
  319. } /* end of nls_cstring_to_uniname */
  320. /*======================================================================*/
  321. /* Local Function Definitions */
  322. /*======================================================================*/
  323. static s32 convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch, s32 *lossy)
  324. {
  325. int len;
  326. *uni = 0x0;
  327. if (ch[0] < 0x80) {
  328. *uni = (u16) ch[0];
  329. return 1;
  330. }
  331. len = nls->char2uni(ch, NLS_MAX_CHARSET_SIZE, uni);
  332. if (len < 0) {
  333. /* conversion failed */
  334. printk("%s: fail to use nls\n", __func__);
  335. if (lossy != NULL)
  336. *lossy = TRUE;
  337. *uni = (u16) '_';
  338. if (!strcmp(nls->charset, "utf8"))
  339. return 1;
  340. else
  341. return 2;
  342. }
  343. return len;
  344. } /* end of convert_ch_to_uni */
  345. static s32 convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni, s32 *lossy)
  346. {
  347. int len;
  348. ch[0] = 0x0;
  349. if (uni < 0x0080) {
  350. ch[0] = (u8) uni;
  351. return 1;
  352. }
  353. len = nls->uni2char(uni, ch, NLS_MAX_CHARSET_SIZE);
  354. if (len < 0) {
  355. /* conversion failed */
  356. printk("%s: fail to use nls\n", __func__);
  357. if (lossy != NULL)
  358. *lossy = TRUE;
  359. ch[0] = '_';
  360. return 1;
  361. }
  362. return len;
  363. } /* end of convert_uni_to_ch */
  364. /* end of exfat_nls.c */