diff options
author | Keith Mok <ek9852@gmail.com> | 2008-04-28 05:16:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-28 11:58:47 -0400 |
commit | f22032ba8de2960a64a3dd9719fb5c99b1f1ae6e (patch) | |
tree | c515ff4c94c041325cede8061a9fe3301ec08e53 /fs/fat/dir.c | |
parent | 061e97469f46f924cf14bbf1dd4805b46986691a (diff) |
vfat: bug fix for vfat cannot handle filename with 255
This patch fix the problem that the buffer allocated for convert of unicode to
utf8 in fat/dir.c is too small.
And cannot handle filename with 255 asian characters when mounted with utf8
options.
Also it fix the filename length limitation checking in vfat/namei.c that the
filename length should be checked against the number of converted unicode
characters.
Not the length before NLS/UTF8 converted.
Signed-off-by: Keith Mok <ek9852@gmail.com>
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/fat/dir.c')
-rw-r--r-- | fs/fat/dir.c | 44 |
1 files changed, 28 insertions, 16 deletions
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 72cbcd61bd95..7b62ffb663f6 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c | |||
@@ -124,8 +124,8 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos, | |||
124 | * but ignore that right now. | 124 | * but ignore that right now. |
125 | * Ahem... Stack smashing in ring 0 isn't fun. Fixed. | 125 | * Ahem... Stack smashing in ring 0 isn't fun. Fixed. |
126 | */ | 126 | */ |
127 | static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate, | 127 | static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int len, |
128 | struct nls_table *nls) | 128 | int uni_xlate, struct nls_table *nls) |
129 | { | 129 | { |
130 | wchar_t *ip, ec; | 130 | wchar_t *ip, ec; |
131 | unsigned char *op, nc; | 131 | unsigned char *op, nc; |
@@ -135,10 +135,11 @@ static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate, | |||
135 | ip = uni; | 135 | ip = uni; |
136 | op = ascii; | 136 | op = ascii; |
137 | 137 | ||
138 | while (*ip) { | 138 | while (*ip && ((len - NLS_MAX_CHARSET_SIZE) > 0)) { |
139 | ec = *ip++; | 139 | ec = *ip++; |
140 | if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) { | 140 | if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) { |
141 | op += charlen; | 141 | op += charlen; |
142 | len -= charlen; | ||
142 | } else { | 143 | } else { |
143 | if (uni_xlate == 1) { | 144 | if (uni_xlate == 1) { |
144 | *op = ':'; | 145 | *op = ':'; |
@@ -149,16 +150,19 @@ static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate, | |||
149 | ec >>= 4; | 150 | ec >>= 4; |
150 | } | 151 | } |
151 | op += 5; | 152 | op += 5; |
153 | len -= 5; | ||
152 | } else { | 154 | } else { |
153 | *op++ = '?'; | 155 | *op++ = '?'; |
156 | len--; | ||
154 | } | 157 | } |
155 | } | 158 | } |
156 | /* We have some slack there, so it's OK */ | ||
157 | if (op>ascii+256) { | ||
158 | op = ascii + 256; | ||
159 | break; | ||
160 | } | ||
161 | } | 159 | } |
160 | |||
161 | if (unlikely(*ip)) { | ||
162 | printk(KERN_WARNING "FAT: filename was truncated while " | ||
163 | "converting."); | ||
164 | } | ||
165 | |||
162 | *op = 0; | 166 | *op = 0; |
163 | return (op - ascii); | 167 | return (op - ascii); |
164 | } | 168 | } |
@@ -311,9 +315,11 @@ int fat_search_long(struct inode *inode, const unsigned char *name, | |||
311 | struct nls_table *nls_io = sbi->nls_io; | 315 | struct nls_table *nls_io = sbi->nls_io; |
312 | struct nls_table *nls_disk = sbi->nls_disk; | 316 | struct nls_table *nls_disk = sbi->nls_disk; |
313 | wchar_t bufuname[14]; | 317 | wchar_t bufuname[14]; |
314 | unsigned char xlate_len, nr_slots; | 318 | unsigned char nr_slots; |
319 | int xlate_len; | ||
315 | wchar_t *unicode = NULL; | 320 | wchar_t *unicode = NULL; |
316 | unsigned char work[MSDOS_NAME], bufname[260]; /* 256 + 4 */ | 321 | unsigned char work[MSDOS_NAME]; |
322 | unsigned char *bufname = NULL; | ||
317 | int uni_xlate = sbi->options.unicode_xlate; | 323 | int uni_xlate = sbi->options.unicode_xlate; |
318 | int utf8 = sbi->options.utf8; | 324 | int utf8 = sbi->options.utf8; |
319 | int anycase = (sbi->options.name_check != 's'); | 325 | int anycase = (sbi->options.name_check != 's'); |
@@ -321,6 +327,10 @@ int fat_search_long(struct inode *inode, const unsigned char *name, | |||
321 | loff_t cpos = 0; | 327 | loff_t cpos = 0; |
322 | int chl, i, j, last_u, err; | 328 | int chl, i, j, last_u, err; |
323 | 329 | ||
330 | bufname = (unsigned char*)__get_free_page(GFP_KERNEL); | ||
331 | if (!bufname) | ||
332 | return -ENOMEM; | ||
333 | |||
324 | err = -ENOENT; | 334 | err = -ENOENT; |
325 | while(1) { | 335 | while(1) { |
326 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) | 336 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) |
@@ -386,8 +396,8 @@ parse_record: | |||
386 | 396 | ||
387 | bufuname[last_u] = 0x0000; | 397 | bufuname[last_u] = 0x0000; |
388 | xlate_len = utf8 | 398 | xlate_len = utf8 |
389 | ?utf8_wcstombs(bufname, bufuname, sizeof(bufname)) | 399 | ?utf8_wcstombs(bufname, bufuname, PAGE_SIZE) |
390 | :uni16_to_x8(bufname, bufuname, uni_xlate, nls_io); | 400 | :uni16_to_x8(bufname, bufuname, PAGE_SIZE, uni_xlate, nls_io); |
391 | if (xlate_len == name_len) | 401 | if (xlate_len == name_len) |
392 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || | 402 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || |
393 | (anycase && !nls_strnicmp(nls_io, name, bufname, | 403 | (anycase && !nls_strnicmp(nls_io, name, bufname, |
@@ -396,8 +406,8 @@ parse_record: | |||
396 | 406 | ||
397 | if (nr_slots) { | 407 | if (nr_slots) { |
398 | xlate_len = utf8 | 408 | xlate_len = utf8 |
399 | ?utf8_wcstombs(bufname, unicode, sizeof(bufname)) | 409 | ?utf8_wcstombs(bufname, unicode, PAGE_SIZE) |
400 | :uni16_to_x8(bufname, unicode, uni_xlate, nls_io); | 410 | :uni16_to_x8(bufname, unicode, PAGE_SIZE, uni_xlate, nls_io); |
401 | if (xlate_len != name_len) | 411 | if (xlate_len != name_len) |
402 | continue; | 412 | continue; |
403 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || | 413 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || |
@@ -416,6 +426,8 @@ Found: | |||
416 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); | 426 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); |
417 | err = 0; | 427 | err = 0; |
418 | EODir: | 428 | EODir: |
429 | if (bufname) | ||
430 | free_page((unsigned long)bufname); | ||
419 | if (unicode) | 431 | if (unicode) |
420 | free_page((unsigned long)unicode); | 432 | free_page((unsigned long)unicode); |
421 | 433 | ||
@@ -598,7 +610,7 @@ parse_record: | |||
598 | if (isvfat) { | 610 | if (isvfat) { |
599 | bufuname[j] = 0x0000; | 611 | bufuname[j] = 0x0000; |
600 | i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname)) | 612 | i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname)) |
601 | : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io); | 613 | : uni16_to_x8(bufname, bufuname, sizeof(bufname), uni_xlate, nls_io); |
602 | } | 614 | } |
603 | 615 | ||
604 | fill_name = bufname; | 616 | fill_name = bufname; |
@@ -610,7 +622,7 @@ parse_record: | |||
610 | int buf_size = PAGE_SIZE - (261 * sizeof(unicode[0])); | 622 | int buf_size = PAGE_SIZE - (261 * sizeof(unicode[0])); |
611 | int long_len = utf8 | 623 | int long_len = utf8 |
612 | ? utf8_wcstombs(longname, unicode, buf_size) | 624 | ? utf8_wcstombs(longname, unicode, buf_size) |
613 | : uni16_to_x8(longname, unicode, uni_xlate, nls_io); | 625 | : uni16_to_x8(longname, unicode, buf_size, uni_xlate, nls_io); |
614 | 626 | ||
615 | if (!both) { | 627 | if (!both) { |
616 | fill_name = longname; | 628 | fill_name = longname; |