namei.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,292 行 · 第 1/2 页

C
1,292
字号
	int i;	const unsigned char *ip;	char *op;	int fill;	unsigned char c1, c2, c3;	if (utf8) {		*outlen = utf8_mbstowcs((__u16 *) outname, name, PAGE_SIZE);		if (name[len-1] == '.')			*outlen-=2;		op = &outname[*outlen * sizeof(__u16)];	} else {		if (name[len-1] == '.') 			len--;		op = outname;		if (nls) {			for (i = 0, ip = name, op = outname, *outlen = 0;			     i < len && *outlen <= 260; i++, *outlen += 1)			{				if (escape && (*ip == ':')) {					if (i > len - 4) return -EINVAL;					c1 = fat_esc2uni[ip[1]];					c2 = fat_esc2uni[ip[2]];					c3 = fat_esc2uni[ip[3]];					if (c1 == 255 || c2 == 255 || c3 == 255)						return -EINVAL;					*op++ = (c1 << 4) + (c2 >> 2);					*op++ = ((c2 & 0x3) << 6) + c3;					ip += 4;				} else {					*op++ = nls->charset2uni[*ip].uni1;					*op++ = nls->charset2uni[*ip].uni2;					ip++;				}			}		} else {			for (i = 0, ip = name, op = outname, *outlen = 0;			     i < len && *outlen <= 260; i++, *outlen += 1)			{				*op++ = *ip++;				*op++ = 0;			}		}	}	if (*outlen > 260)		return -ENAMETOOLONG;	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 intvfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len,		     char *msdos_name, int *slots,		     int uni_xlate, int utf8, struct nls_table *nls){	struct msdos_dir_slot *ps;	struct msdos_dir_entry *de;	int res;	int slot;	unsigned char cksum;	char *uniname;	const char *ip;	unsigned long page;	int unilen;	int i;	loff_t offset;	if (name[len-1] == '.') len--;	if(!(page = __get_free_page(GFP_KERNEL)))		return -ENOMEM;	uniname = (char *) page;	res = xlate_to_uni(name, len, uniname, &unilen, uni_xlate, utf8, nls);	if (res < 0) {		free_page(page);		return res;	}	*slots = unilen / 13;	for (cksum = i = 0; i < 11; i++) {		cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i];	}	PRINTK3(("vfat_fill_long_slots 3: slots=%d\n",*slots));	for (ps = ds, slot = *slots; slot > 0; slot--, ps++) {		ps->id = slot;		ps->attr = ATTR_EXT;		ps->reserved = 0;		ps->alias_checksum = cksum;		ps->start = 0;		offset = (slot - 1) * 26;		ip = &uniname[offset];		memcpy(ps->name0_4, ip, 10);		memcpy(ps->name5_10, ip+10, 12);		memcpy(ps->name11_12, ip+22, 4);	}	ds[0].id |= 0x40;	de = (struct msdos_dir_entry *) ps;	PRINTK3(("vfat_fill_long_slots 9\n"));	strncpy(de->name, msdos_name, MSDOS_NAME);	(*slots)++;	free_page(page);	return 0;}/* We can't get "." or ".." here - VFS takes care of those cases */static int vfat_build_slots(struct inode *dir,const char *name,int len,     struct msdos_dir_slot *ds, int *slots){	struct msdos_dir_entry *de;	char msdos_name[MSDOS_NAME];	int res, xlate, utf8;	struct nls_table *nls;	de = (struct msdos_dir_entry *) ds;	xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate;	utf8 = MSDOS_SB(dir->i_sb)->options.utf8;	nls = MSDOS_SB(dir->i_sb)->nls_io;	*slots = 1;	res = vfat_valid_longname(name, len, xlate);	if (res < 0)		return res;	if (vfat_valid_shortname(name, len, utf8) >= 0) {		vfat_format_name(name, len, de->name, utf8);		return 0;	}	res = vfat_create_shortname(dir, name, len, msdos_name, utf8);	if (res < 0)		return res;	return vfat_fill_long_slots(ds, name, len, msdos_name, slots, xlate,					utf8, nls);}static int vfat_add_entry(struct inode *dir,struct qstr* qname,	int is_dir,struct vfat_slot_info *sinfo_out,	struct buffer_head **bh, struct msdos_dir_entry **de){	struct super_block *sb = dir->i_sb;	struct msdos_dir_slot *ps;	loff_t offset;	struct msdos_dir_slot *ds;	int slots, slot;	int res;	struct msdos_dir_entry *de1;	struct buffer_head *bh1;	int ino;	int len;	loff_t dummy;	ds = (struct msdos_dir_slot *)	    kmalloc(sizeof(struct msdos_dir_slot)*MSDOS_SLOTS, GFP_KERNEL);	if (ds == NULL) return -ENOMEM;	len = qname->len;	while (len && qname->name[len-1] == '.')		len--;	res = fat_search_long(dir, qname->name, len,			(MSDOS_SB(sb)->options.name_check != 's') ||			!MSDOS_SB(sb)->options.posixfs,			&dummy, &dummy);	if (res > 0) /* found */		res = -EEXIST;	if (res)		goto cleanup;	res = vfat_build_slots(dir, qname->name, len, ds, &slots);	if (res < 0) goto cleanup;	offset = fat_add_entries(dir, slots, &bh1, &de1, &ino);	if (offset < 0) {		res = offset;		goto cleanup;	}	fat_brelse(sb, bh1);	/* Now create the new entry */	*bh = NULL;	for (slot = 0, ps = ds; slot < slots; slot++, ps++) {		if (fat_get_entry(dir,&offset,bh,de, &sinfo_out->ino) < 0) {			res = -EIO;			goto cleanup;		}		memcpy(*de, ps, sizeof(struct msdos_dir_slot));		fat_mark_buffer_dirty(sb, *bh, 1);	}	dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;	mark_inode_dirty(dir);	fat_date_unix2dos(dir->i_mtime,&(*de)->time,&(*de)->date);	(*de)->ctime_ms = 0;	(*de)->ctime = (*de)->time;	(*de)->adate = (*de)->cdate = (*de)->date;	(*de)->start = 0;	(*de)->starthi = 0;	(*de)->size = 0;	(*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH;	(*de)->lcase = CASE_LOWER_BASE | CASE_LOWER_EXT;	fat_mark_buffer_dirty(sb, *bh, 1);	/* slots can't be less than 1 */	sinfo_out->long_slots = slots - 1;	sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots;	res = 0;cleanup:	kfree(ds);	return res;}static int vfat_find(struct inode *dir,struct qstr* qname,	struct vfat_slot_info *sinfo, struct buffer_head **last_bh,	struct msdos_dir_entry **last_de){	struct super_block *sb = dir->i_sb;	loff_t offset;	int res,len;	len = qname->len;	while (len && qname->name[len-1] == '.') 		len--;	res = fat_search_long(dir, qname->name, len,			(MSDOS_SB(sb)->options.name_check != 's'),			&offset,&sinfo->longname_offset);	if (res>0) {		sinfo->long_slots = res-1;		if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->ino)>=0)			return 0;		res = -EIO;	} 	return res ? res : -ENOENT;}/* Find a hashed dentry for inode; NULL if there are none */static struct dentry *find_alias(struct inode *inode){	struct list_head *head, *next, *tmp;	struct dentry *alias;	head = &inode->i_dentry;	next = inode->i_dentry.next;	while (next != head) {		tmp = next;		next = tmp->next;		alias = list_entry(tmp, struct dentry, d_alias);		if (!list_empty(&alias->d_hash))			return dget(alias);	}	return NULL;}struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry){	int res;	struct vfat_slot_info sinfo;	struct inode *inode;	struct dentry *alias;	struct buffer_head *bh = NULL;	struct msdos_dir_entry *de;	int table;		PRINTK2(("vfat_lookup: name=%s, len=%d\n", 		 dentry->d_name.name, dentry->d_name.len));	table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0;	dentry->d_op = &vfat_dentry_ops[table];	inode = NULL;	res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de);	if (res < 0) {		table++;		goto error;	}	inode = fat_build_inode(dir->i_sb, de, sinfo.ino, &res);	fat_brelse(dir->i_sb, bh);	if (res)		return ERR_PTR(res);	alias = find_alias(inode);	if (alias) {		if (d_invalidate(alias)==0)			dput(alias);		else {			iput(inode);			return alias;		}			}error:	dentry->d_op = &vfat_dentry_ops[table];	dentry->d_time = dentry->d_parent->d_inode->i_version;	d_add(dentry,inode);	return NULL;}int vfat_create(struct inode *dir,struct dentry* dentry,int mode){	struct super_block *sb = dir->i_sb;	struct inode *inode = NULL;	struct buffer_head *bh = NULL;	struct msdos_dir_entry *de;	struct vfat_slot_info sinfo;	int res;	res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo, &bh, &de);	if (res < 0)		return res;	inode = fat_build_inode(sb, de, sinfo.ino, &res);	fat_brelse(sb, bh);	if (!inode)		return res;	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;	mark_inode_dirty(inode);	inode->i_version = ++event;	dir->i_version = event;	MSDOS_I(dir)->i_last_pos = 0;	dentry->d_time = dentry->d_parent->d_inode->i_version;	d_instantiate(dentry,inode);	return 0;}static int vfat_create_dotdirs(struct inode *dir, struct inode *parent){	struct super_block *sb = dir->i_sb;	struct buffer_head *bh;	struct msdos_dir_entry *de;	__u16 date, time;	if ((bh = fat_add_cluster1(dir)) == NULL) return -ENOSPC;	/* zeroed out, so... */	fat_date_unix2dos(dir->i_mtime,&time,&date);	de = (struct msdos_dir_entry*)&bh->b_data[0];	memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);	memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);	de[0].attr = de[1].attr = ATTR_DIR;	de[0].ctime = de[0].time = de[1].ctime = de[1].time = CT_LE_W(time);	de[0].adate = de[0].cdate = de[0].date = de[1].adate =		de[1].cdate = de[1].date = CT_LE_W(date);	de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart);	de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16);	de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart);	de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16);	fat_mark_buffer_dirty(sb, bh, 1);	fat_brelse(sb, bh);	dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;	mark_inode_dirty(dir);	return 0;}static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,     struct buffer_head *bh, struct msdos_dir_entry *de){	struct super_block *sb = dir->i_sb;	loff_t offset;	int i,ino;	/* remove the shortname */	dir->i_mtime = CURRENT_TIME;	dir->i_atime = CURRENT_TIME;	dir->i_version = ++event;	MSDOS_I(dir)->i_last_pos = 0;	mark_inode_dirty(dir);	de->name[0] = DELETED_FLAG;	fat_mark_buffer_dirty(sb, bh, 1);	/* remove the longname */	offset = sinfo->longname_offset; de = NULL;	for (i = sinfo->long_slots; i > 0; --i) {		if (fat_get_entry(dir, &offset, &bh, &de, &ino) < 0)			continue;		de->name[0] = DELETED_FLAG;		de->attr = 0;		fat_mark_buffer_dirty(sb, bh, 1);	}	if (bh) fat_brelse(sb, bh);}int vfat_rmdir(struct inode *dir,struct dentry* dentry){	int res;	struct vfat_slot_info sinfo;	struct buffer_head *bh = NULL;	struct msdos_dir_entry *de;	if (!list_empty(&dentry->d_hash))		return -EBUSY;	res = fat_dir_empty(dentry->d_inode);	if (res)		return res;	res = vfat_find(dir,&dentry->d_name,&sinfo, &bh, &de);	if (res<0)		return res;	dentry->d_inode->i_nlink = 0;	dentry->d_inode->i_mtime = CURRENT_TIME;	dentry->d_inode->i_atime = CURRENT_TIME;	fat_detach(dentry->d_inode);	mark_inode_dirty(dentry->d_inode);	/* releases bh */	vfat_remove_entry(dir,&sinfo,bh,de);	dir->i_nlink--;	return 0;}int vfat_unlink(struct inode *dir, struct dentry* dentry){	int res;	struct vfat_slot_info sinfo;	struct buffer_head *bh = NULL;	struct msdos_dir_entry *de;	PRINTK1(("vfat_unlink: %s\n", dentry->d_name.name));	res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de);	if (res < 0)		return res;	dentry->d_inode->i_nlink = 0;	dentry->d_inode->i_mtime = CURRENT_TIME;	dentry->d_inode->i_atime = CURRENT_TIME;	fat_detach(dentry->d_inode);	mark_inode_dirty(dentry->d_inode);	/* releases bh */	vfat_remove_entry(dir,&sinfo,bh,de);	d_delete(dentry);	return res;}int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode){	struct super_block *sb = dir->i_sb;	struct inode *inode = NULL;	struct vfat_slot_info sinfo;	struct buffer_head *bh = NULL;	struct msdos_dir_entry *de;	int res;	res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo, &bh, &de);	if (res < 0)		return res;	inode = fat_build_inode(sb, de, sinfo.ino, &res);	if (!inode)		goto out;	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;	mark_inode_dirty(inode);	inode->i_version = ++event;	dir->i_version = event;	MSDOS_I(dir)->i_last_pos = 0;	dir->i_nlink++;	inode->i_nlink = 2; /* no need to mark them dirty */	res = vfat_create_dotdirs(inode, dir);	if (res < 0)		goto mkdir_failed;	dentry->d_time = dentry->d_parent->d_inode->i_version;	d_instantiate(dentry,inode);out:	fat_brelse(sb, bh);	return res;mkdir_failed:	inode->i_nlink = 0;	inode->i_mtime = CURRENT_TIME;	inode->i_atime = CURRENT_TIME;	fat_detach(inode);	mark_inode_dirty(inode);	/* releases bh */	vfat_remove_entry(dir,&sinfo,bh,de);	iput(inode);	dir->i_nlink--;	return res;} int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,		struct inode *new_dir,struct dentry *new_dentry){	struct super_block *sb = old_dir->i_sb;	struct buffer_head *old_bh,*new_bh,*dotdot_bh;	struct msdos_dir_entry *old_de,*new_de,*dotdot_de;	int dotdot_ino;	struct inode *old_inode, *new_inode;	int res, is_dir;	struct vfat_slot_info old_sinfo,sinfo;	old_bh = new_bh = dotdot_bh = NULL;	old_inode = old_dentry->d_inode;	new_inode = new_dentry->d_inode;	res = vfat_find(old_dir,&old_dentry->d_name,&old_sinfo,&old_bh,&old_de);	PRINTK3(("vfat_rename 2\n"));	if (res < 0) goto rename_done;	is_dir = S_ISDIR(old_inode->i_mode);	if (is_dir && (res = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,				&dotdot_de,&dotdot_ino)) < 0)		goto rename_done;	if (new_dentry->d_inode) {		res = vfat_find(new_dir,&new_dentry->d_name,&sinfo,&new_bh,				&new_de);		if (res < 0 || MSDOS_I(new_inode)->i_location != sinfo.ino) {			/* WTF??? Cry and fail. */			printk(KERN_WARNING "vfat_rename: fs corrupted\n");			goto rename_done;		}		if (is_dir) {			res = fat_dir_empty(new_inode);			if (res)				goto rename_done;		}		fat_detach(new_inode);	} else {		res = vfat_add_entry(new_dir,&new_dentry->d_name,is_dir,&sinfo,					&new_bh,&new_de);		if (res < 0) goto rename_done;	}	new_dir->i_version = ++event;	MSDOS_I(new_dir)->i_last_pos = 0;	/* releases old_bh */	vfat_remove_entry(old_dir,&old_sinfo,old_bh,old_de);	old_bh=NULL;	fat_detach(old_inode);	fat_attach(old_inode, sinfo.ino);	mark_inode_dirty(old_inode);	old_dir->i_version = ++event;	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;	mark_inode_dirty(old_dir);	if (new_inode) {		new_inode->i_nlink--;		new_inode->i_ctime=CURRENT_TIME;	}	if (is_dir) {		int start = MSDOS_I(new_dir)->i_logstart;		dotdot_de->start = CT_LE_W(start);		dotdot_de->starthi = CT_LE_W(start>>16);		fat_mark_buffer_dirty(sb, dotdot_bh, 1);		old_dir->i_nlink--;		if (new_inode) {			new_inode->i_nlink--;		} else {			new_dir->i_nlink++;			mark_inode_dirty(new_dir);		}	}rename_done:	fat_brelse(sb, dotdot_bh);	fat_brelse(sb, old_bh);	fat_brelse(sb, new_bh);	return res;}/* Public inode operations for the VFAT fs */struct inode_operations vfat_dir_inode_operations = {	&fat_dir_operations,	/* default directory file-ops */	vfat_create,		/* create */	vfat_lookup,		/* lookup */	NULL,			/* link */	vfat_unlink,		/* unlink */	NULL,			/* symlink */	vfat_mkdir,		/* mkdir */	vfat_rmdir,		/* rmdir */	NULL,			/* mknod */	vfat_rename,		/* rename */	NULL,			/* readlink */	NULL,			/* followlink */	NULL,			/* readpage */	NULL,			/* writepage */	NULL,			/* bmap */	NULL,			/* truncate */	NULL			/* permission */};struct super_block *vfat_read_super(struct super_block *sb,void *data,				    int silent){	struct super_block *res;  	MOD_INC_USE_COUNT;		MSDOS_SB(sb)->options.isvfat = 1;	res = fat_read_super(sb, data, silent, &vfat_dir_inode_operations);	if (res == NULL) {		sb->s_dev = 0;		MOD_DEC_USE_COUNT;		return NULL;	}	if (!parse_options((char *) data, &(MSDOS_SB(sb)->options))) {		MOD_DEC_USE_COUNT;	} else {		MSDOS_SB(sb)->put_super_callback=vfat_put_super_callback;		MSDOS_SB(sb)->options.dotsOK = 0;		if (MSDOS_SB(sb)->options.posixfs) {			MSDOS_SB(sb)->options.name_check = 's';		}		if (MSDOS_SB(sb)->options.name_check != 's') {			sb->s_root->d_op = &vfat_dentry_ops[0];		} else {			sb->s_root->d_op = &vfat_dentry_ops[2];		}	}	return res;}#ifdef MODULEint init_module(void){	return init_vfat_fs();}void cleanup_module(void){	unregister_filesystem(&vfat_fs_type);}#endif /* ifdef MODULE */

⌨️ 快捷键说明

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