⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dir.c

📁 linux环境下基于FAT的文件系统的通用代码
💻 C
📖 第 1 页 / 共 3 页
字号:
EXPORT_SYMBOL_GPL(fat_search_long);struct fat_ioctl_filldir_callback {	void __user *dirent;	int result;	/* for dir ioctl */	const char *longname;	int long_len;	const char *shortname;	int short_len;};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;	struct msdos_sb_info *sbi = MSDOS_SB(sb);	struct buffer_head *bh;	struct msdos_dir_entry *de;	struct nls_table *nls_disk = sbi->nls_disk;	unsigned char nr_slots;	wchar_t bufuname[14];	wchar_t *unicode = NULL;	unsigned char c, work[MSDOS_NAME];	unsigned char bufname[FAT_MAX_SHORT_SIZE], *ptname = bufname;	unsigned short opt_shortname = sbi->options.shortname;	int isvfat = sbi->options.isvfat;	int nocase = sbi->options.nocase;	const char *fill_name = NULL;	unsigned long inum;	unsigned long lpos, dummy, *furrfu = &lpos;	loff_t cpos;	int chi, chl, i, i2, j, last, last_u, dotoffset = 0, fill_len = 0;	int ret = 0;	lock_super(sb);	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;get_new:	if (fat_get_entry(inode, &cpos, &bh, &de) == -1)		goto end_of_dir;parse_record:	nr_slots = 0;	/*	 * Check for long filename entry, but if short_only, we don't	 * need to parse long filename.	 */	if (isvfat && !short_only) {		if (de->name[0] == DELETED_FLAG)			goto record_end;		if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))			goto record_end;		if (de->attr != ATTR_EXT && IS_FREE(de->name))			goto record_end;	} else {		if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name))			goto record_end;	}	if (isvfat && de->attr == ATTR_EXT) {		int status = fat_parse_long(inode, &cpos, &bh, &de,					    &unicode, &nr_slots);		if (status < 0) {			filp->f_pos = cpos;			ret = status;			goto out;		} else if (status == PARSE_INVALID)			goto record_end;		else if (status == PARSE_NOT_LONGNAME)			goto parse_record;		else if (status == PARSE_EOF)			goto end_of_dir;		if (nr_slots) {			void *longname = unicode + FAT_MAX_UNI_CHARS;			int size = PATH_MAX - FAT_MAX_UNI_SIZE;			int len = fat_uni_to_x8(sbi, unicode, longname, size);			fill_name = longname;			fill_len = len;			/* !both && !short_only, so we don't need shortname. */			if (!both)				goto start_filldir;		}	}	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 = 8; i2 < MSDOS_NAME;) {		if (!(c = work[i2]))			break;		chl = fat_shortname2uni(nls_disk, &work[i2], MSDOS_NAME - 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 < MSDOS_NAME; chi++) {				ptname[i++] = work[i2++];				last = i;			}		}	}	if (!last)		goto record_end;	i = last + dotoffset;	j = last_u;	if (isvfat) {		bufuname[j] = 0x0000;		i = fat_uni_to_x8(sbi, bufuname, bufname, sizeof(bufname));	}	if (nr_slots) {		/* hack for fat_ioctl_filldir() */		struct fat_ioctl_filldir_callback *p = dirent;		p->longname = fill_name;		p->long_len = fill_len;		p->shortname = bufname;		p->short_len = i;		fill_name = NULL;		fill_len = 0;	} else {		fill_name = bufname;		fill_len = i;	}start_filldir:	lpos = cpos - (nr_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_path.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 (filldir(dirent, fill_name, fill_len, *furrfu, inum,		    (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)		goto fill_failed;record_end:	furrfu = &lpos;	filp->f_pos = cpos;	goto get_new;end_of_dir:	filp->f_pos = cpos;fill_failed:	brelse(bh);	if (unicode)		__putname(unicode);out:	unlock_super(sb);	return ret;}static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir){	struct inode *inode = filp->f_path.dentry->d_inode;	return __fat_readdir(inode, filp, dirent, filldir, 0, 0);}#define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type)			   \static int func(void *__buf, const char *name, int name_len,		   \			     loff_t offset, u64 ino, unsigned int d_type)  \{									   \	struct fat_ioctl_filldir_callback *buf = __buf;			   \	struct dirent_type __user *d1 = buf->dirent;			   \	struct dirent_type __user *d2 = d1 + 1;				   \									   \	if (buf->result)						   \		return -EINVAL;						   \	buf->result++;							   \									   \	if (name != NULL) {						   \		/* dirent has only short name */			   \		if (name_len >= sizeof(d1->d_name))			   \			name_len = sizeof(d1->d_name) - 1;		   \									   \		if (put_user(0, d2->d_name)			||	   \		    put_user(0, &d2->d_reclen)			||	   \		    copy_to_user(d1->d_name, name, name_len)	||	   \		    put_user(0, d1->d_name + name_len)		||	   \		    put_user(name_len, &d1->d_reclen))			   \			goto efault;					   \	} else {							   \		/* dirent has short and long name */			   \		const char *longname = buf->longname;			   \		int long_len = buf->long_len;				   \		const char *shortname = buf->shortname;			   \		int short_len = buf->short_len;				   \									   \		if (long_len >= sizeof(d1->d_name))			   \			long_len = sizeof(d1->d_name) - 1;		   \		if (short_len >= sizeof(d1->d_name))			   \			short_len = sizeof(d1->d_name) - 1;		   \									   \		if (copy_to_user(d2->d_name, longname, long_len)	|| \		    put_user(0, d2->d_name + long_len)			|| \		    put_user(long_len, &d2->d_reclen)			|| \		    put_user(ino, &d2->d_ino)				|| \		    put_user(offset, &d2->d_off)			|| \		    copy_to_user(d1->d_name, shortname, short_len)	|| \		    put_user(0, d1->d_name + short_len)			|| \		    put_user(short_len, &d1->d_reclen))			   \			goto efault;					   \	}								   \	return 0;							   \efault:									   \	buf->result = -EFAULT;						   \	return -EFAULT;							   \}FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, __fat_dirent)static int fat_ioctl_readdir(struct inode *inode, struct file *filp,			     void __user *dirent, filldir_t filldir,			     int short_only, int both){	struct fat_ioctl_filldir_callback buf;	int ret;	buf.dirent = dirent;	buf.result = 0;	mutex_lock(&inode->i_mutex);	ret = -ENOENT;	if (!IS_DEADDIR(inode)) {		ret = __fat_readdir(inode, filp, &buf, filldir,				    short_only, both);	}	mutex_unlock(&inode->i_mutex);	if (ret >= 0)		ret = buf.result;	return ret;}static int fat_dir_ioctl(struct inode *inode, struct file *filp,			 unsigned int cmd, unsigned long arg){	struct __fat_dirent __user *d1 = (struct __fat_dirent __user *)arg;	int short_only, both;	switch (cmd) {	case VFAT_IOCTL_READDIR_SHORT:		short_only = 1;		both = 0;		break;	case VFAT_IOCTL_READDIR_BOTH:		short_only = 0;		both = 1;		break;	default:		return fat_generic_ioctl(inode, filp, cmd, arg);	}	if (!access_ok(VERIFY_WRITE, d1, sizeof(struct __fat_dirent[2])))		return -EFAULT;	/*	 * Yes, we don't need this put_user() absolutely. However old	 * code didn't return the right value. So, app use this value,	 * in order to check whether it is EOF.	 */	if (put_user(0, &d1->d_reclen))		return -EFAULT;	return fat_ioctl_readdir(inode, filp, d1, fat_ioctl_filldir,				 short_only, both);}#ifdef CONFIG_COMPAT#define	VFAT_IOCTL_READDIR_BOTH32	_IOR('r', 1, struct compat_dirent[2])#define	VFAT_IOCTL_READDIR_SHORT32	_IOR('r', 2, struct compat_dirent[2])FAT_IOCTL_FILLDIR_FUNC(fat_compat_ioctl_filldir, compat_dirent)static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd,				 unsigned long arg){	struct inode *inode = filp->f_path.dentry->d_inode;	struct compat_dirent __user *d1 = compat_ptr(arg);	int short_only, both;	switch (cmd) {	case VFAT_IOCTL_READDIR_SHORT32:		short_only = 1;		both = 0;		break;	case VFAT_IOCTL_READDIR_BOTH32:		short_only = 0;		both = 1;		break;	default:		return -ENOIOCTLCMD;	}	if (!access_ok(VERIFY_WRITE, d1, sizeof(struct compat_dirent[2])))		return -EFAULT;	/*	 * Yes, we don't need this put_user() absolutely. However old	 * code didn't return the right value. So, app use this value,	 * in order to check whether it is EOF.	 */	if (put_user(0, &d1->d_reclen))		return -EFAULT;	return fat_ioctl_readdir(inode, filp, d1, fat_compat_ioctl_filldir,				 short_only, both);}#endif /* CONFIG_COMPAT */const struct file_operations fat_dir_operations = {	.llseek		= generic_file_llseek,	.read		= generic_read_dir,	.readdir	= fat_readdir,	.ioctl		= fat_dir_ioctl,#ifdef CONFIG_COMPAT	.compat_ioctl	= fat_compat_dir_ioctl,#endif	.fsync		= file_fsync,};static int fat_get_short_entry(struct inode *dir, loff_t *pos,			       struct buffer_head **bh,			       struct msdos_dir_entry **de){	while (fat_get_entry(dir, pos, bh, de) >= 0) {		/* free entry or long name entry or volume label */		if (!IS_FREE((*de)->name) && !((*de)->attr & ATTR_VOLUME))			return 0;	}	return -ENOENT;}/* * The ".." entry can not provide the "struct fat_slot_info" informations * for inode. So, this function provide the some informations only. */int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,			 struct msdos_dir_entry **de, loff_t *i_pos){	loff_t offset;	offset = 0;	*bh = NULL;	while (fat_get_short_entry(dir, &offset, bh, de) >= 0) {		if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME)) {			*i_pos = fat_make_i_pos(dir->i_sb, *bh, *de);			return 0;		}	}	return -ENOENT;}EXPORT_SYMBOL_GPL(fat_get_dotdot_entry);/* See if directory is empty */int fat_dir_empty(struct inode *dir){	struct buffer_head *bh;	struct msdos_dir_entry *de;	loff_t cpos;	int result = 0;	bh = NULL;	cpos = 0;	while (fat_get_short_entry(dir, &cpos, &bh, &de) >= 0) {		if (strncmp(de->name, MSDOS_DOT   , MSDOS_NAME) &&		    strncmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {			result = -ENOTEMPTY;			break;		}	}	brelse(bh);	return result;}EXPORT_SYMBOL_GPL(fat_dir_empty);/* * fat_subdirs counts the number of sub-directories of dir. It can be run * on directories being created. */int fat_subdirs(struct inode *dir){	struct buffer_head *bh;	struct msdos_dir_entry *de;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -