if (bh) brelse(bh); 
brelse(bh); 
static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,			filldir_t filldir, int short_only, int both){	struct super_block *sb = inode->i_sb;	struct msdos_sb_info *sbi = MSDOS_SB(sb);	struct buffer_head *bh;	struct msdos_dir_entry *de;	struct nls_table *nls_io = sbi->nls_io;	struct nls_table *nls_disk = sbi->nls_disk;	unsigned char long_slots;	const char *fill_name;	int fill_len;	wchar_t bufuname[14];	wchar_t *unicode = NULL;	unsigned char c, work[8], bufname[56], *ptname = bufname;	unsigned long lpos, dummy, *furrfu = &lpos;	int uni_xlate = sbi->options.unicode_xlate;	int isvfat = sbi->options.isvfat;	int utf8 = sbi->options.utf8;	int nocase = sbi->options.nocase;	unsigned short opt_shortname = sbi->options.shortname;	unsigned long inum;	int chi, chl, i, i2, j, last, last_u, dotoffset = 0;	loff_t cpos;	int ret = 0;	lock_kernel();	cpos = filp->f_pos;	/* Fake . and .. for the root directory. */	if (inode->i_ino == MSDOS_ROOT_INO) {		while (cpos < 2) {			if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO, DT_DIR) < 0)				goto out;			cpos++;			filp->f_pos++;		}		if (cpos == 2) {			dummy = 2;			furrfu = &dummy;			cpos = 0;		}	}	if (cpos & (sizeof(struct msdos_dir_entry)-1)) {		ret = -ENOENT;		goto out;	}	bh = NULL;GetNew:	long_slots = 0;	if (fat_get_entry(inode, &cpos, &bh, &de) == -1)		goto EODir;	/* Check for long filename entry */	if (isvfat) {		if (de->name[0] == DELETED_FLAG)			goto RecEnd;		if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))			goto RecEnd;		if (de->attr != ATTR_EXT && IS_FREE(de->name))			goto RecEnd;	} else {		if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name))			goto RecEnd;	}	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;		}		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;		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;	}	if (sbi->options.dotsOK) {		ptname = bufname;		dotoffset = 0;		if (de->attr & ATTR_HIDDEN) {			*ptname++ = '.';			dotoffset = 1;		}	}	memcpy(work, de->name, sizeof(de->name));	/* see namei.c, msdos_format_name */	if (work[0] == 0x05)		work[0] = 0xE5;	for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) {		if (!(c = work[i])) break;		chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,					&bufuname[j++], opt_shortname,					de->lcase & CASE_LOWER_BASE);		if (chl <= 1) {			ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;			if (c != ' ') {				last = i;				last_u = j;			}		} else {			last_u = j;			for (chi = 0; chi < chl && i < 8; chi++) {				ptname[i] = work[i];				i++; last = i;			}		}	}	i = last;	j = last_u;	fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);	ptname[i++] = '.';	for (i2 = 0; i2 < 3;) {		if (!(c = de->ext[i2])) break;		chl = fat_shortname2uni(nls_disk, &de->ext[i2], 3 - i2,					&bufuname[j++], opt_shortname,					de->lcase & CASE_LOWER_EXT);		if (chl <= 1) {			i2++;			ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;			if (c != ' ') {				last = i;				last_u = j;			}		} else {			last_u = j;			for (chi = 0; chi < chl && i2 < 3; chi++) {				ptname[i++] = de->ext[i2++];				last = i;			}		}	}	if (!last)		goto RecEnd;	i = last + dotoffset;	j = last_u;	lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry);	if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME))		inum = inode->i_ino;	else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {		inum = parent_ino(filp->f_dentry);	} else {		loff_t i_pos = fat_make_i_pos(sb, bh, de);		struct inode *tmp = fat_iget(sb, i_pos);		if (tmp) {			inum = tmp->i_ino;			iput(tmp);		} else			inum = iunique(sb, MSDOS_ROOT_INO);	}	if (isvfat) {		bufuname[j] = 0x0000;		i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname))			 : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);	}	fill_name = bufname;	fill_len = i;	if (!short_only && long_slots) {		/* convert the unicode long name. 261 is maximum size		 * of unicode buffer. (13 * slots + nul) */		void *longname = unicode + 261;		int buf_size = PAGE_SIZE - (261 * sizeof(unicode[0]));		int long_len = utf8			? utf8_wcstombs(longname, unicode, buf_size)			: uni16_to_x8(longname, unicode, uni_xlate, nls_io);		if (!both) {			fill_name = longname;			fill_len = long_len;		} else {			/* hack for fat_ioctl_filldir() */			struct fat_ioctl_filldir_callback *p = dirent;			p->longname = longname;			p->long_len = long_len;			p->shortname = bufname;			p->short_len = i;			fill_name = NULL;			fill_len = 0;		}	}	if (filldir(dirent, fill_name, fill_len, *furrfu, inum,		    (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)		goto FillFailed;RecEnd:	furrfu = &lpos;	filp->f_pos = cpos;	goto GetNew;EODir:	filp->f_pos = cpos;FillFailed:	if (bh)		brelse(bh);	if (unicode)		free_page((unsigned long)unicode);out:	unlock_kernel();	return ret;}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/f3ef6f63e5c575c136b39bb423a6e9a002932da7/dir.c/buggy/fs/fat/dir.c