diff options
Diffstat (limited to 'fs/fat/dir.c')
-rw-r--r-- | fs/fat/dir.c | 52 |
1 files changed, 32 insertions, 20 deletions
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 72cbcd61bd95..486725ee99ae 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 | } |
@@ -243,7 +247,7 @@ static int fat_parse_long(struct inode *dir, loff_t *pos, | |||
243 | unsigned char id, slot, slots, alias_checksum; | 247 | unsigned char id, slot, slots, alias_checksum; |
244 | 248 | ||
245 | if (!*unicode) { | 249 | if (!*unicode) { |
246 | *unicode = (wchar_t *)__get_free_page(GFP_KERNEL); | 250 | *unicode = __getname(); |
247 | if (!*unicode) { | 251 | if (!*unicode) { |
248 | brelse(*bh); | 252 | brelse(*bh); |
249 | return -ENOMEM; | 253 | return -ENOMEM; |
@@ -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 = __getname(); | ||
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, PATH_MAX) |
390 | :uni16_to_x8(bufname, bufuname, uni_xlate, nls_io); | 400 | :uni16_to_x8(bufname, bufuname, PATH_MAX, 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, PATH_MAX) |
400 | :uni16_to_x8(bufname, unicode, uni_xlate, nls_io); | 410 | :uni16_to_x8(bufname, unicode, PATH_MAX, 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,8 +426,10 @@ 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 | __putname(bufname); | ||
419 | if (unicode) | 431 | if (unicode) |
420 | free_page((unsigned long)unicode); | 432 | __putname(unicode); |
421 | 433 | ||
422 | return err; | 434 | return err; |
423 | } | 435 | } |
@@ -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; |
@@ -607,10 +619,10 @@ parse_record: | |||
607 | /* convert the unicode long name. 261 is maximum size | 619 | /* convert the unicode long name. 261 is maximum size |
608 | * of unicode buffer. (13 * slots + nul) */ | 620 | * of unicode buffer. (13 * slots + nul) */ |
609 | void *longname = unicode + 261; | 621 | void *longname = unicode + 261; |
610 | int buf_size = PAGE_SIZE - (261 * sizeof(unicode[0])); | 622 | int buf_size = PATH_MAX - (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; |
@@ -640,7 +652,7 @@ EODir: | |||
640 | FillFailed: | 652 | FillFailed: |
641 | brelse(bh); | 653 | brelse(bh); |
642 | if (unicode) | 654 | if (unicode) |
643 | free_page((unsigned long)unicode); | 655 | __putname(unicode); |
644 | out: | 656 | out: |
645 | unlock_kernel(); | 657 | unlock_kernel(); |
646 | return ret; | 658 | return ret; |