Hi!
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().
Tested on User-mode Linux with a small 16 MB vfat partition.
Signed-off-by: Pekka Enberg <[email protected]>
---
dir.c | 239 +++++++++++++++++++++++++++++++-----------------------------------
1 file changed, 113 insertions(+), 126 deletions(-)
Index: 2.6/fs/fat/dir.c
===================================================================
--- 2.6.orig/fs/fat/dir.c
+++ 2.6/fs/fat/dir.c
@@ -197,6 +197,95 @@ fat_shortname2uni(struct nls_table *nls,
return len;
}
+enum {
+ DIRENT_END = 0x01,
+ NOT_EXTENDED = 0x02,
+ DIR_END = 0x03
+};
+
+/**
+ * fat_parse_extended - Parse extended directory entry.
+ *
+ * This function returns zero on success, negative value on error, or one of
+ * the following:
+ *
+ * %DIRENT_END - Directory entry ended unexpectedly.
+ * %NOT_EXTENDED - Directory entry does not contain extended attributes.
+ * %DIR_END - Directory has no more entries.
+ */
+static int fat_parse_extended(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;
+ unsigned char slot;
+ unsigned char slots;
+ unsigned char sum;
+ unsigned char alias_checksum;
+ int i;
+
+ 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 DIRENT_END;
+ slots = id & ~0x40;
+ if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
+ return DIRENT_END;
+ *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 DIR_END;
+ if (slot == 0)
+ break;
+ ds = (struct msdos_dir_slot *) *de;
+ if (ds->attr != ATTR_EXT)
+ return NOT_EXTENDED;
+ if ((ds->id & ~0x40) != slot)
+ goto parse_long;
+ if (ds->alias_checksum != alias_checksum)
+ goto parse_long;
+ }
+ if ((*de)->name[0] == DELETED_FLAG)
+ return DIRENT_END;
+ if ((*de)->attr == ATTR_EXT)
+ goto parse_long;
+ if (IS_FREE((*de)->name) || ((*de)->attr & ATTR_VOLUME))
+ return DIRENT_END;
+ for (sum = 0, i = 0; i < 11; i++)
+ sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + (*de)->name[i];
+ if (sum != alias_checksum)
+ *nr_slots = 0;
+
+ return 0;
+}
+
/*
* Return values: negative -> error, 0 -> not found, positive -> found,
* value is the total amount of slots, including the shortname entry.
@@ -234,68 +323,16 @@ parse_record:
if (de->attr != ATTR_EXT && IS_FREE(de->name))
continue;
if (de->attr == ATTR_EXT) {
- struct msdos_dir_slot *ds;
- unsigned char id;
- unsigned char slot;
- unsigned char slots;
- unsigned char sum;
- unsigned char 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))
- continue;
- slots = id & ~0x40;
- if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
+ int status = fat_parse_extended(inode, &cpos, &bh, &de,
+ &unicode, &nr_slots);
+ if (status < 0)
+ return status;
+ else if (status == DIRENT_END)
continue;
- 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(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;
- for (sum = 0, i = 0; i < 11; i++)
- sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
- if (sum != alias_checksum)
- nr_slots = 0;
+ else if (status == NOT_EXTENDED)
+ goto parse_record;
+ else if (status == DIR_END)
+ goto EODir;
}
memcpy(work, de->name, sizeof(de->name));
@@ -383,7 +420,7 @@ struct fat_ioctl_filldir_callback {
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)
{
struct super_block *sb = inode->i_sb;
@@ -450,69 +487,19 @@ GetNew:
}
if (isvfat && de->attr == ATTR_EXT) {
- struct msdos_dir_slot *ds;
- unsigned char id;
- unsigned char slot;
- unsigned char slots;
- unsigned char sum;
- unsigned char alias_checksum;
-
- if (!unicode) {
- 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;
- slots = id & ~0x40;
- if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
- goto RecEnd;
- long_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(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;
+ int status = fat_parse_extended(inode, &cpos, &bh, &de,
+ &unicode, &long_slots);
+ if (status < 0) {
+ filp->f_pos = cpos;
+ ret = status;
+ goto out;
}
- if (de->name[0] == DELETED_FLAG)
+ else if (status == DIRENT_END)
goto RecEnd;
- if (de->attr == ATTR_EXT)
- goto ParseLong;
- if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))
- goto RecEnd;
- for (sum = 0, i = 0; i < 11; i++)
- sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
- if (sum != alias_checksum)
- long_slots = 0;
+ else if (status == NOT_EXTENDED)
+ goto RecEnd; /* XXX: Retry? */
+ else if (status == DIR_END)
+ goto EODir;
}
if (sbi->options.dotsOK) {
@@ -647,7 +634,7 @@ out:
static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
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,
@@ -736,8 +723,8 @@ static int fat_dir_ioctl(struct inode *
down(&inode->i_sem);
ret = -ENOENT;
if (!IS_DEADDIR(inode)) {
- ret = fat_readdirx(inode, filp, &buf, fat_ioctl_filldir,
- short_only, both);
+ ret = __fat_readdir(inode, filp, &buf, fat_ioctl_filldir,
+ short_only, both);
}
up(&inode->i_sem);
if (ret >= 0)
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
|
|