linux 进入文件系统路径,Linux虚拟文件系统--文件路径名的解析(1)--整体过程

注意之前传递进来的dfd为AT_FDCWD,因此path_init中只有可能出现前两种情况:1.路径以绝对路径的方式给出 2.路径以相对路径的方式给出。此时nd中的path保存了查找的起始目录,对于第一种情况,即为'/',第二种情况起始目录要从当前进程的fs结构中提取。

下面通过path_walk()开始进行解析,我们直接进入path_walk()-->link_path_walk()-->__link_path_walk()进行分析,因为前面几个函数都没做什么实质性的工作。

static int __link_path_walk(const char *name, struct nameidata *nd)

{

struct path next;

struct inode *inode;

int err;

unsigned int lookup_flags = nd->flags;

while (*name=='/')//忽略文件名前面的'/'

name++;

if (!*name)

goto return_reval;

inode = nd->path.dentry->d_inode;//获取当前目录的inode

if (nd->depth)

lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE);

/* At this point we know we have a real path component. */

for(;;) {

unsigned long hash;

struct qstr this;

unsigned int c;

nd->flags |= LOOKUP_CONTINUE;

err = exec_permission_lite(inode);//进行访问权限的检查

if (err)

break;

this.name = name;//当前进行解析的文件名分量

c = *(const unsigned char *)name;

hash = init_name_hash();//hash值初始化为0

/*计算当前文件名分量的hash值*/

do {

name++;

hash = partial_name_hash(c, hash);

c = *(const unsigned char *)name;

} while (c && (c != '/'));

this.len = name - (const char *) this.name;//保存文件名分量的长度

this.hash = end_name_hash(hash);//保存当前文件名分量的hash值

/* remove trailing slashes? */

if (!c)//文件名解析完毕

goto last_component;

while (*++name == '/');//跳过'/'

if (!*name)

goto last_with_slashes;

/*

* "." and ".." are special - ".." especially so because it has

* to be able to know about the current root directory and

* parent relationships.

*/

/*如果检测到之前分析的文件名分量的第一个字符为'.'*/

if (this.name[0] == '.') switch (this.len) {

default:

break;

case 2://文件名长度为2并且下一个字符也为'.'则表明要退回到上级目录

if (this.name[1] != '.')

break;

follow_dotdot(nd);

inode = nd->path.dentry->d_inode;

//注意这里没有break,因此将通过后面的continue直接回到循环开头

case 1://长度为1表示当前目录,则直接忽略即可

continue;

}

/*下面的部分用来处理普通的文件路径分量(不为.和..)*/

/*如果底层文件系统的dentry定义了d_op和d_hash则调用文件系统中的d_hash进行hash值的计算*/

if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) {

err = nd->path.dentry->d_op->d_hash(nd->path.dentry,

&this);

if (err < 0)

break;

}

//do_lookup执行实际的查找,注意nd中的path对应的是父目录,而this是对应的当前解析的路径分量

err = do_lookup(nd, &this, &next);

if (err)

break;

err = -ENOENT;

inode = next.dentry->d_inode;//获取刚刚解析的路径分量的inode

if (!inode)

goto out_dput;

if (inode->i_op->follow_link) {//如果刚刚解析的路径为符号链接,则通过do_follow_link进行处理

err = do_follow_link(&next, nd);

if (err)

goto return_err;

err = -ENOENT;

inode = nd->path.dentry->d_inode;

if (!inode)

break;

} else//不为符号链接,则路径分量解析完毕,根据next更新nd中的path准备解析下一个分量

path_to_nameidata(&next, nd);

err = -ENOTDIR;

if (!inode->i_op->lookup)//如果刚刚解析的路径分量对应的inode没有定义lookup函数,

break;                //则无法以此为父目录进行解析了

continue;//这里标识一次解析完毕,跳转到开头继续解析下一个分量

/* here ends the main loop */

last_with_slashes:

lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;

last_component://到了最后一个分量

/* Clear LOOKUP_CONTINUE iff it was previously unset */

nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;

if (lookup_flags & LOOKUP_PARENT)//如果最终要查找的是最后一个路径分量的父目录

goto lookup_parent;

/*下面的查找过程和上面的基本一致*/

if (this.name[0] == '.') switch (this.len) {

default:

break;

case 2:

if (this.name[1] != '.')

break;

follow_dotdot(nd);

inode = nd->path.dentry->d_inode;

/* fallthrough */

case 1:

goto return_reval;

}

if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) {

err = nd->path.dentry->d_op->d_hash(nd->path.dentry,

&this);

if (err < 0)

break;

}

err = do_lookup(nd, &this, &next);

if (err)

break;

inode = next.dentry->d_inode;

if (follow_on_final(inode, lookup_flags)) {

err = do_follow_link(&next, nd);

if (err)

goto return_err;

inode = nd->path.dentry->d_inode;

} else

path_to_nameidata(&next, nd);

err = -ENOENT;

if (!inode)

break;

if (lookup_flags & LOOKUP_DIRECTORY) {

err = -ENOTDIR;

if (!inode->i_op->lookup)

break;

}

goto return_base;

lookup_parent://如果目标是最后一个分量的父目录,则不用进行查找了,

//因为nd的path总是指向当前要分析的路径的父目录的

//下面只需要对nd的last_tpye字段进行处理,表示最后一个分量的类型

nd->last = this;

nd->last_type = LAST_NORM;

if (this.name[0] != '.')

goto return_base;

if (this.len == 1)

nd->last_type = LAST_DOT;

else if (this.len == 2 && this.name[1] == '.')

nd->last_type = LAST_DOTDOT;

else

goto return_base;

return_reval:

/*

* We bypassed the ordinary revalidation routines.

* We may need to check the cached dentry for staleness.

*/

if (nd->path.dentry && nd->path.dentry->d_sb &&

(nd->path.dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) {

err = -ESTALE;

/* Note: we do not d_invalidate() */

if (!nd->path.dentry->d_op->d_revalidate(

nd->path.dentry, nd))

break;

}

return_base:

return 0;

out_dput:

path_put_conditional(&next, nd);

break;

}

path_put(&nd->path);

return_err:

return err;

}

其中几个比较重要的函数,follow_dotdot()--退回到上级目录, do_lookup()--普通文件名的实际查找工作, do_follow_link()--追踪符号链接,在下篇文章再拿出来进行具体分析。0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值