注意之前传递进来的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()--追踪符号链接,在下篇文章再拿出来进行具体分析。

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

  1. 十年码农讲解Linux型内核,操作系统 --- 虚拟文件系统

    1.虚拟文件系统的分层结构 上层:虚拟文件系统 底层:特定文件系统模块,例如:网络文件系统(nfs.smb)等其他类型文件系统 虚拟文件系统的目的:将接口暴露给用户,屏蔽底层文件系统的差异性,它是对所 ...

  2. linux 虚拟文件系统 源码,Linux内核源代码情状分析-虚拟文件系统

    Linux内核源代码情景分析-虚拟文件系统 我们先来看两张图: 第一张是VFS与具体文件系统的关系示意图: 第二张是Linux文件系统的层次结构: 特殊文件:用来实现"管道"的文件 ...

  3. Linux文件系统二(虚拟文件系统VFS实现原理)

    创作人QQ:851301776,邮箱:lfr890207@163.com         欢迎大家一起技术交流,本博客主要是自己学习的心得体会,只为每天进步一点点! 个人座右铭:          1 ...

  4. Linux套接字与虚拟文件系统

    引言    在Unix的世界里,万物皆文件,通过虚拟文件系统VFS,程序可以用标准的Unix系统调用对不同的文件系统,甚至不同介质上的文件系统进行读写操作.对于网络套接字socket也是如此,除了专属 ...

  5. Linux内核设计与实现---虚拟文件系统

    虚拟文件系统 1 通用文件系统 2 文件系统抽象层 3 Unix文件系统 4 VFS对象及其数据结构 其他VFS对象 5 超级快对象 超级块操作 6 索引节点对象 索引节点操作 7 目录项对象 目录项 ...

  6. linux 文件系统路径,Linux编程 1 (文件系统路径说明, 目录结构说明)

    一. Linux文件系统路径说明 熟悉windows系统的,都知道文件路径表示,如C:\User\rich\Documnets\test.doc. 在linux中目录称为虚拟目录(virtual di ...

  7. linux文件系统体系结构 和 虚拟文件系统(VFS)

    图 1. Linux 文件系统组件的体系结构 用户空间包含一些应用程序(例如,文件系统的使用者)和 GNU C 库(glibc),它们为文件系统调用(打开.读取.写和关闭)提供用户接口.系统调用接口的 ...

  8. linux c 判断路径是 目录还是文件

    主要函数: stat(),opendir(),readdir(), 主要结构体:struct dirent  和 struct stat 主要宏:S_ISDIR(),     S_ISREG() 函数 ...

  9. linux C传入路径递归创建目录和文件接口实现

    本文封装了C 传入路径递归创建目录和文件接口实现,文末有提供示例代码: eg:传入./dir1/dir2/dir3/dir4/file0 可自动在当前目录创建dir1/dir2/dir3/dir4/四 ...

最新文章

  1. 人工智能产业发展深度报告:格局、潜力与展望
  2. 无法对jar进行签名,Android jar signer问题
  3. java finalize逃脱_关于Java中的finalize()方法
  4. Python函数之初体验
  5. 计算机与数学文化论文参考文献,数学文化与人类文明论文.doc
  6. IEnumerable.EachTSource(FuncTSource, TSource predicate) 逐个更改列表成员的值
  7. Base64编码解码
  8. TDSQL 安装部署(多图预警)
  9. sql server alter权限_SQL
  10. vue源码解析推荐文章
  11. 手把手教你用Vue.js封装Form组件
  12. 使用libevhtp搭建HTTPS SERVER(单向验证身份)
  13. android 重新点击图标显示不出来了,android开发怎么弄成,点击图标后弹出一个消息框。主界面不显示...
  14. 开通写scdn博客第一天
  15. armbian php7.1_N1 + armbian+宝塔面板+apache+MySQL+php
  16. python 等值线_绘图系列(1):利用matplotlib绘制等值线图
  17. 今日运势 酷q_《意大利grand老妇人》电影_意大利grand老妇人老版国语字幕-内蒙古呼和浩特铁路预防职务犯协会...
  18. 2019西电复试计科,软件机试真题
  19. 计算机组成原理笔试,农村信用社招聘笔试--计算机组成原理重点总结.doc
  20. python统计套利

热门文章

  1. Python学习笔记(7):操作Excel
  2. 3D立体建模的分类:实体建模和表面建模
  3. ASP.NET MVC实现Excel文件的上传下载
  4. 基于RFID的仓储管理系统的设计与实现-毕业论文
  5. Lua manual翻译——第三章第七、八、九节
  6. 2021-06-13Leetcode79.单词搜索
  7. 《Java程序设计》课堂实践内容总结
  8. 2021年安全生产模拟考试(全国特种作业操作证焊工作业-熔化焊接与热切割模拟考试题库二)
  9. 机票垂直搜索引擎之性能优化
  10. Python自动发邮件总结及说明