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

📄 namei.c

📁 课程设计
💻 C
字号:
#include <linux/fs.h>
#include <linux/buffer_head.h>

#include "xbfs.h"


int dir_sanity_check(ino_t ino, struct xbfs_inode_disk *id);
u32 bmp_get_block(struct super_block *sb);
void bmp_free_block(struct super_block *sb, u32 block);
void xbfs_set_inode(struct inode *inode);


static int add_link(struct dentry *dentry, struct inode *inode)
{
	struct inode *parent;
	struct xbfs_inode_disk *id;
	struct buffer_head *bh;
	struct xbfs_dirent *ent;

	parent = dentry->d_parent->d_inode;
	DPRINT("add to inode %ld\n", parent->i_ino);

	bh = sb_bread(parent->i_sb, parent->i_ino);
	if (!bh) {
		DPRINT("sb_bread inode %ld error\n", parent->i_ino);
		return -EINVAL;
	}

	id = (typeof(id))bh->b_data;
	ent = find_empty_dirent(id);
	if (!ent) {
		DPRINT("dir inode %ld is full. cannot add dirent\n", parent->i_ino);
		brelse(bh);
		return -ENOSPC;
	}
	
	DPRINT("malloc dirent idx %d\n", ent - id->dirent);
	
	strncpy(ent->name, dentry->d_name.name, sizeof(ent->name) - 1);
	ent->block = inode->i_ino;
	set_dirent_empty(&ent[1]);
	mark_buffer_dirty(bh);

	d_instantiate(dentry, inode);

	brelse(bh);
	return 0;
}

static struct xbfs_dirent *find_dirent(struct dentry *dentry, struct xbfs_inode_disk *id)
{
	struct xbfs_dirent *ent;

	for_each_dirent(id, ent, {
		if (!memcmp(dentry->d_name.name, 
					ent->name, 
					dentry->d_name.len + 1))
			goto found;
	});
	
	return NULL;

found:
	return ent;
}

static struct dentry *xbfs_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
{
	struct xbfs_inode_disk *id;
	struct inode *inode;
	struct buffer_head *bh;
	struct xbfs_dirent *ent;

	DPRINT("enter\n");

	if (dentry->d_name.len > sizeof(id->dirent->name))
		return ERR_PTR(-ENAMETOOLONG);

	bh = sb_bread(dir->i_sb, dir->i_ino);
	if (!bh) {
		DPRINT("sb_bread inode %ld error\n", dir->i_ino);
		return ERR_PTR(-EINVAL);
	}
	
	id = (typeof(id))bh->b_data;
	if (dir_sanity_check(dir->i_ino, id))
		goto out_relse;
	
	ent = find_dirent(dentry, id);
	if (!ent)
		goto out_relse;

	inode = iget(dir->i_sb, ent->block);
 	if (!inode) {
		DPRINT("entry %s of inode %ld is fucked\n", 
				ent->name,
				dir->i_ino);
		goto out_relse;
	}
	d_add(dentry, inode);

out_relse:
	brelse(bh);
	return NULL;
}

int xbfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{
	DPRINT("enter\n");

	generic_fillattr(dentry->d_inode, stat);
	return 0;
}

static struct inode *__mknod(struct inode *dir, struct dentry *dentry, int mode)
{
	struct inode *inode;
	u32 ino;
	struct buffer_head *bh;
	struct xbfs_inode_disk *id;

	DPRINT("enter\n");
	
	inode = new_inode(dir->i_sb);
	if (!inode) {
		DPRINT("no mem to malloc inode\n");
		return NULL;
	}
	
	ino = bmp_get_block(dir->i_sb);
	if (!ino)
		return NULL;

	bh = sb_bread(dir->i_sb, ino);
	if (!bh) {
		DPRINT("bmp.c may be fucked. cannot read block %d\n", ino);
		goto out_free_blk;
	}

	id = (typeof(id))bh->b_data;
	id->mode = mode;
	id->size = 0;
	set_dirent_empty(&id->dirent[0]);
	mark_buffer_dirty(bh);
	
	inode->i_mode = mode;
	inode->i_ino = ino;
	insert_inode_hash(inode);
	xbfs_set_inode(inode);
	mark_inode_dirty(inode);
	
	if (add_link(dentry, inode))
		goto out_relse;

	DPRINT("done\n");
	
	return inode;

out_relse:
	brelse(bh);

out_free_blk:
	bmp_free_block(dir->i_sb, ino);
	iput(inode);
	return NULL;
}

static int xbfs_mknod(struct inode * dir, struct dentry *dentry, int mode, dev_t rdev)
{
	DPRINT("enter\n");
	
	if (__mknod(dir, dentry, mode))
		return 0;
	return -EPERM;
}

static int xbfs_create(struct inode * dir, struct dentry *dentry, int mode,
		struct nameidata *nd)
{
	return xbfs_mknod(dir, dentry, mode, 0);
}

static int xbfs_mkdir(struct inode * dir, struct dentry *dentry, int mode)
{
	struct inode *inode;

	DPRINT("enter\n");
	
	inode = __mknod(dir, dentry, S_IFDIR | mode);
	if (!inode)
		return -EPERM;

	inode_inc_link_count(inode);
	inode_inc_link_count(dir);
	
	return 0;
}


static int xbfs_unlink(struct inode * dir, struct dentry *dentry)
{
	struct xbfs_inode_disk *id;
	struct inode *parent;
	struct buffer_head *bh;
	struct xbfs_dirent *ent;

	DPRINT("enter\n");

	parent = dentry->d_parent->d_inode;
	bh = sb_bread(dir->i_sb, parent->i_ino);
	if (!bh) {
		DPRINT("sb_bread inode %ld error\n", parent->i_ino);
		return -EINVAL;
	}

	id = (typeof(id))bh->b_data;
	ent = find_dirent(dentry, id);
	if (!ent) {
		DPRINT("%s not found\n", dentry->d_name.name);
		brelse(bh);
		return -ENOSPC;
	}

	set_dirent_tombstone(ent);
	mark_buffer_dirty(bh);
	mark_inode_dirty(parent);
	brelse(bh);

	inode_dec_link_count(dentry->d_inode);
	mark_inode_dirty(dentry->d_inode);

	return 0;
}


static int xbfs_rmdir(struct inode * dir, struct dentry *dentry)
{
	struct inode *inode;
	struct buffer_head *bh;
	struct xbfs_inode_disk *id;
	struct xbfs_dirent *ent;
	int err;
	
	DPRINT("enter\n");

	inode = dentry->d_inode;
	
	bh = sb_bread(dir->i_sb, inode->i_ino);
	if (!bh) {
		DPRINT("sb_bread inode %ld error\n", inode->i_ino);
		return -EINVAL;
	}
	
	id = (typeof(id))bh->b_data;
	for_each_dirent(id, ent, {
		brelse(bh);
		return -ENOTEMPTY;
	});

	err = xbfs_unlink(dir, dentry);
	if (!err) {
		inode_dec_link_count(dir);
		inode_dec_link_count(inode);
	}

	return err;
}


const struct inode_operations xbfs_dir_inode_operations = {
	.lookup		= xbfs_lookup,
	.getattr	= xbfs_getattr,
	.mknod		= xbfs_mknod,
	.mkdir		= xbfs_mkdir,
	.unlink		= xbfs_unlink,
	.rmdir		= xbfs_rmdir,
	.create		= xbfs_create
};

⌨️ 快捷键说明

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