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/

Reply via email to