[PATCH] fat: Remove duplicate directory scanning code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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]
  Powered by Linux