diff options
author | Steven J. Magnani <steve@digidescorp.com> | 2012-07-30 17:42:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-30 20:25:20 -0400 |
commit | deb8274a0cf44827ec260330cc1d94d0f3dcfb94 (patch) | |
tree | 38f7f1f7e3cadf8a7f1964bacee576b6008b415c /fs/fat | |
parent | a943ed71c9171fb5e3b256e8022bbedff95cc826 (diff) |
fat: refactor shortname parsing
Nearly identical shortname parsing is performed in fat_search_long() and
__fat_readdir(). Extract this code into a function that may be called by
both.
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
Acked-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')
-rw-r--r-- | fs/fat/dir.c | 255 |
1 files changed, 137 insertions, 118 deletions
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 6eaa28c98ad1..dc49ed2cbffa 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c | |||
@@ -35,6 +35,11 @@ | |||
35 | #define FAT_MAX_UNI_CHARS ((MSDOS_SLOTS - 1) * 13 + 1) | 35 | #define FAT_MAX_UNI_CHARS ((MSDOS_SLOTS - 1) * 13 + 1) |
36 | #define FAT_MAX_UNI_SIZE (FAT_MAX_UNI_CHARS * sizeof(wchar_t)) | 36 | #define FAT_MAX_UNI_SIZE (FAT_MAX_UNI_CHARS * sizeof(wchar_t)) |
37 | 37 | ||
38 | static inline unsigned char fat_tolower(unsigned char c) | ||
39 | { | ||
40 | return ((c >= 'A') && (c <= 'Z')) ? c+32 : c; | ||
41 | } | ||
42 | |||
38 | static inline loff_t fat_make_i_pos(struct super_block *sb, | 43 | static inline loff_t fat_make_i_pos(struct super_block *sb, |
39 | struct buffer_head *bh, | 44 | struct buffer_head *bh, |
40 | struct msdos_dir_entry *de) | 45 | struct msdos_dir_entry *de) |
@@ -333,6 +338,124 @@ parse_long: | |||
333 | return 0; | 338 | return 0; |
334 | } | 339 | } |
335 | 340 | ||
341 | /** | ||
342 | * fat_parse_short - Parse MS-DOS (short) directory entry. | ||
343 | * @sb: superblock | ||
344 | * @de: directory entry to parse | ||
345 | * @name: FAT_MAX_SHORT_SIZE array in which to place extracted name | ||
346 | * @dot_hidden: Nonzero == prepend '.' to names with ATTR_HIDDEN | ||
347 | * | ||
348 | * Returns the number of characters extracted into 'name'. | ||
349 | */ | ||
350 | static int fat_parse_short(struct super_block *sb, | ||
351 | const struct msdos_dir_entry *de, | ||
352 | unsigned char *name, int dot_hidden) | ||
353 | { | ||
354 | const struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
355 | int isvfat = sbi->options.isvfat; | ||
356 | int nocase = sbi->options.nocase; | ||
357 | unsigned short opt_shortname = sbi->options.shortname; | ||
358 | struct nls_table *nls_disk = sbi->nls_disk; | ||
359 | wchar_t uni_name[14]; | ||
360 | unsigned char c, work[MSDOS_NAME]; | ||
361 | unsigned char *ptname = name; | ||
362 | int chi, chl, i, j, k; | ||
363 | int dotoffset = 0; | ||
364 | int name_len = 0, uni_len = 0; | ||
365 | |||
366 | if (!isvfat && dot_hidden && (de->attr & ATTR_HIDDEN)) { | ||
367 | *ptname++ = '.'; | ||
368 | dotoffset = 1; | ||
369 | } | ||
370 | |||
371 | memcpy(work, de->name, sizeof(work)); | ||
372 | /* see namei.c, msdos_format_name */ | ||
373 | if (work[0] == 0x05) | ||
374 | work[0] = 0xE5; | ||
375 | |||
376 | /* Filename */ | ||
377 | for (i = 0, j = 0; i < 8;) { | ||
378 | c = work[i]; | ||
379 | if (!c) | ||
380 | break; | ||
381 | chl = fat_shortname2uni(nls_disk, &work[i], 8 - i, | ||
382 | &uni_name[j++], opt_shortname, | ||
383 | de->lcase & CASE_LOWER_BASE); | ||
384 | if (chl <= 1) { | ||
385 | if (!isvfat) | ||
386 | ptname[i] = nocase ? c : fat_tolower(c); | ||
387 | i++; | ||
388 | if (c != ' ') { | ||
389 | name_len = i; | ||
390 | uni_len = j; | ||
391 | } | ||
392 | } else { | ||
393 | uni_len = j; | ||
394 | if (isvfat) | ||
395 | i += min(chl, 8-i); | ||
396 | else { | ||
397 | for (chi = 0; chi < chl && i < 8; chi++, i++) | ||
398 | ptname[i] = work[i]; | ||
399 | } | ||
400 | if (chl) | ||
401 | name_len = i; | ||
402 | } | ||
403 | } | ||
404 | |||
405 | i = name_len; | ||
406 | j = uni_len; | ||
407 | fat_short2uni(nls_disk, ".", 1, &uni_name[j++]); | ||
408 | if (!isvfat) | ||
409 | ptname[i] = '.'; | ||
410 | i++; | ||
411 | |||
412 | /* Extension */ | ||
413 | for (k = 8; k < MSDOS_NAME;) { | ||
414 | c = work[k]; | ||
415 | if (!c) | ||
416 | break; | ||
417 | chl = fat_shortname2uni(nls_disk, &work[k], MSDOS_NAME - k, | ||
418 | &uni_name[j++], opt_shortname, | ||
419 | de->lcase & CASE_LOWER_EXT); | ||
420 | if (chl <= 1) { | ||
421 | k++; | ||
422 | if (!isvfat) | ||
423 | ptname[i] = nocase ? c : fat_tolower(c); | ||
424 | i++; | ||
425 | if (c != ' ') { | ||
426 | name_len = i; | ||
427 | uni_len = j; | ||
428 | } | ||
429 | } else { | ||
430 | uni_len = j; | ||
431 | if (isvfat) { | ||
432 | int offset = min(chl, MSDOS_NAME-k); | ||
433 | k += offset; | ||
434 | i += offset; | ||
435 | } else { | ||
436 | for (chi = 0; chi < chl && k < MSDOS_NAME; | ||
437 | chi++, i++, k++) { | ||
438 | ptname[i] = work[k]; | ||
439 | } | ||
440 | } | ||
441 | if (chl) | ||
442 | name_len = i; | ||
443 | } | ||
444 | } | ||
445 | |||
446 | if (name_len > 0) { | ||
447 | name_len += dotoffset; | ||
448 | |||
449 | if (sbi->options.isvfat) { | ||
450 | uni_name[uni_len] = 0x0000; | ||
451 | name_len = fat_uni_to_x8(sb, uni_name, name, | ||
452 | FAT_MAX_SHORT_SIZE); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | return name_len; | ||
457 | } | ||
458 | |||
336 | /* | 459 | /* |
337 | * Return values: negative -> error, 0 -> not found, positive -> found, | 460 | * Return values: negative -> error, 0 -> not found, positive -> found, |
338 | * value is the total amount of slots, including the shortname entry. | 461 | * value is the total amount of slots, including the shortname entry. |
@@ -344,15 +467,11 @@ int fat_search_long(struct inode *inode, const unsigned char *name, | |||
344 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 467 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
345 | struct buffer_head *bh = NULL; | 468 | struct buffer_head *bh = NULL; |
346 | struct msdos_dir_entry *de; | 469 | struct msdos_dir_entry *de; |
347 | struct nls_table *nls_disk = sbi->nls_disk; | ||
348 | unsigned char nr_slots; | 470 | unsigned char nr_slots; |
349 | wchar_t bufuname[14]; | ||
350 | wchar_t *unicode = NULL; | 471 | wchar_t *unicode = NULL; |
351 | unsigned char work[MSDOS_NAME]; | ||
352 | unsigned char bufname[FAT_MAX_SHORT_SIZE]; | 472 | unsigned char bufname[FAT_MAX_SHORT_SIZE]; |
353 | unsigned short opt_shortname = sbi->options.shortname; | ||
354 | loff_t cpos = 0; | 473 | loff_t cpos = 0; |
355 | int chl, i, j, last_u, err, len; | 474 | int err, len; |
356 | 475 | ||
357 | err = -ENOENT; | 476 | err = -ENOENT; |
358 | while (1) { | 477 | while (1) { |
@@ -380,47 +499,16 @@ parse_record: | |||
380 | goto end_of_dir; | 499 | goto end_of_dir; |
381 | } | 500 | } |
382 | 501 | ||
383 | memcpy(work, de->name, sizeof(de->name)); | 502 | /* Never prepend '.' to hidden files here. |
384 | /* see namei.c, msdos_format_name */ | 503 | * That is done only for msdos mounts (and only when |
385 | if (work[0] == 0x05) | 504 | * 'dotsOK=yes'); if we are executing here, it is in the |
386 | work[0] = 0xE5; | 505 | * context of a vfat mount. |
387 | for (i = 0, j = 0, last_u = 0; i < 8;) { | 506 | */ |
388 | if (!work[i]) | 507 | len = fat_parse_short(sb, de, bufname, 0); |
389 | break; | 508 | if (len == 0) |
390 | chl = fat_shortname2uni(nls_disk, &work[i], 8 - i, | ||
391 | &bufuname[j++], opt_shortname, | ||
392 | de->lcase & CASE_LOWER_BASE); | ||
393 | if (chl <= 1) { | ||
394 | if (work[i] != ' ') | ||
395 | last_u = j; | ||
396 | } else { | ||
397 | last_u = j; | ||
398 | } | ||
399 | i += chl; | ||
400 | } | ||
401 | j = last_u; | ||
402 | fat_short2uni(nls_disk, ".", 1, &bufuname[j++]); | ||
403 | for (i = 8; i < MSDOS_NAME;) { | ||
404 | if (!work[i]) | ||
405 | break; | ||
406 | chl = fat_shortname2uni(nls_disk, &work[i], | ||
407 | MSDOS_NAME - i, | ||
408 | &bufuname[j++], opt_shortname, | ||
409 | de->lcase & CASE_LOWER_EXT); | ||
410 | if (chl <= 1) { | ||
411 | if (work[i] != ' ') | ||
412 | last_u = j; | ||
413 | } else { | ||
414 | last_u = j; | ||
415 | } | ||
416 | i += chl; | ||
417 | } | ||
418 | if (!last_u) | ||
419 | continue; | 509 | continue; |
420 | 510 | ||
421 | /* Compare shortname */ | 511 | /* Compare shortname */ |
422 | bufuname[last_u] = 0x0000; | ||
423 | len = fat_uni_to_x8(sb, bufuname, bufname, sizeof(bufname)); | ||
424 | if (fat_name_match(sbi, name, name_len, bufname, len)) | 512 | if (fat_name_match(sbi, name, name_len, bufname, len)) |
425 | goto found; | 513 | goto found; |
426 | 514 | ||
@@ -469,20 +557,15 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent, | |||
469 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 557 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
470 | struct buffer_head *bh; | 558 | struct buffer_head *bh; |
471 | struct msdos_dir_entry *de; | 559 | struct msdos_dir_entry *de; |
472 | struct nls_table *nls_disk = sbi->nls_disk; | ||
473 | unsigned char nr_slots; | 560 | unsigned char nr_slots; |
474 | wchar_t bufuname[14]; | ||
475 | wchar_t *unicode = NULL; | 561 | wchar_t *unicode = NULL; |
476 | unsigned char c, work[MSDOS_NAME]; | 562 | unsigned char bufname[FAT_MAX_SHORT_SIZE]; |
477 | unsigned char bufname[FAT_MAX_SHORT_SIZE], *ptname = bufname; | ||
478 | unsigned short opt_shortname = sbi->options.shortname; | ||
479 | int isvfat = sbi->options.isvfat; | 563 | int isvfat = sbi->options.isvfat; |
480 | int nocase = sbi->options.nocase; | ||
481 | const char *fill_name = NULL; | 564 | const char *fill_name = NULL; |
482 | unsigned long inum; | 565 | unsigned long inum; |
483 | unsigned long lpos, dummy, *furrfu = &lpos; | 566 | unsigned long lpos, dummy, *furrfu = &lpos; |
484 | loff_t cpos; | 567 | loff_t cpos; |
485 | int chi, chl, i, i2, j, last, last_u, dotoffset = 0, fill_len = 0; | 568 | int short_len = 0, fill_len = 0; |
486 | int ret = 0; | 569 | int ret = 0; |
487 | 570 | ||
488 | lock_super(sb); | 571 | lock_super(sb); |
@@ -556,74 +639,10 @@ parse_record: | |||
556 | } | 639 | } |
557 | } | 640 | } |
558 | 641 | ||
559 | if (sbi->options.dotsOK) { | 642 | short_len = fat_parse_short(sb, de, bufname, sbi->options.dotsOK); |
560 | ptname = bufname; | 643 | if (short_len == 0) |
561 | dotoffset = 0; | ||
562 | if (de->attr & ATTR_HIDDEN) { | ||
563 | *ptname++ = '.'; | ||
564 | dotoffset = 1; | ||
565 | } | ||
566 | } | ||
567 | |||
568 | memcpy(work, de->name, sizeof(de->name)); | ||
569 | /* see namei.c, msdos_format_name */ | ||
570 | if (work[0] == 0x05) | ||
571 | work[0] = 0xE5; | ||
572 | for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) { | ||
573 | if (!(c = work[i])) | ||
574 | break; | ||
575 | chl = fat_shortname2uni(nls_disk, &work[i], 8 - i, | ||
576 | &bufuname[j++], opt_shortname, | ||
577 | de->lcase & CASE_LOWER_BASE); | ||
578 | if (chl <= 1) { | ||
579 | ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c; | ||
580 | if (c != ' ') { | ||
581 | last = i; | ||
582 | last_u = j; | ||
583 | } | ||
584 | } else { | ||
585 | last_u = j; | ||
586 | for (chi = 0; chi < chl && i < 8; chi++) { | ||
587 | ptname[i] = work[i]; | ||
588 | i++; last = i; | ||
589 | } | ||
590 | } | ||
591 | } | ||
592 | i = last; | ||
593 | j = last_u; | ||
594 | fat_short2uni(nls_disk, ".", 1, &bufuname[j++]); | ||
595 | ptname[i++] = '.'; | ||
596 | for (i2 = 8; i2 < MSDOS_NAME;) { | ||
597 | if (!(c = work[i2])) | ||
598 | break; | ||
599 | chl = fat_shortname2uni(nls_disk, &work[i2], MSDOS_NAME - i2, | ||
600 | &bufuname[j++], opt_shortname, | ||
601 | de->lcase & CASE_LOWER_EXT); | ||
602 | if (chl <= 1) { | ||
603 | i2++; | ||
604 | ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c; | ||
605 | if (c != ' ') { | ||
606 | last = i; | ||
607 | last_u = j; | ||
608 | } | ||
609 | } else { | ||
610 | last_u = j; | ||
611 | for (chi = 0; chi < chl && i2 < MSDOS_NAME; chi++) { | ||
612 | ptname[i++] = work[i2++]; | ||
613 | last = i; | ||
614 | } | ||
615 | } | ||
616 | } | ||
617 | if (!last) | ||
618 | goto record_end; | 644 | goto record_end; |
619 | 645 | ||
620 | i = last + dotoffset; | ||
621 | j = last_u; | ||
622 | |||
623 | if (isvfat) { | ||
624 | bufuname[j] = 0x0000; | ||
625 | i = fat_uni_to_x8(sb, bufuname, bufname, sizeof(bufname)); | ||
626 | } | ||
627 | if (nr_slots) { | 646 | if (nr_slots) { |
628 | /* hack for fat_ioctl_filldir() */ | 647 | /* hack for fat_ioctl_filldir() */ |
629 | struct fat_ioctl_filldir_callback *p = dirent; | 648 | struct fat_ioctl_filldir_callback *p = dirent; |
@@ -631,12 +650,12 @@ parse_record: | |||
631 | p->longname = fill_name; | 650 | p->longname = fill_name; |
632 | p->long_len = fill_len; | 651 | p->long_len = fill_len; |
633 | p->shortname = bufname; | 652 | p->shortname = bufname; |
634 | p->short_len = i; | 653 | p->short_len = short_len; |
635 | fill_name = NULL; | 654 | fill_name = NULL; |
636 | fill_len = 0; | 655 | fill_len = 0; |
637 | } else { | 656 | } else { |
638 | fill_name = bufname; | 657 | fill_name = bufname; |
639 | fill_len = i; | 658 | fill_len = short_len; |
640 | } | 659 | } |
641 | 660 | ||
642 | start_filldir: | 661 | start_filldir: |