diff options
Diffstat (limited to 'fs/fat/dir.c')
-rw-r--r-- | fs/fat/dir.c | 131 |
1 files changed, 67 insertions, 64 deletions
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index b57c4b1db636..a4410740627f 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c | |||
@@ -123,10 +123,11 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos, | |||
123 | * but ignore that right now. | 123 | * but ignore that right now. |
124 | * Ahem... Stack smashing in ring 0 isn't fun. Fixed. | 124 | * Ahem... Stack smashing in ring 0 isn't fun. Fixed. |
125 | */ | 125 | */ |
126 | static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int len, | 126 | static int uni16_to_x8(unsigned char *ascii, const wchar_t *uni, int len, |
127 | int uni_xlate, struct nls_table *nls) | 127 | int uni_xlate, struct nls_table *nls) |
128 | { | 128 | { |
129 | wchar_t *ip, ec; | 129 | const wchar_t *ip; |
130 | wchar_t ec; | ||
130 | unsigned char *op, nc; | 131 | unsigned char *op, nc; |
131 | int charlen; | 132 | int charlen; |
132 | int k; | 133 | int k; |
@@ -166,6 +167,16 @@ static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int len, | |||
166 | return (op - ascii); | 167 | return (op - ascii); |
167 | } | 168 | } |
168 | 169 | ||
170 | static inline int fat_uni_to_x8(struct msdos_sb_info *sbi, const wchar_t *uni, | ||
171 | unsigned char *buf, int size) | ||
172 | { | ||
173 | if (sbi->options.utf8) | ||
174 | return utf8_wcstombs(buf, uni, size); | ||
175 | else | ||
176 | return uni16_to_x8(buf, uni, size, sbi->options.unicode_xlate, | ||
177 | sbi->nls_io); | ||
178 | } | ||
179 | |||
169 | static inline int | 180 | static inline int |
170 | fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) | 181 | fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) |
171 | { | 182 | { |
@@ -226,6 +237,19 @@ fat_shortname2uni(struct nls_table *nls, unsigned char *buf, int buf_size, | |||
226 | return len; | 237 | return len; |
227 | } | 238 | } |
228 | 239 | ||
240 | static inline int fat_name_match(struct msdos_sb_info *sbi, | ||
241 | const unsigned char *a, int a_len, | ||
242 | const unsigned char *b, int b_len) | ||
243 | { | ||
244 | if (a_len != b_len) | ||
245 | return 0; | ||
246 | |||
247 | if (sbi->options.name_check != 's') | ||
248 | return !nls_strnicmp(sbi->nls_io, a, b, a_len); | ||
249 | else | ||
250 | return !memcmp(a, b, a_len); | ||
251 | } | ||
252 | |||
229 | enum { PARSE_INVALID = 1, PARSE_NOT_LONGNAME, PARSE_EOF, }; | 253 | enum { PARSE_INVALID = 1, PARSE_NOT_LONGNAME, PARSE_EOF, }; |
230 | 254 | ||
231 | /** | 255 | /** |
@@ -311,29 +335,24 @@ int fat_search_long(struct inode *inode, const unsigned char *name, | |||
311 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 335 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
312 | struct buffer_head *bh = NULL; | 336 | struct buffer_head *bh = NULL; |
313 | struct msdos_dir_entry *de; | 337 | struct msdos_dir_entry *de; |
314 | struct nls_table *nls_io = sbi->nls_io; | ||
315 | struct nls_table *nls_disk = sbi->nls_disk; | 338 | struct nls_table *nls_disk = sbi->nls_disk; |
316 | wchar_t bufuname[14]; | ||
317 | unsigned char nr_slots; | 339 | unsigned char nr_slots; |
318 | int xlate_len; | 340 | wchar_t bufuname[14]; |
319 | wchar_t *unicode = NULL; | 341 | wchar_t *unicode = NULL; |
320 | unsigned char work[MSDOS_NAME]; | 342 | unsigned char work[MSDOS_NAME]; |
321 | unsigned char *bufname = NULL; | 343 | unsigned char *bufname = NULL; |
322 | int uni_xlate = sbi->options.unicode_xlate; | ||
323 | int utf8 = sbi->options.utf8; | ||
324 | int anycase = (sbi->options.name_check != 's'); | ||
325 | unsigned short opt_shortname = sbi->options.shortname; | 344 | unsigned short opt_shortname = sbi->options.shortname; |
326 | loff_t cpos = 0; | 345 | loff_t cpos = 0; |
327 | int chl, i, j, last_u, err; | 346 | int chl, i, j, last_u, err, len; |
328 | 347 | ||
329 | bufname = __getname(); | 348 | bufname = __getname(); |
330 | if (!bufname) | 349 | if (!bufname) |
331 | return -ENOMEM; | 350 | return -ENOMEM; |
332 | 351 | ||
333 | err = -ENOENT; | 352 | err = -ENOENT; |
334 | while(1) { | 353 | while (1) { |
335 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) | 354 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) |
336 | goto EODir; | 355 | goto end_of_dir; |
337 | parse_record: | 356 | parse_record: |
338 | nr_slots = 0; | 357 | nr_slots = 0; |
339 | if (de->name[0] == DELETED_FLAG) | 358 | if (de->name[0] == DELETED_FLAG) |
@@ -352,7 +371,7 @@ parse_record: | |||
352 | else if (status == PARSE_NOT_LONGNAME) | 371 | else if (status == PARSE_NOT_LONGNAME) |
353 | goto parse_record; | 372 | goto parse_record; |
354 | else if (status == PARSE_EOF) | 373 | else if (status == PARSE_EOF) |
355 | goto EODir; | 374 | goto end_of_dir; |
356 | } | 375 | } |
357 | 376 | ||
358 | memcpy(work, de->name, sizeof(de->name)); | 377 | memcpy(work, de->name, sizeof(de->name)); |
@@ -393,30 +412,21 @@ parse_record: | |||
393 | if (!last_u) | 412 | if (!last_u) |
394 | continue; | 413 | continue; |
395 | 414 | ||
415 | /* Compare shortname */ | ||
396 | bufuname[last_u] = 0x0000; | 416 | bufuname[last_u] = 0x0000; |
397 | xlate_len = utf8 | 417 | len = fat_uni_to_x8(sbi, bufuname, bufname, PATH_MAX); |
398 | ?utf8_wcstombs(bufname, bufuname, PATH_MAX) | 418 | if (fat_name_match(sbi, name, name_len, bufname, len)) |
399 | :uni16_to_x8(bufname, bufuname, PATH_MAX, uni_xlate, nls_io); | 419 | goto found; |
400 | if (xlate_len == name_len) | ||
401 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || | ||
402 | (anycase && !nls_strnicmp(nls_io, name, bufname, | ||
403 | xlate_len))) | ||
404 | goto Found; | ||
405 | 420 | ||
406 | if (nr_slots) { | 421 | if (nr_slots) { |
407 | xlate_len = utf8 | 422 | /* Compare longname */ |
408 | ?utf8_wcstombs(bufname, unicode, PATH_MAX) | 423 | len = fat_uni_to_x8(sbi, unicode, bufname, PATH_MAX); |
409 | :uni16_to_x8(bufname, unicode, PATH_MAX, uni_xlate, nls_io); | 424 | if (fat_name_match(sbi, name, name_len, bufname, len)) |
410 | if (xlate_len != name_len) | 425 | goto found; |
411 | continue; | ||
412 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || | ||
413 | (anycase && !nls_strnicmp(nls_io, name, bufname, | ||
414 | xlate_len))) | ||
415 | goto Found; | ||
416 | } | 426 | } |
417 | } | 427 | } |
418 | 428 | ||
419 | Found: | 429 | found: |
420 | nr_slots++; /* include the de */ | 430 | nr_slots++; /* include the de */ |
421 | sinfo->slot_off = cpos - nr_slots * sizeof(*de); | 431 | sinfo->slot_off = cpos - nr_slots * sizeof(*de); |
422 | sinfo->nr_slots = nr_slots; | 432 | sinfo->nr_slots = nr_slots; |
@@ -424,7 +434,7 @@ Found: | |||
424 | sinfo->bh = bh; | 434 | sinfo->bh = bh; |
425 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); | 435 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); |
426 | err = 0; | 436 | err = 0; |
427 | EODir: | 437 | end_of_dir: |
428 | if (bufname) | 438 | if (bufname) |
429 | __putname(bufname); | 439 | __putname(bufname); |
430 | if (unicode) | 440 | if (unicode) |
@@ -452,23 +462,19 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent, | |||
452 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 462 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
453 | struct buffer_head *bh; | 463 | struct buffer_head *bh; |
454 | struct msdos_dir_entry *de; | 464 | struct msdos_dir_entry *de; |
455 | struct nls_table *nls_io = sbi->nls_io; | ||
456 | struct nls_table *nls_disk = sbi->nls_disk; | 465 | struct nls_table *nls_disk = sbi->nls_disk; |
457 | unsigned char long_slots; | 466 | unsigned char nr_slots; |
458 | const char *fill_name; | ||
459 | int fill_len; | ||
460 | wchar_t bufuname[14]; | 467 | wchar_t bufuname[14]; |
461 | wchar_t *unicode = NULL; | 468 | wchar_t *unicode = NULL; |
462 | unsigned char c, work[MSDOS_NAME], bufname[56], *ptname = bufname; | 469 | unsigned char c, work[MSDOS_NAME], bufname[56], *ptname = bufname; |
463 | unsigned long lpos, dummy, *furrfu = &lpos; | 470 | unsigned short opt_shortname = sbi->options.shortname; |
464 | int uni_xlate = sbi->options.unicode_xlate; | ||
465 | int isvfat = sbi->options.isvfat; | 471 | int isvfat = sbi->options.isvfat; |
466 | int utf8 = sbi->options.utf8; | ||
467 | int nocase = sbi->options.nocase; | 472 | int nocase = sbi->options.nocase; |
468 | unsigned short opt_shortname = sbi->options.shortname; | 473 | const char *fill_name; |
469 | unsigned long inum; | 474 | unsigned long inum; |
470 | int chi, chl, i, i2, j, last, last_u, dotoffset = 0; | 475 | unsigned long lpos, dummy, *furrfu = &lpos; |
471 | loff_t cpos; | 476 | loff_t cpos; |
477 | int chi, chl, i, i2, j, last, last_u, dotoffset = 0, fill_len; | ||
472 | int ret = 0; | 478 | int ret = 0; |
473 | 479 | ||
474 | lock_super(sb); | 480 | lock_super(sb); |
@@ -488,43 +494,43 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent, | |||
488 | cpos = 0; | 494 | cpos = 0; |
489 | } | 495 | } |
490 | } | 496 | } |
491 | if (cpos & (sizeof(struct msdos_dir_entry)-1)) { | 497 | if (cpos & (sizeof(struct msdos_dir_entry) - 1)) { |
492 | ret = -ENOENT; | 498 | ret = -ENOENT; |
493 | goto out; | 499 | goto out; |
494 | } | 500 | } |
495 | 501 | ||
496 | bh = NULL; | 502 | bh = NULL; |
497 | GetNew: | 503 | get_new: |
498 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) | 504 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) |
499 | goto EODir; | 505 | goto end_of_dir; |
500 | parse_record: | 506 | parse_record: |
501 | long_slots = 0; | 507 | nr_slots = 0; |
502 | /* Check for long filename entry */ | 508 | /* Check for long filename entry */ |
503 | if (isvfat) { | 509 | if (isvfat) { |
504 | if (de->name[0] == DELETED_FLAG) | 510 | if (de->name[0] == DELETED_FLAG) |
505 | goto RecEnd; | 511 | goto record_end; |
506 | if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME)) | 512 | if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME)) |
507 | goto RecEnd; | 513 | goto record_end; |
508 | if (de->attr != ATTR_EXT && IS_FREE(de->name)) | 514 | if (de->attr != ATTR_EXT && IS_FREE(de->name)) |
509 | goto RecEnd; | 515 | goto record_end; |
510 | } else { | 516 | } else { |
511 | if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name)) | 517 | if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name)) |
512 | goto RecEnd; | 518 | goto record_end; |
513 | } | 519 | } |
514 | 520 | ||
515 | if (isvfat && de->attr == ATTR_EXT) { | 521 | if (isvfat && de->attr == ATTR_EXT) { |
516 | int status = fat_parse_long(inode, &cpos, &bh, &de, | 522 | int status = fat_parse_long(inode, &cpos, &bh, &de, |
517 | &unicode, &long_slots); | 523 | &unicode, &nr_slots); |
518 | if (status < 0) { | 524 | if (status < 0) { |
519 | filp->f_pos = cpos; | 525 | filp->f_pos = cpos; |
520 | ret = status; | 526 | ret = status; |
521 | goto out; | 527 | goto out; |
522 | } else if (status == PARSE_INVALID) | 528 | } else if (status == PARSE_INVALID) |
523 | goto RecEnd; | 529 | goto record_end; |
524 | else if (status == PARSE_NOT_LONGNAME) | 530 | else if (status == PARSE_NOT_LONGNAME) |
525 | goto parse_record; | 531 | goto parse_record; |
526 | else if (status == PARSE_EOF) | 532 | else if (status == PARSE_EOF) |
527 | goto EODir; | 533 | goto end_of_dir; |
528 | } | 534 | } |
529 | 535 | ||
530 | if (sbi->options.dotsOK) { | 536 | if (sbi->options.dotsOK) { |
@@ -586,12 +592,12 @@ parse_record: | |||
586 | } | 592 | } |
587 | } | 593 | } |
588 | if (!last) | 594 | if (!last) |
589 | goto RecEnd; | 595 | goto record_end; |
590 | 596 | ||
591 | i = last + dotoffset; | 597 | i = last + dotoffset; |
592 | j = last_u; | 598 | j = last_u; |
593 | 599 | ||
594 | lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry); | 600 | lpos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry); |
595 | if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) | 601 | if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) |
596 | inum = inode->i_ino; | 602 | inum = inode->i_ino; |
597 | else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) { | 603 | else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) { |
@@ -608,20 +614,17 @@ parse_record: | |||
608 | 614 | ||
609 | if (isvfat) { | 615 | if (isvfat) { |
610 | bufuname[j] = 0x0000; | 616 | bufuname[j] = 0x0000; |
611 | i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname)) | 617 | i = fat_uni_to_x8(sbi, bufuname, bufname, sizeof(bufname)); |
612 | : uni16_to_x8(bufname, bufuname, sizeof(bufname), uni_xlate, nls_io); | ||
613 | } | 618 | } |
614 | 619 | ||
615 | fill_name = bufname; | 620 | fill_name = bufname; |
616 | fill_len = i; | 621 | fill_len = i; |
617 | if (!short_only && long_slots) { | 622 | if (!short_only && nr_slots) { |
618 | /* convert the unicode long name. 261 is maximum size | 623 | /* convert the unicode long name. 261 is maximum size |
619 | * of unicode buffer. (13 * slots + nul) */ | 624 | * of unicode buffer. (13 * slots + nul) */ |
620 | void *longname = unicode + 261; | 625 | void *longname = unicode + 261; |
621 | int buf_size = PATH_MAX - (261 * sizeof(unicode[0])); | 626 | int buf_size = PATH_MAX - (261 * sizeof(unicode[0])); |
622 | int long_len = utf8 | 627 | int long_len = fat_uni_to_x8(sbi, unicode, longname, buf_size); |
623 | ? utf8_wcstombs(longname, unicode, buf_size) | ||
624 | : uni16_to_x8(longname, unicode, buf_size, uni_xlate, nls_io); | ||
625 | 628 | ||
626 | if (!both) { | 629 | if (!both) { |
627 | fill_name = longname; | 630 | fill_name = longname; |
@@ -640,15 +643,15 @@ parse_record: | |||
640 | } | 643 | } |
641 | if (filldir(dirent, fill_name, fill_len, *furrfu, inum, | 644 | if (filldir(dirent, fill_name, fill_len, *furrfu, inum, |
642 | (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0) | 645 | (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0) |
643 | goto FillFailed; | 646 | goto fill_failed; |
644 | 647 | ||
645 | RecEnd: | 648 | record_end: |
646 | furrfu = &lpos; | 649 | furrfu = &lpos; |
647 | filp->f_pos = cpos; | 650 | filp->f_pos = cpos; |
648 | goto GetNew; | 651 | goto get_new; |
649 | EODir: | 652 | end_of_dir: |
650 | filp->f_pos = cpos; | 653 | filp->f_pos = cpos; |
651 | FillFailed: | 654 | fill_failed: |
652 | brelse(bh); | 655 | brelse(bh); |
653 | if (unicode) | 656 | if (unicode) |
654 | __putname(unicode); | 657 | __putname(unicode); |