📄 ext2namei.c
字号:
/*
* linux/fs/ext2/namei.c
*
* Rewrite to pagecache. Almost all code had been changed, so blame me
* if the things go wrong. Please, send bug reports to viro@math.psu.edu
*
* Stuff here is basically a glue between the VFS and generic UNIXish
* filesystem that keeps everything in pagecache. All knowledge of the
* directory layout is in fs/ext2/dir.c - it turned out to be easily separatable
* and it's easier to debug that way. In principle we might want to
* generalize that a bit and turn it into a library. Or not.
*
* The only non-static object here is ext2_dir_inode_operations.
*
* TODO: get rid of kmap() use, add readahead.
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*
* from
*
* linux/fs/minix/namei.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Big-endian to little-endian byte-swapping/bitmaps by
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
/*该段代码函数均为实现ext2系统中磁盘上寻找文件而设*/
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/pagemap.h>
/*
*以下两函数成对,分别实现硬链接数减1和加1操作,使得编码清晰
*/
/*硬链接数加1*/
static inline void ext2_inc_count(struct inode *inode)
{
/*硬链接数加1*/
inode->i_nlink++;
/*设置该inode为脏*/
mark_inode_dirty(inode);
}
/*硬链接数目减1*/
static inline void ext2_dec_count(struct inode *inode)
{
/*硬链接数目减1*/
inode->i_nlink--;
/*重新设置该inode为脏*/
mark_inode_dirty(inode);
}
/*将给定inode挂接到与其对应的dentry*/
static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
{
/*当前inode加入到页面*/
int err = ext2_add_link(dentry, inode);
if (!err) {
/*将inode挂接到其对应的dentry结构上
*并将inode、dentry连入其相应队列*/
d_instantiate(dentry, inode);
/*成功返回0*/
return 0;
}
/*硬链接数目减1*/
ext2_dec_count(inode);
/*释放inode节点资源*/
iput(inode);
return err;
}
/*
* ext2系统中查找指定目录
*/
static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry)
{
struct inode * inode;
ino_t ino;/*usigned long索引结点号*/
/*文件名长度大于ext2系统规定最大长度255*/
if (dentry->d_name.len > EXT2_NAME_LEN)
/*返回文件名过长的错误*/
return ERR_PTR(-ENAMETOOLONG);
/*从磁盘上找到并读入当前结点的目录项*/
ino = ext2_inode_by_name(dir, dentry);
inode = NULL;
if (ino) {
/*根据索引结点号从磁盘读入相应索引结点并在内存中建立相应inode*/
inode = iget(dir->i_sb, ino);
/*inode为空则返回操作无法执行的错误*/
if (!inode)
return ERR_PTR(-EACCES);
}
/*完成dentry结构的设置,并将其挂入哈希表的某个队列*/
d_add(dentry, inode);
/*成功返回空*/
return NULL;
}
/*
*当我们要产生一个新的文件时,内核必须要先为这个文件产生一个inode,配置inode内存是属于VFS的工作范围,
*但是产生一个inode跟文件系统本身有很大的关系,因此VFS会调用文件系统里i_op->create()做些额外的事,在ext2文件系统中则由该函数实现。
*/
static int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
{
/*ext2系统中新建一个inode结构*/
struct inode * inode = ext2_new_inode (dir, mode);
/*设置错误标记*/
int err = PTR_ERR(inode);
/*判断无错*/
if (!IS_ERR(inode)) {
/*初始化inode各变量值*/
inode->i_op = &ext2_file_inode_operations;
inode->i_fop = &ext2_file_operations;
inode->i_mapping->a_ops = &ext2_aops;
/*设置inode结构脏位*/
mark_inode_dirty(inode);
/*将inode挂接到与其对应的dentry*/
err = ext2_add_nondir(dentry, inode);
}
return err;
}
/*在指定目录下产生一个特殊文件的inode,并根据指定模式为inode->i_op赋相应值*/
static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
/*ext2文件系统中新建一个指定模式的inode*/
struct inode * inode = ext2_new_inode (dir, mode);
/*记录错误信息*/
int err = PTR_ERR(inode);
/*若创建成功*/
if (!IS_ERR(inode)) {
/*初始化特殊文件inode的各项值*/
init_special_inode(inode, mode, rdev);
/*设置该inode为脏*/
mark_inode_dirty(inode);
/*将inode挂接到与其对应的dentry*/
err = ext2_add_nondir(dentry, inode);
}
/*返回信息*/
return err;
}
/*为与目录项相关的符号链接创建一个新的索引节点*/
static int ext2_symlink (struct inode * dir, struct dentry * dentry,
const char * symname)
{ /*创建一个超块,并使它等于dir所指向的超块*/
struct super_block * sb = dir->i_sb;
/*错误类型为文件名过长*/
int err = -ENAMETOOLONG;
/*i等于路径名的长度加一*/
unsigned l = strlen(symname)+1;
struct inode * inode;
/*i的长度达于超块的长度,返回错误类型*/
if (l > sb->s_blocksize)
goto out;
/*将dir和文件类型传给ext2_new_inode函数建立一个新的inode*/
inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO);
err = PTR_ERR(inode);
/*若有错返回错误类型*/
if (IS_ERR(inode))
goto out;
if (l > sizeof (inode->u.ext2_i.i_data)) {
/* slow symlink */
/*node的i_op指针指向ext2文件系统快速符号连接文件索引点的操作 */
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &ext2_aops;
/*调用block_symlink函数,建立符号连接*/
err = block_symlink(inode, symname, l);
/*有错则跳转*/
if (err)
goto out_fail;
} else {
/* fast symlink */
/*inode的i_op指针指向ext2文件系统快速符号连接文件索引点的操作集*/
inode->i_op = &ext2_fast_symlink_inode_operations;
/*调用memcpy函数,建立符号连接*/
memcpy((char*)&inode->u.ext2_i.i_data,symname,l);
/*inode的字节长度为symname 的长度*/
inode->i_size = l-1;
}
/*置inode为脏*/
mark_inode_dirty(inode);
/*将文件挂接到制定的目录下,并填入其文件索引节点*/
err = ext2_add_nondir(dentry, inode);
out:
return err;
out_fail:
/*inode的硬链接数减一*/
ext2_dec_count(inode);
/*inode的用户数减一*/
iput (inode);
goto out;
}
/*创建一个名为new_dentry新的硬链接,这个硬链接指向dir目录下的old_dentry的文件*/
static int ext2_link (struct dentry * old_dentry, struct inode * dir,
struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
/*若旧文件是目录则返回错误信息*/
if (S_ISDIR(inode->i_mode))
return -EPERM;
/*若inode的硬链接数超过上限返回错误信息*/
if (inode->i_nlink >= EXT2_LINK_MAX)
return -EMLINK;
/*将inode的修改时间置为当前时间*/
inode->i_ctime = CURRENT_TIME;
/*node的硬链接数加一*/
ext2_inc_count(inode);
atomic_inc(&inode->i_count);
/*掉用ext2_add_nondir函数,把dentry挂接到其父目录之下,并填入其文件索引节点
*成功返回0,否则返回错误类型*/
return ext2_add_nondir(dentry, inode);
}
/*在ext2文件卷上建立一个目录*/
static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
struct inode * inode;
int err = -EMLINK;
/*目录的应链接数超过了系统规定的最大值*/
if (dir->i_nlink >= EXT2_LINK_MAX)
goto out;
/*目录的链接数加一*/
ext2_inc_count(dir);
/*调用ext2_new_inode(dir,S_IFDIR,&err),在ext2文件卷中产生一个新ext2 inode;记其对应的VFS inode 为 inode */
inode = ext2_new_inode (dir, S_IFDIR | mode);
err = PTR_ERR(inode);
/*有错则转到out_dir*/
if (IS_ERR(inode))
goto out_dir;
/*修改inode对应指针*/
inode->i_op = &ext2_dir_inode_operations;
inode->i_fop = &ext2_dir_operations;
inode->i_mapping->a_ops = &ext2_aops;
/*增加inode的硬链接数*/
ext2_inc_count(inode);
/*找到将要建立资目录的地址,并把该区域置成null*/
err = ext2_make_empty(inode, dir);
/*有错则跳转*/
if (err)
goto out_fail;
/*将文件挂接到其父目录之下*/
err = ext2_add_link(dentry, inode);
if (err)
goto out_fail;
d_instantiate(dentry, inode);
out:
return err;
out_fail:
/*inode的硬链接数减一*/
ext2_dec_count(inode);
ext2_dec_count(inode);
iput(inode);
out_dir:
/*目录的硬链接数减一*/
ext2_dec_count(dir);
goto out;
}
/*从目录删除目录项对象所指文件的硬链接*/
static int ext2_unlink(struct inode * dir, struct dentry *dentry)
{
struct inode * inode = dentry->d_inode;
struct ext2_dir_entry_2 * de;
struct page * page;
int err = -ENOENT;
/*在目录下找到该文件到入口地址*/
de = ext2_find_entry (dir, dentry, &page);
if (!de)
goto out;
/*删除入口地址*/
err = ext2_delete_entry (de, page);
if (err)
goto out;
/*把目录的修改时间赋给inode*/
inode->i_ctime = dir->i_ctime;
/*将文件的硬链接数减一*/
ext2_dec_count(inode);
err = 0;
out:
return err;
}
/*删除子目录,自目录的信息包含在dentry中*/
static int ext2_rmdir (struct inode * dir, struct dentry *dentry)
{
struct inode * inode = dentry->d_inode;
int err = -ENOTEMPTY;
/*若要删除的目录为空*/
if (ext2_empty_dir(inode)) {
/*从目录删除目录项对象所指文件的硬链接*/
err = ext2_unlink(dir, dentry);
if (!err) {
inode->i_size = 0;
/*将文件的硬链接数减一*/
ext2_dec_count(inode);
/*将目录的硬链接数减一*/
ext2_dec_count(dir);
}
}
return err;
}
/*由代表目录的inode提供
*将位于old_dir里的old_dentry文件名称改为位于new_dir里的new_dentry的文件名*/
static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
struct inode * new_dir, struct dentry * new_dentry )
{ /*获得旧文件的信息*/
struct inode * old_inode = old_dentry->d_inode;
/*获得新文件的信息*/
struct inode * new_inode = new_dentry->d_inode;
/*页表结构体*/
struct page * dir_page = NULL;
/*目录项置为null*/
struct ext2_dir_entry_2 * dir_de = NULL;
struct page * old_page;
struct ext2_dir_entry_2 * old_de;
int err = -ENOENT;
/*找旧文件的入口地址*/
old_de = ext2_find_entry (old_dir, old_dentry, &old_page);
/*若找不到则退出*/
if (!old_de)
goto out;
/*判断是否是目录*/
if (S_ISDIR(old_inode->i_mode)) {
err = -EIO;
/*得到上层目录文件的入口*/
dir_de = ext2_dotdot(old_inode, &dir_page);
/*未找到跳到out_old*/
if (!dir_de)
goto out_old;
}
/*如果目录不为空*/
if (new_inode) {
struct page *new_page;
struct ext2_dir_entry_2 *new_de;
/*错误类型目录不空*/
err = -ENOTEMPTY;
/*若目录不为空转到out_dir处理*/
if (dir_de && !ext2_empty_dir (new_inode))
goto out_dir;
err = -ENOENT;
/*找新文件的入口地址*/
new_de = ext2_find_entry (new_dir, new_dentry, &new_page);
/*如果找不到转到out_dir处理*/
if (!new_de)
goto out_dir;
/*旧文件的硬链接数加一*/
ext2_inc_count(old_inode);
/*给出新文件的目录和文件入口地址,将旧文件的inode赋给新文件*/
ext2_set_link(new_dir, new_de, new_page, old_inode);
/*将inode的修改时间赋成当前时间*/
new_inode->i_ctime = CURRENT_TIME;
/*目录文件不为空*/
if (dir_de)
/*将与新文件建立连接的文件数减一*/
new_inode->i_nlink--;
/*新文件的硬链接数减一*/
ext2_dec_count(new_inode);
} else {
if (dir_de) {
/*错误类型为连接错误*/
err = -EMLINK;
/*与新文件建立连接的文件数大于上限转到out_dir*/
if (new_dir->i_nlink >= EXT2_LINK_MAX)
goto out_dir;
}
/*旧文件的硬链接数加一*/
ext2_inc_count(old_inode);
/*将新文件挂接到其父目录之下*/
err = ext2_add_link(new_dentry, old_inode);
if (err) {
/*旧文件的硬链接数减一*/
ext2_dec_count(old_inode);
/*转到out_dir*/
goto out_dir;
}
/*目录文件不为空*/
if (dir_de)
/*旧目录的硬链接数加一*/
ext2_inc_count(new_dir);
}
/*删除旧文件的入口地址*/
ext2_delete_entry (old_de, old_page);
/*旧文件的硬链接数减一*/
ext2_dec_count(old_inode);
/*目录文件不为空*/
if (dir_de) {
/*释放page*/
ext2_set_link(old_inode, dir_de, dir_page, new_dir);
/*旧文件的硬链接数减一*/
ext2_dec_count(old_dir);
}
return 0;
out_dir:
/*目录文件不为空*/
if (dir_de) {
kunmap(dir_page);
/*释放dir_page目录页*/
page_cache_release(dir_page);
}
out_old:
kunmap(old_page);
/*释放old_page旧目录页*/
page_cache_release(old_page);
out:
/*返回错误信息*/
return err;
}
/*ext2目录结点的函数跳转结构*/
struct inode_operations ext2_dir_inode_operations = {
create: ext2_create, /*新建一个inode*/
lookup: ext2_lookup, /*查找指定目录*/
link: ext2_link,/*创建链接*/
unlink: ext2_unlink,/*删除链接*/
symlink: ext2_symlink,/*符号链接*/
mkdir: ext2_mkdir,/*创建子目录*/
rmdir: ext2_rmdir,/*删除子目录*/
mknod: ext2_mknod,/*创建设备节点*/
rename: ext2_rename,/*重命名*/
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -