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>
This commit is contained in:
parent
a943ed71c9
commit
deb8274a0c
1 changed files with 137 additions and 118 deletions
255
fs/fat/dir.c
255
fs/fat/dir.c
|
@ -35,6 +35,11 @@
|
||||||
#define FAT_MAX_UNI_CHARS ((MSDOS_SLOTS - 1) * 13 + 1)
|
#define FAT_MAX_UNI_CHARS ((MSDOS_SLOTS - 1) * 13 + 1)
|
||||||
#define FAT_MAX_UNI_SIZE (FAT_MAX_UNI_CHARS * sizeof(wchar_t))
|
#define FAT_MAX_UNI_SIZE (FAT_MAX_UNI_CHARS * sizeof(wchar_t))
|
||||||
|
|
||||||
|
static inline unsigned char fat_tolower(unsigned char c)
|
||||||
|
{
|
||||||
|
return ((c >= 'A') && (c <= 'Z')) ? c+32 : c;
|
||||||
|
}
|
||||||
|
|
||||||
static inline loff_t fat_make_i_pos(struct super_block *sb,
|
static inline loff_t fat_make_i_pos(struct super_block *sb,
|
||||||
struct buffer_head *bh,
|
struct buffer_head *bh,
|
||||||
struct msdos_dir_entry *de)
|
struct msdos_dir_entry *de)
|
||||||
|
@ -333,6 +338,124 @@ static int fat_parse_long(struct inode *dir, loff_t *pos,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fat_parse_short - Parse MS-DOS (short) directory entry.
|
||||||
|
* @sb: superblock
|
||||||
|
* @de: directory entry to parse
|
||||||
|
* @name: FAT_MAX_SHORT_SIZE array in which to place extracted name
|
||||||
|
* @dot_hidden: Nonzero == prepend '.' to names with ATTR_HIDDEN
|
||||||
|
*
|
||||||
|
* Returns the number of characters extracted into 'name'.
|
||||||
|
*/
|
||||||
|
static int fat_parse_short(struct super_block *sb,
|
||||||
|
const struct msdos_dir_entry *de,
|
||||||
|
unsigned char *name, int dot_hidden)
|
||||||
|
{
|
||||||
|
const struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
||||||
|
int isvfat = sbi->options.isvfat;
|
||||||
|
int nocase = sbi->options.nocase;
|
||||||
|
unsigned short opt_shortname = sbi->options.shortname;
|
||||||
|
struct nls_table *nls_disk = sbi->nls_disk;
|
||||||
|
wchar_t uni_name[14];
|
||||||
|
unsigned char c, work[MSDOS_NAME];
|
||||||
|
unsigned char *ptname = name;
|
||||||
|
int chi, chl, i, j, k;
|
||||||
|
int dotoffset = 0;
|
||||||
|
int name_len = 0, uni_len = 0;
|
||||||
|
|
||||||
|
if (!isvfat && dot_hidden && (de->attr & ATTR_HIDDEN)) {
|
||||||
|
*ptname++ = '.';
|
||||||
|
dotoffset = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(work, de->name, sizeof(work));
|
||||||
|
/* see namei.c, msdos_format_name */
|
||||||
|
if (work[0] == 0x05)
|
||||||
|
work[0] = 0xE5;
|
||||||
|
|
||||||
|
/* Filename */
|
||||||
|
for (i = 0, j = 0; i < 8;) {
|
||||||
|
c = work[i];
|
||||||
|
if (!c)
|
||||||
|
break;
|
||||||
|
chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
|
||||||
|
&uni_name[j++], opt_shortname,
|
||||||
|
de->lcase & CASE_LOWER_BASE);
|
||||||
|
if (chl <= 1) {
|
||||||
|
if (!isvfat)
|
||||||
|
ptname[i] = nocase ? c : fat_tolower(c);
|
||||||
|
i++;
|
||||||
|
if (c != ' ') {
|
||||||
|
name_len = i;
|
||||||
|
uni_len = j;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uni_len = j;
|
||||||
|
if (isvfat)
|
||||||
|
i += min(chl, 8-i);
|
||||||
|
else {
|
||||||
|
for (chi = 0; chi < chl && i < 8; chi++, i++)
|
||||||
|
ptname[i] = work[i];
|
||||||
|
}
|
||||||
|
if (chl)
|
||||||
|
name_len = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i = name_len;
|
||||||
|
j = uni_len;
|
||||||
|
fat_short2uni(nls_disk, ".", 1, &uni_name[j++]);
|
||||||
|
if (!isvfat)
|
||||||
|
ptname[i] = '.';
|
||||||
|
i++;
|
||||||
|
|
||||||
|
/* Extension */
|
||||||
|
for (k = 8; k < MSDOS_NAME;) {
|
||||||
|
c = work[k];
|
||||||
|
if (!c)
|
||||||
|
break;
|
||||||
|
chl = fat_shortname2uni(nls_disk, &work[k], MSDOS_NAME - k,
|
||||||
|
&uni_name[j++], opt_shortname,
|
||||||
|
de->lcase & CASE_LOWER_EXT);
|
||||||
|
if (chl <= 1) {
|
||||||
|
k++;
|
||||||
|
if (!isvfat)
|
||||||
|
ptname[i] = nocase ? c : fat_tolower(c);
|
||||||
|
i++;
|
||||||
|
if (c != ' ') {
|
||||||
|
name_len = i;
|
||||||
|
uni_len = j;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uni_len = j;
|
||||||
|
if (isvfat) {
|
||||||
|
int offset = min(chl, MSDOS_NAME-k);
|
||||||
|
k += offset;
|
||||||
|
i += offset;
|
||||||
|
} else {
|
||||||
|
for (chi = 0; chi < chl && k < MSDOS_NAME;
|
||||||
|
chi++, i++, k++) {
|
||||||
|
ptname[i] = work[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chl)
|
||||||
|
name_len = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name_len > 0) {
|
||||||
|
name_len += dotoffset;
|
||||||
|
|
||||||
|
if (sbi->options.isvfat) {
|
||||||
|
uni_name[uni_len] = 0x0000;
|
||||||
|
name_len = fat_uni_to_x8(sb, uni_name, name,
|
||||||
|
FAT_MAX_SHORT_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return name_len;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return values: negative -> error, 0 -> not found, positive -> found,
|
* Return values: negative -> error, 0 -> not found, positive -> found,
|
||||||
* value is the total amount of slots, including the shortname entry.
|
* 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,
|
||||||
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
||||||
struct buffer_head *bh = NULL;
|
struct buffer_head *bh = NULL;
|
||||||
struct msdos_dir_entry *de;
|
struct msdos_dir_entry *de;
|
||||||
struct nls_table *nls_disk = sbi->nls_disk;
|
|
||||||
unsigned char nr_slots;
|
unsigned char nr_slots;
|
||||||
wchar_t bufuname[14];
|
|
||||||
wchar_t *unicode = NULL;
|
wchar_t *unicode = NULL;
|
||||||
unsigned char work[MSDOS_NAME];
|
|
||||||
unsigned char bufname[FAT_MAX_SHORT_SIZE];
|
unsigned char bufname[FAT_MAX_SHORT_SIZE];
|
||||||
unsigned short opt_shortname = sbi->options.shortname;
|
|
||||||
loff_t cpos = 0;
|
loff_t cpos = 0;
|
||||||
int chl, i, j, last_u, err, len;
|
int err, len;
|
||||||
|
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -380,47 +499,16 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
|
||||||
goto end_of_dir;
|
goto end_of_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(work, de->name, sizeof(de->name));
|
/* Never prepend '.' to hidden files here.
|
||||||
/* see namei.c, msdos_format_name */
|
* That is done only for msdos mounts (and only when
|
||||||
if (work[0] == 0x05)
|
* 'dotsOK=yes'); if we are executing here, it is in the
|
||||||
work[0] = 0xE5;
|
* context of a vfat mount.
|
||||||
for (i = 0, j = 0, last_u = 0; i < 8;) {
|
*/
|
||||||
if (!work[i])
|
len = fat_parse_short(sb, de, bufname, 0);
|
||||||
break;
|
if (len == 0)
|
||||||
chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
|
|
||||||
&bufuname[j++], opt_shortname,
|
|
||||||
de->lcase & CASE_LOWER_BASE);
|
|
||||||
if (chl <= 1) {
|
|
||||||
if (work[i] != ' ')
|
|
||||||
last_u = j;
|
|
||||||
} else {
|
|
||||||
last_u = j;
|
|
||||||
}
|
|
||||||
i += chl;
|
|
||||||
}
|
|
||||||
j = last_u;
|
|
||||||
fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
|
|
||||||
for (i = 8; i < MSDOS_NAME;) {
|
|
||||||
if (!work[i])
|
|
||||||
break;
|
|
||||||
chl = fat_shortname2uni(nls_disk, &work[i],
|
|
||||||
MSDOS_NAME - i,
|
|
||||||
&bufuname[j++], opt_shortname,
|
|
||||||
de->lcase & CASE_LOWER_EXT);
|
|
||||||
if (chl <= 1) {
|
|
||||||
if (work[i] != ' ')
|
|
||||||
last_u = j;
|
|
||||||
} else {
|
|
||||||
last_u = j;
|
|
||||||
}
|
|
||||||
i += chl;
|
|
||||||
}
|
|
||||||
if (!last_u)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Compare shortname */
|
/* Compare shortname */
|
||||||
bufuname[last_u] = 0x0000;
|
|
||||||
len = fat_uni_to_x8(sb, bufuname, bufname, sizeof(bufname));
|
|
||||||
if (fat_name_match(sbi, name, name_len, bufname, len))
|
if (fat_name_match(sbi, name, name_len, bufname, len))
|
||||||
goto found;
|
goto found;
|
||||||
|
|
||||||
|
@ -469,20 +557,15 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
|
||||||
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
||||||
struct buffer_head *bh;
|
struct buffer_head *bh;
|
||||||
struct msdos_dir_entry *de;
|
struct msdos_dir_entry *de;
|
||||||
struct nls_table *nls_disk = sbi->nls_disk;
|
|
||||||
unsigned char nr_slots;
|
unsigned char nr_slots;
|
||||||
wchar_t bufuname[14];
|
|
||||||
wchar_t *unicode = NULL;
|
wchar_t *unicode = NULL;
|
||||||
unsigned char c, work[MSDOS_NAME];
|
unsigned char bufname[FAT_MAX_SHORT_SIZE];
|
||||||
unsigned char bufname[FAT_MAX_SHORT_SIZE], *ptname = bufname;
|
|
||||||
unsigned short opt_shortname = sbi->options.shortname;
|
|
||||||
int isvfat = sbi->options.isvfat;
|
int isvfat = sbi->options.isvfat;
|
||||||
int nocase = sbi->options.nocase;
|
|
||||||
const char *fill_name = NULL;
|
const char *fill_name = NULL;
|
||||||
unsigned long inum;
|
unsigned long inum;
|
||||||
unsigned long lpos, dummy, *furrfu = &lpos;
|
unsigned long lpos, dummy, *furrfu = &lpos;
|
||||||
loff_t cpos;
|
loff_t cpos;
|
||||||
int chi, chl, i, i2, j, last, last_u, dotoffset = 0, fill_len = 0;
|
int short_len = 0, fill_len = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
lock_super(sb);
|
lock_super(sb);
|
||||||
|
@ -556,74 +639,10 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sbi->options.dotsOK) {
|
short_len = fat_parse_short(sb, de, bufname, sbi->options.dotsOK);
|
||||||
ptname = bufname;
|
if (short_len == 0)
|
||||||
dotoffset = 0;
|
|
||||||
if (de->attr & ATTR_HIDDEN) {
|
|
||||||
*ptname++ = '.';
|
|
||||||
dotoffset = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(work, de->name, sizeof(de->name));
|
|
||||||
/* see namei.c, msdos_format_name */
|
|
||||||
if (work[0] == 0x05)
|
|
||||||
work[0] = 0xE5;
|
|
||||||
for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) {
|
|
||||||
if (!(c = work[i]))
|
|
||||||
break;
|
|
||||||
chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
|
|
||||||
&bufuname[j++], opt_shortname,
|
|
||||||
de->lcase & CASE_LOWER_BASE);
|
|
||||||
if (chl <= 1) {
|
|
||||||
ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
|
|
||||||
if (c != ' ') {
|
|
||||||
last = i;
|
|
||||||
last_u = j;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
last_u = j;
|
|
||||||
for (chi = 0; chi < chl && i < 8; chi++) {
|
|
||||||
ptname[i] = work[i];
|
|
||||||
i++; last = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i = last;
|
|
||||||
j = last_u;
|
|
||||||
fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
|
|
||||||
ptname[i++] = '.';
|
|
||||||
for (i2 = 8; i2 < MSDOS_NAME;) {
|
|
||||||
if (!(c = work[i2]))
|
|
||||||
break;
|
|
||||||
chl = fat_shortname2uni(nls_disk, &work[i2], MSDOS_NAME - i2,
|
|
||||||
&bufuname[j++], opt_shortname,
|
|
||||||
de->lcase & CASE_LOWER_EXT);
|
|
||||||
if (chl <= 1) {
|
|
||||||
i2++;
|
|
||||||
ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
|
|
||||||
if (c != ' ') {
|
|
||||||
last = i;
|
|
||||||
last_u = j;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
last_u = j;
|
|
||||||
for (chi = 0; chi < chl && i2 < MSDOS_NAME; chi++) {
|
|
||||||
ptname[i++] = work[i2++];
|
|
||||||
last = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!last)
|
|
||||||
goto record_end;
|
goto record_end;
|
||||||
|
|
||||||
i = last + dotoffset;
|
|
||||||
j = last_u;
|
|
||||||
|
|
||||||
if (isvfat) {
|
|
||||||
bufuname[j] = 0x0000;
|
|
||||||
i = fat_uni_to_x8(sb, bufuname, bufname, sizeof(bufname));
|
|
||||||
}
|
|
||||||
if (nr_slots) {
|
if (nr_slots) {
|
||||||
/* hack for fat_ioctl_filldir() */
|
/* hack for fat_ioctl_filldir() */
|
||||||
struct fat_ioctl_filldir_callback *p = dirent;
|
struct fat_ioctl_filldir_callback *p = dirent;
|
||||||
|
@ -631,12 +650,12 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
|
||||||
p->longname = fill_name;
|
p->longname = fill_name;
|
||||||
p->long_len = fill_len;
|
p->long_len = fill_len;
|
||||||
p->shortname = bufname;
|
p->shortname = bufname;
|
||||||
p->short_len = i;
|
p->short_len = short_len;
|
||||||
fill_name = NULL;
|
fill_name = NULL;
|
||||||
fill_len = 0;
|
fill_len = 0;
|
||||||
} else {
|
} else {
|
||||||
fill_name = bufname;
|
fill_name = bufname;
|
||||||
fill_len = i;
|
fill_len = short_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
start_filldir:
|
start_filldir:
|
||||||
|
|
Loading…
Reference in a new issue