1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
6 #include <linux/string.h>
10 static u16 bad_dos_chars[] = {
12 0x002B, 0x002C, 0x003B, 0x003D, 0x005B, 0x005D,
13 0xFF0B, 0xFF0C, 0xFF1B, 0xFF1D, 0xFF3B, 0xFF3D,
17 static u16 bad_uni_chars[] = {
18 /* " * / : < > ? \ | */
19 0x0022, 0x002A, 0x002F, 0x003A,
20 0x003C, 0x003E, 0x003F, 0x005C, 0x007C,
24 static int convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch,
36 len = nls->char2uni(ch, NLS_MAX_CHARSET_SIZE, uni);
38 /* conversion failed */
39 pr_info("%s: fail to use nls\n", __func__);
43 if (!strcmp(nls->charset, "utf8"))
52 static int convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni,
64 len = nls->uni2char(uni, ch, NLS_MAX_CHARSET_SIZE);
66 /* conversion failed */
67 pr_info("%s: fail to use nls\n", __func__);
77 u16 nls_upper(struct super_block *sb, u16 a)
79 struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
81 if (EXFAT_SB(sb)->options.casesensitive)
83 if (p_fs->vol_utbl && p_fs->vol_utbl[get_col_index(a)])
84 return p_fs->vol_utbl[get_col_index(a)][get_row_index(a)];
89 static u16 *nls_wstrchr(u16 *str, u16 wchar)
92 if (*(str++) == wchar)
99 int nls_dosname_cmp(struct super_block *sb, u8 *a, u8 *b)
101 return strncmp(a, b, DOS_NAME_LENGTH);
104 int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b)
108 for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) {
109 if (nls_upper(sb, *a) != nls_upper(sb, *b))
117 void nls_uniname_to_dosname(struct super_block *sb,
118 struct dos_name_t *p_dosname,
119 struct uni_name_t *p_uniname, bool *p_lossy)
123 u8 buf[MAX_CHARSET_SIZE];
124 u8 lower = 0, upper = 0;
125 u8 *dosname = p_dosname->name;
126 u16 *uniname = p_uniname->name;
127 u16 *p, *last_period;
128 struct nls_table *nls = EXFAT_SB(sb)->nls_disk;
130 for (i = 0; i < DOS_NAME_LENGTH; i++)
131 *(dosname + i) = ' ';
133 if (!nls_uniname_cmp(sb, uniname, (u16 *)UNI_CUR_DIR_NAME)) {
135 p_dosname->name_case = 0x0;
141 if (!nls_uniname_cmp(sb, uniname, (u16 *)UNI_PAR_DIR_NAME)) {
143 *(dosname + 1) = '.';
144 p_dosname->name_case = 0x0;
150 /* search for the last embedded period */
152 for (p = uniname; *p; p++) {
158 while (i < DOS_NAME_LENGTH) {
163 if (uniname <= last_period) {
164 if (uniname < last_period)
166 uniname = last_period + 1;
170 if (*uniname == (u16)'\0') {
172 } else if (*uniname == (u16)' ') {
174 } else if (*uniname == (u16)'.') {
175 if (uniname < last_period)
179 } else if (nls_wstrchr(bad_dos_chars, *uniname)) {
181 *(dosname + i) = '_';
184 len = convert_uni_to_ch(nls, buf, *uniname, &lossy);
187 if ((i >= 8) && ((i + len) > DOS_NAME_LENGTH))
190 if ((i < 8) && ((i + len) > 8)) {
197 for (j = 0; j < len; j++, i++)
198 *(dosname + i) = *(buf + j);
199 } else { /* len == 1 */
200 if ((*buf >= 'a') && (*buf <= 'z')) {
201 *(dosname + i) = *buf - ('a' - 'A');
207 } else if ((*buf >= 'A') && (*buf <= 'Z')) {
208 *(dosname + i) = *buf;
215 *(dosname + i) = *buf;
224 if (*dosname == 0xE5)
231 p_dosname->name_case = 0xFF;
233 p_dosname->name_case = lower;
239 void nls_dosname_to_uniname(struct super_block *sb,
240 struct uni_name_t *p_uniname,
241 struct dos_name_t *p_dosname)
244 u8 buf[DOS_NAME_LENGTH + 2];
245 u8 *dosname = p_dosname->name;
246 u16 *uniname = p_uniname->name;
247 struct nls_table *nls = EXFAT_SB(sb)->nls_disk;
249 if (*dosname == 0x05) {
255 for (; i < 8; i++, n++) {
256 if (*(dosname + i) == ' ')
259 if ((*(dosname + i) >= 'A') && (*(dosname + i) <= 'Z') &&
260 (p_dosname->name_case & 0x08))
261 *(buf + n) = *(dosname + i) + ('a' - 'A');
263 *(buf + n) = *(dosname + i);
265 if (*(dosname + 8) != ' ') {
270 for (i = 8; i < DOS_NAME_LENGTH; i++, n++) {
271 if (*(dosname + i) == ' ')
274 if ((*(dosname + i) >= 'A') && (*(dosname + i) <= 'Z') &&
275 (p_dosname->name_case & 0x10))
276 *(buf + n) = *(dosname + i) + ('a' - 'A');
278 *(buf + n) = *(dosname + i);
284 while (j < (MAX_NAME_LENGTH - 1)) {
285 if (*(buf + i) == '\0')
288 i += convert_ch_to_uni(nls, uniname, (buf + i), NULL);
294 *uniname = (u16)'\0';
297 void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring,
298 struct uni_name_t *p_uniname)
301 u8 buf[MAX_CHARSET_SIZE];
302 u16 *uniname = p_uniname->name;
303 struct nls_table *nls = EXFAT_SB(sb)->nls_io;
306 len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH,
307 UTF16_HOST_ENDIAN, p_cstring,
314 while (i < (MAX_NAME_LENGTH - 1)) {
315 if (*uniname == (u16)'\0')
318 len = convert_uni_to_ch(nls, buf, *uniname, NULL);
321 for (j = 0; j < len; j++)
322 *p_cstring++ = (char)*(buf + j);
323 } else { /* len == 1 */
324 *p_cstring++ = (char)*buf;
334 void nls_cstring_to_uniname(struct super_block *sb,
335 struct uni_name_t *p_uniname, u8 *p_cstring,
341 u8 upname[MAX_NAME_LENGTH * 2];
342 u16 *uniname = p_uniname->name;
343 struct nls_table *nls = EXFAT_SB(sb)->nls_io;
345 /* strip all trailing spaces */
346 end_of_name = p_cstring + strlen(p_cstring);
348 while (*(--end_of_name) == ' ') {
349 if (end_of_name < p_cstring)
352 *(++end_of_name) = '\0';
354 if (strcmp(p_cstring, ".") && strcmp(p_cstring, "..")) {
355 /* strip all trailing periods */
356 while (*(--end_of_name) == '.') {
357 if (end_of_name < p_cstring)
360 *(++end_of_name) = '\0';
363 if (*p_cstring == '\0')
367 i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH,
368 UTF16_HOST_ENDIAN, uniname,
370 for (j = 0; j < i; j++)
371 SET16_A(upname + j * 2, nls_upper(sb, uniname[j]));
376 while (j < (MAX_NAME_LENGTH - 1)) {
377 if (*(p_cstring + i) == '\0')
380 i += convert_ch_to_uni(nls, uniname,
381 (u8 *)(p_cstring + i), &lossy);
383 if ((*uniname < 0x0020) ||
384 nls_wstrchr(bad_uni_chars, *uniname))
387 SET16_A(upname + j * 2, nls_upper(sb, *uniname));
393 if (*(p_cstring + i) != '\0')
395 *uniname = (u16)'\0';
398 p_uniname->name_len = j;
399 p_uniname->name_hash = calc_checksum_2byte(upname, j << 1, 0,