aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat
diff options
context:
space:
mode:
authorSteven J. Magnani <steve@digidescorp.com>2012-07-30 17:42:16 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-30 20:25:20 -0400
commitdeb8274a0cf44827ec260330cc1d94d0f3dcfb94 (patch)
tree38f7f1f7e3cadf8a7f1964bacee576b6008b415c /fs/fat
parenta943ed71c9171fb5e3b256e8022bbedff95cc826 (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.c255
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
38static inline unsigned char fat_tolower(unsigned char c)
39{
40 return ((c >= 'A') && (c <= 'Z')) ? c+32 : c;
41}
42
38static inline loff_t fat_make_i_pos(struct super_block *sb, 43static 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 */
350static 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
642start_filldir: 661start_filldir: