[PATCH] fat: Remove duplicate directory scanning code

This patch removes duplicate directory scanning code from fs/fat/dir.c.  The
two functions that share identical code are fat_readdirx() and
fat_search_long().  This patch also renames fat_readdirx to __fat_readdir().

Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Pekka Enberg 2005-10-30 15:03:50 -08:00 committed by Linus Torvalds
parent 9131dd4256
commit ad2c1604da

View file

@ -222,6 +222,80 @@ fat_shortname2uni(struct nls_table *nls, unsigned char *buf, int buf_size,
return len; return len;
} }
enum { PARSE_INVALID = 1, PARSE_NOT_LONGNAME, PARSE_EOF, };
/**
* fat_parse_long - Parse extended directory entry.
*
* This function returns zero on success, negative value on error, or one of
* the following:
*
* %PARSE_INVALID - Directory entry is invalid.
* %PARSE_NOT_LONGNAME - Directory entry does not contain longname.
* %PARSE_EOF - Directory has no more entries.
*/
static int fat_parse_long(struct inode *dir, loff_t *pos,
struct buffer_head **bh, struct msdos_dir_entry **de,
wchar_t **unicode, unsigned char *nr_slots)
{
struct msdos_dir_slot *ds;
unsigned char id, slot, slots, alias_checksum;
if (!*unicode) {
*unicode = (wchar_t *)__get_free_page(GFP_KERNEL);
if (!*unicode) {
brelse(*bh);
return -ENOMEM;
}
}
parse_long:
slots = 0;
ds = (struct msdos_dir_slot *)*de;
id = ds->id;
if (!(id & 0x40))
return PARSE_INVALID;
slots = id & ~0x40;
if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
return PARSE_INVALID;
*nr_slots = slots;
alias_checksum = ds->alias_checksum;
slot = slots;
while (1) {
int offset;
slot--;
offset = slot * 13;
fat16_towchar(*unicode + offset, ds->name0_4, 5);
fat16_towchar(*unicode + offset + 5, ds->name5_10, 6);
fat16_towchar(*unicode + offset + 11, ds->name11_12, 2);
if (ds->id & 0x40)
(*unicode)[offset + 13] = 0;
if (fat_get_entry(dir, pos, bh, de) < 0)
return PARSE_EOF;
if (slot == 0)
break;
ds = (struct msdos_dir_slot *)*de;
if (ds->attr != ATTR_EXT)
return PARSE_NOT_LONGNAME;
if ((ds->id & ~0x40) != slot)
goto parse_long;
if (ds->alias_checksum != alias_checksum)
goto parse_long;
}
if ((*de)->name[0] == DELETED_FLAG)
return PARSE_INVALID;
if ((*de)->attr == ATTR_EXT)
goto parse_long;
if (IS_FREE((*de)->name) || ((*de)->attr & ATTR_VOLUME))
return PARSE_INVALID;
if (fat_checksum((*de)->name) != alias_checksum)
*nr_slots = 0;
return 0;
}
/* /*
* 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.
@ -259,65 +333,16 @@ parse_record:
if (de->attr != ATTR_EXT && IS_FREE(de->name)) if (de->attr != ATTR_EXT && IS_FREE(de->name))
continue; continue;
if (de->attr == ATTR_EXT) { if (de->attr == ATTR_EXT) {
struct msdos_dir_slot *ds; int status = fat_parse_long(inode, &cpos, &bh, &de,
unsigned char id; &unicode, &nr_slots);
unsigned char slot; if (status < 0)
unsigned char slots; return status;
unsigned char alias_checksum; else if (status == PARSE_INVALID)
if (!unicode) {
unicode = (wchar_t *)
__get_free_page(GFP_KERNEL);
if (!unicode) {
brelse(bh);
return -ENOMEM;
}
}
parse_long:
slots = 0;
ds = (struct msdos_dir_slot *) de;
id = ds->id;
if (!(id & 0x40))
continue; continue;
slots = id & ~0x40; else if (status == PARSE_NOT_LONGNAME)
if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */ goto parse_record;
continue; else if (status == PARSE_EOF)
nr_slots = slots; goto EODir;
alias_checksum = ds->alias_checksum;
slot = slots;
while (1) {
int offset;
slot--;
offset = slot * 13;
fat16_towchar(unicode + offset, ds->name0_4, 5);
fat16_towchar(unicode + offset + 5, ds->name5_10, 6);
fat16_towchar(unicode + offset + 11, ds->name11_12, 2);
if (ds->id & 0x40) {
unicode[offset + 13] = 0;
}
if (fat_get_entry(inode, &cpos, &bh, &de) < 0)
goto EODir;
if (slot == 0)
break;
ds = (struct msdos_dir_slot *) de;
if (ds->attr != ATTR_EXT)
goto parse_record;
if ((ds->id & ~0x40) != slot)
goto parse_long;
if (ds->alias_checksum != alias_checksum)
goto parse_long;
}
if (de->name[0] == DELETED_FLAG)
continue;
if (de->attr == ATTR_EXT)
goto parse_long;
if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))
continue;
if (fat_checksum(de->name) != alias_checksum)
nr_slots = 0;
} }
memcpy(work, de->name, sizeof(de->name)); memcpy(work, de->name, sizeof(de->name));
@ -405,8 +430,8 @@ struct fat_ioctl_filldir_callback {
int short_len; int short_len;
}; };
static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent, static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
filldir_t filldir, int short_only, int both) filldir_t filldir, int short_only, int both)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb); struct msdos_sb_info *sbi = MSDOS_SB(sb);
@ -455,9 +480,10 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,
bh = NULL; bh = NULL;
GetNew: GetNew:
long_slots = 0;
if (fat_get_entry(inode, &cpos, &bh, &de) == -1) if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
goto EODir; goto EODir;
parse_record:
long_slots = 0;
/* Check for long filename entry */ /* Check for long filename entry */
if (isvfat) { if (isvfat) {
if (de->name[0] == DELETED_FLAG) if (de->name[0] == DELETED_FLAG)
@ -472,66 +498,18 @@ GetNew:
} }
if (isvfat && de->attr == ATTR_EXT) { if (isvfat && de->attr == ATTR_EXT) {
struct msdos_dir_slot *ds; int status = fat_parse_long(inode, &cpos, &bh, &de,
unsigned char id; &unicode, &long_slots);
unsigned char slot; if (status < 0) {
unsigned char slots; filp->f_pos = cpos;
unsigned char alias_checksum; ret = status;
goto out;
if (!unicode) { } else if (status == PARSE_INVALID)
unicode = (wchar_t *)__get_free_page(GFP_KERNEL);
if (!unicode) {
filp->f_pos = cpos;
brelse(bh);
ret = -ENOMEM;
goto out;
}
}
ParseLong:
slots = 0;
ds = (struct msdos_dir_slot *) de;
id = ds->id;
if (!(id & 0x40))
goto RecEnd; goto RecEnd;
slots = id & ~0x40; else if (status == PARSE_NOT_LONGNAME)
if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */ goto parse_record;
goto RecEnd; else if (status == PARSE_EOF)
long_slots = slots; goto EODir;
alias_checksum = ds->alias_checksum;
slot = slots;
while (1) {
int offset;
slot--;
offset = slot * 13;
fat16_towchar(unicode + offset, ds->name0_4, 5);
fat16_towchar(unicode + offset + 5, ds->name5_10, 6);
fat16_towchar(unicode + offset + 11, ds->name11_12, 2);
if (ds->id & 0x40) {
unicode[offset + 13] = 0;
}
if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
goto EODir;
if (slot == 0)
break;
ds = (struct msdos_dir_slot *) de;
if (ds->attr != ATTR_EXT)
goto RecEnd; /* XXX */
if ((ds->id & ~0x40) != slot)
goto ParseLong;
if (ds->alias_checksum != alias_checksum)
goto ParseLong;
}
if (de->name[0] == DELETED_FLAG)
goto RecEnd;
if (de->attr == ATTR_EXT)
goto ParseLong;
if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))
goto RecEnd;
if (fat_checksum(de->name) != alias_checksum)
long_slots = 0;
} }
if (sbi->options.dotsOK) { if (sbi->options.dotsOK) {
@ -665,7 +643,7 @@ out:
static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir) static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
{ {
struct inode *inode = filp->f_dentry->d_inode; struct inode *inode = filp->f_dentry->d_inode;
return fat_readdirx(inode, filp, dirent, filldir, 0, 0); return __fat_readdir(inode, filp, dirent, filldir, 0, 0);
} }
static int fat_ioctl_filldir(void *__buf, const char *name, int name_len, static int fat_ioctl_filldir(void *__buf, const char *name, int name_len,
@ -754,8 +732,8 @@ static int fat_dir_ioctl(struct inode * inode, struct file * filp,
down(&inode->i_sem); down(&inode->i_sem);
ret = -ENOENT; ret = -ENOENT;
if (!IS_DEADDIR(inode)) { if (!IS_DEADDIR(inode)) {
ret = fat_readdirx(inode, filp, &buf, fat_ioctl_filldir, ret = __fat_readdir(inode, filp, &buf, fat_ioctl_filldir,
short_only, both); short_only, both);
} }
up(&inode->i_sem); up(&inode->i_sem);
if (ret >= 0) if (ret >= 0)