📄 namei.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 + -