Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad2c1604 authored by Pekka Enberg's avatar Pekka Enberg Committed by Linus Torvalds
Browse files

[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: default avatarPekka Enberg <penberg@cs.helsinki.fi>
Signed-off-by: default avatarOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 9131dd42
Loading
Loading
Loading
Loading
+101 −123
Original line number Diff line number Diff line
@@ -222,6 +222,80 @@ fat_shortname2uni(struct nls_table *nls, unsigned char *buf, int buf_size,
	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,
 * value is the total amount of slots, including the shortname entry.
@@ -259,65 +333,16 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
		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 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))
			int status = fat_parse_long(inode, &cpos, &bh, &de,
						    &unicode, &nr_slots);
			if (status < 0)
				return status;
			else if (status == PARSE_INVALID)
				continue;
			slots = id & ~0x40;
			if (slots > 20 || !slots)	/* ceil(256 * 2 / 26) */
				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)
			else if (status == PARSE_NOT_LONGNAME)
				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;
			else if (status == PARSE_EOF)
				goto EODir;
		}

		memcpy(work, de->name, sizeof(de->name));
@@ -405,7 +430,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;
@@ -455,9 +480,10 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,

	bh = NULL;
GetNew:
	long_slots = 0;
	if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
		goto EODir;
parse_record:
	long_slots = 0;
	/* Check for long filename entry */
	if (isvfat) {
		if (de->name[0] == DELETED_FLAG)
@@ -472,66 +498,18 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,
	}

	if (isvfat && de->attr == ATTR_EXT) {
		struct msdos_dir_slot *ds;
		unsigned char id;
		unsigned char slot;
		unsigned char slots;
		unsigned char alias_checksum;

		if (!unicode) {
			unicode = (wchar_t *)__get_free_page(GFP_KERNEL);
			if (!unicode) {
		int status = fat_parse_long(inode, &cpos, &bh, &de,
					    &unicode, &long_slots);
		if (status < 0) {
			filp->f_pos = cpos;
				brelse(bh);
				ret = -ENOMEM;
			ret = status;
			goto out;
			}
		}
ParseLong:
		slots = 0;
		ds = (struct msdos_dir_slot *) de;
		id = ds->id;
		if (!(id & 0x40))
		} else if (status == PARSE_INVALID)
			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)
		else if (status == PARSE_NOT_LONGNAME)
			goto parse_record;
		else if (status == PARSE_EOF)
			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) {
@@ -665,7 +643,7 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,
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,
@@ -754,7 +732,7 @@ static int fat_dir_ioctl(struct inode * inode, struct file * filp,
	down(&inode->i_sem);
	ret = -ENOENT;
	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);
	}
	up(&inode->i_sem);