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

📄 namei_vfat.c

📁 linux环境下基于FAT的文件系统的通用代码
💻 C
📖 第 1 页 / 共 2 页
字号:
					ip += charlen;					i += charlen;					op += 2;				}			}			if (i < len)				return -ENAMETOOLONG;		} else {			for (i = 0, ip = name, op = outname, *outlen = 0;			     i < len && *outlen <= 255;			     i++, *outlen += 1)			{				*op++ = *ip++;				*op++ = 0;			}			if (i < len)				return -ENAMETOOLONG;		}	}	*longlen = *outlen;	if (*outlen % 13) {		*op++ = 0;		*op++ = 0;		*outlen += 1;		if (*outlen % 13) {			fill = 13 - (*outlen % 13);			for (i = 0; i < fill; i++) {				*op++ = 0xff;				*op++ = 0xff;			}			*outlen += fill;		}	}	return 0;}static int vfat_build_slots(struct inode *dir, const unsigned char *name,			    int len, int is_dir, int cluster,			    struct timespec *ts,			    struct msdos_dir_slot *slots, int *nr_slots){	struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);	struct fat_mount_options *opts = &sbi->options;	struct msdos_dir_slot *ps;	struct msdos_dir_entry *de;	unsigned char cksum, lcase;	unsigned char msdos_name[MSDOS_NAME];	wchar_t *uname;	__le16 time, date;	u8 time_cs;	int err, ulen, usize, i;	loff_t offset;	*nr_slots = 0;	uname = __getname();	if (!uname)		return -ENOMEM;	err = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize,			   opts->unicode_xlate, opts->utf8, sbi->nls_io);	if (err)		goto out_free;	err = vfat_is_used_badchars(uname, ulen);	if (err)		goto out_free;	err = vfat_create_shortname(dir, sbi->nls_disk, uname, ulen,				    msdos_name, &lcase);	if (err < 0)		goto out_free;	else if (err == 1) {		de = (struct msdos_dir_entry *)slots;		err = 0;		goto shortname;	}	/* build the entry of long file name */	cksum = fat_checksum(msdos_name);	*nr_slots = usize / 13;	for (ps = slots, i = *nr_slots; i > 0; i--, ps++) {		ps->id = i;		ps->attr = ATTR_EXT;		ps->reserved = 0;		ps->alias_checksum = cksum;		ps->start = 0;		offset = (i - 1) * 13;		fatwchar_to16(ps->name0_4, uname + offset, 5);		fatwchar_to16(ps->name5_10, uname + offset + 5, 6);		fatwchar_to16(ps->name11_12, uname + offset + 11, 2);	}	slots[0].id |= 0x40;	de = (struct msdos_dir_entry *)ps;shortname:	/* build the entry of 8.3 alias name */	(*nr_slots)++;	memcpy(de->name, msdos_name, MSDOS_NAME);	de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;	de->lcase = lcase;	fat_time_unix2fat(sbi, ts, &time, &date, &time_cs);	de->time = de->ctime = time;	de->date = de->cdate = de->adate = date;	de->ctime_cs = time_cs;	de->start = cpu_to_le16(cluster);	de->starthi = cpu_to_le16(cluster >> 16);	de->size = 0;out_free:	__putname(uname);	return err;}static int vfat_add_entry(struct inode *dir, struct qstr *qname, int is_dir,			  int cluster, struct timespec *ts,			  struct fat_slot_info *sinfo){	struct msdos_dir_slot *slots;	unsigned int len;	int err, nr_slots;	len = vfat_striptail_len(qname);	if (len == 0)		return -ENOENT;	slots = kmalloc(sizeof(*slots) * MSDOS_SLOTS, GFP_NOFS);	if (slots == NULL)		return -ENOMEM;	err = vfat_build_slots(dir, qname->name, len, is_dir, cluster, ts,			       slots, &nr_slots);	if (err)		goto cleanup;	err = fat_add_entries(dir, slots, nr_slots, sinfo);	if (err)		goto cleanup;	/* update timestamp */	dir->i_ctime = dir->i_mtime = dir->i_atime = *ts;	if (IS_DIRSYNC(dir))		(void)fat_sync_inode(dir);	else		mark_inode_dirty(dir);cleanup:	kfree(slots);	return err;}static int vfat_find(struct inode *dir, struct qstr *qname,		     struct fat_slot_info *sinfo){	unsigned int len = vfat_striptail_len(qname);	if (len == 0)		return -ENOENT;	return fat_search_long(dir, qname->name, len, sinfo);}static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,				  struct nameidata *nd){	struct super_block *sb = dir->i_sb;	struct fat_slot_info sinfo;	struct inode *inode;	struct dentry *alias;	int err;	lock_super(sb);	err = vfat_find(dir, &dentry->d_name, &sinfo);	if (err) {		if (err == -ENOENT) {			inode = NULL;			goto out;		}		goto error;	}	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);	brelse(sinfo.bh);	if (IS_ERR(inode)) {		err = PTR_ERR(inode);		goto error;	}	alias = d_find_alias(inode);	if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {		/*		 * This inode has non DCACHE_DISCONNECTED dentry. This		 * means, the user did ->lookup() by an another name		 * (longname vs 8.3 alias of it) in past.		 *		 * Switch to new one for reason of locality if possible.		 */		BUG_ON(d_unhashed(alias));		if (!S_ISDIR(inode->i_mode))			d_move(alias, dentry);		iput(inode);		unlock_super(sb);		return alias;	}out:	unlock_super(sb);	dentry->d_op = sb->s_root->d_op;	dentry->d_time = dentry->d_parent->d_inode->i_version;	dentry = d_splice_alias(inode, dentry);	if (dentry) {		dentry->d_op = sb->s_root->d_op;		dentry->d_time = dentry->d_parent->d_inode->i_version;	}	return dentry;error:	unlock_super(sb);	return ERR_PTR(err);}static int vfat_create(struct inode *dir, struct dentry *dentry, int mode,		       struct nameidata *nd){	struct super_block *sb = dir->i_sb;	struct inode *inode;	struct fat_slot_info sinfo;	struct timespec ts;	int err;	lock_super(sb);	ts = CURRENT_TIME_SEC;	err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo);	if (err)		goto out;	dir->i_version++;	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);	brelse(sinfo.bh);	if (IS_ERR(inode)) {		err = PTR_ERR(inode);		goto out;	}	inode->i_version++;	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;	/* timestamp is already written, so mark_inode_dirty() is unneeded. */	dentry->d_time = dentry->d_parent->d_inode->i_version;	d_instantiate(dentry, inode);out:	unlock_super(sb);	return err;}static int vfat_rmdir(struct inode *dir, struct dentry *dentry){	struct inode *inode = dentry->d_inode;	struct super_block *sb = dir->i_sb;	struct fat_slot_info sinfo;	int err;	lock_super(sb);	err = fat_dir_empty(inode);	if (err)		goto out;	err = vfat_find(dir, &dentry->d_name, &sinfo);	if (err)		goto out;	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */	if (err)		goto out;	drop_nlink(dir);	clear_nlink(inode);	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;	fat_detach(inode);out:	unlock_super(sb);	return err;}static int vfat_unlink(struct inode *dir, struct dentry *dentry){	struct inode *inode = dentry->d_inode;	struct super_block *sb = dir->i_sb;	struct fat_slot_info sinfo;	int err;	lock_super(sb);	err = vfat_find(dir, &dentry->d_name, &sinfo);	if (err)		goto out;	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */	if (err)		goto out;	clear_nlink(inode);	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;	fat_detach(inode);out:	unlock_super(sb);	return err;}static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode){	struct super_block *sb = dir->i_sb;	struct inode *inode;	struct fat_slot_info sinfo;	struct timespec ts;	int err, cluster;	lock_super(sb);	ts = CURRENT_TIME_SEC;	cluster = fat_alloc_new_dir(dir, &ts);	if (cluster < 0) {		err = cluster;		goto out;	}	err = vfat_add_entry(dir, &dentry->d_name, 1, cluster, &ts, &sinfo);	if (err)		goto out_free;	dir->i_version++;	inc_nlink(dir);	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);	brelse(sinfo.bh);	if (IS_ERR(inode)) {		err = PTR_ERR(inode);		/* the directory was completed, just return a error */		goto out;	}	inode->i_version++;	inode->i_nlink = 2;	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;	/* timestamp is already written, so mark_inode_dirty() is unneeded. */	dentry->d_time = dentry->d_parent->d_inode->i_version;	d_instantiate(dentry, inode);	unlock_super(sb);	return 0;out_free:	fat_free_clusters(dir, cluster);out:	unlock_super(sb);	return err;}static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,		       struct inode *new_dir, struct dentry *new_dentry){	struct buffer_head *dotdot_bh;	struct msdos_dir_entry *dotdot_de;	struct inode *old_inode, *new_inode;	struct fat_slot_info old_sinfo, sinfo;	struct timespec ts;	loff_t dotdot_i_pos, new_i_pos;	int err, is_dir, update_dotdot, corrupt = 0;	struct super_block *sb = old_dir->i_sb;	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;	old_inode = old_dentry->d_inode;	new_inode = new_dentry->d_inode;	lock_super(sb);	err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);	if (err)		goto out;	is_dir = S_ISDIR(old_inode->i_mode);	update_dotdot = (is_dir && old_dir != new_dir);	if (update_dotdot) {		if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,					 &dotdot_i_pos) < 0) {			err = -EIO;			goto out;		}	}	ts = CURRENT_TIME_SEC;	if (new_inode) {		if (is_dir) {			err = fat_dir_empty(new_inode);			if (err)				goto out;		}		new_i_pos = MSDOS_I(new_inode)->i_pos;		fat_detach(new_inode);	} else {		err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, 0,				     &ts, &sinfo);		if (err)			goto out;		new_i_pos = sinfo.i_pos;	}	new_dir->i_version++;	fat_detach(old_inode);	fat_attach(old_inode, new_i_pos);	if (IS_DIRSYNC(new_dir)) {		err = fat_sync_inode(old_inode);		if (err)			goto error_inode;	} else		mark_inode_dirty(old_inode);	if (update_dotdot) {		int start = MSDOS_I(new_dir)->i_logstart;		dotdot_de->start = cpu_to_le16(start);		dotdot_de->starthi = cpu_to_le16(start >> 16);		mark_buffer_dirty(dotdot_bh);		if (IS_DIRSYNC(new_dir)) {			err = sync_dirty_buffer(dotdot_bh);			if (err)				goto error_dotdot;		}		drop_nlink(old_dir);		if (!new_inode) 			inc_nlink(new_dir);	}	err = fat_remove_entries(old_dir, &old_sinfo);	/* and releases bh */	old_sinfo.bh = NULL;	if (err)		goto error_dotdot;	old_dir->i_version++;	old_dir->i_ctime = old_dir->i_mtime = ts;	if (IS_DIRSYNC(old_dir))		(void)fat_sync_inode(old_dir);	else		mark_inode_dirty(old_dir);	if (new_inode) {		drop_nlink(new_inode);		if (is_dir)			drop_nlink(new_inode);		new_inode->i_ctime = ts;	}out:	brelse(sinfo.bh);	brelse(dotdot_bh);	brelse(old_sinfo.bh);	unlock_super(sb);	return err;error_dotdot:	/* data cluster is shared, serious corruption */	corrupt = 1;	if (update_dotdot) {		int start = MSDOS_I(old_dir)->i_logstart;		dotdot_de->start = cpu_to_le16(start);		dotdot_de->starthi = cpu_to_le16(start >> 16);		mark_buffer_dirty(dotdot_bh);		corrupt |= sync_dirty_buffer(dotdot_bh);	}error_inode:	fat_detach(old_inode);	fat_attach(old_inode, old_sinfo.i_pos);	if (new_inode) {		fat_attach(new_inode, new_i_pos);		if (corrupt)			corrupt |= fat_sync_inode(new_inode);	} else {		/*		 * If new entry was not sharing the data cluster, it		 * shouldn't be serious corruption.		 */		int err2 = fat_remove_entries(new_dir, &sinfo);		if (corrupt)			corrupt |= err2;		sinfo.bh = NULL;	}	if (corrupt < 0) {		fat_fs_panic(new_dir->i_sb,			     "%s: Filesystem corrupted (i_pos %lld)",			     __func__, sinfo.i_pos);	}	goto out;}static const struct inode_operations vfat_dir_inode_operations = {	.create		= vfat_create,	.lookup		= vfat_lookup,	.unlink		= vfat_unlink,	.mkdir		= vfat_mkdir,	.rmdir		= vfat_rmdir,	.rename		= vfat_rename,	.setattr	= fat_setattr,	.getattr	= fat_getattr,};static int vfat_fill_super(struct super_block *sb, void *data, int silent){	int res;	res = fat_fill_super(sb, data, silent, &vfat_dir_inode_operations, 1);	if (res)		return res;	if (MSDOS_SB(sb)->options.name_check != 's')		sb->s_root->d_op = &vfat_ci_dentry_ops;	else		sb->s_root->d_op = &vfat_dentry_ops;	return 0;}static int vfat_get_sb(struct file_system_type *fs_type,		       int flags, const char *dev_name,		       void *data, struct vfsmount *mnt){	return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super,			   mnt);}static struct file_system_type vfat_fs_type = {	.owner		= THIS_MODULE,	.name		= "vfat",	.get_sb		= vfat_get_sb,	.kill_sb	= kill_block_super,	.fs_flags	= FS_REQUIRES_DEV,};static int __init init_vfat_fs(void){	return register_filesystem(&vfat_fs_type);}static void __exit exit_vfat_fs(void){	unregister_filesystem(&vfat_fs_type);}MODULE_LICENSE("GPL");MODULE_DESCRIPTION("VFAT filesystem support");MODULE_AUTHOR("Gordon Chaffee");module_init(init_vfat_fs)module_exit(exit_vfat_fs)

⌨️ 快捷键说明

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