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()--追踪符号链接,在下篇文章再拿出来进行具体分析。
linux 进入文件系统路径,Linux虚拟文件系统--文件路径名的解析(1)--整体过程相关推荐
- 十年码农讲解Linux型内核,操作系统 --- 虚拟文件系统
1.虚拟文件系统的分层结构 上层:虚拟文件系统 底层:特定文件系统模块,例如:网络文件系统(nfs.smb)等其他类型文件系统 虚拟文件系统的目的:将接口暴露给用户,屏蔽底层文件系统的差异性,它是对所 ...
- linux 虚拟文件系统 源码,Linux内核源代码情状分析-虚拟文件系统
Linux内核源代码情景分析-虚拟文件系统 我们先来看两张图: 第一张是VFS与具体文件系统的关系示意图: 第二张是Linux文件系统的层次结构: 特殊文件:用来实现"管道"的文件 ...
- Linux文件系统二(虚拟文件系统VFS实现原理)
创作人QQ:851301776,邮箱:lfr890207@163.com 欢迎大家一起技术交流,本博客主要是自己学习的心得体会,只为每天进步一点点! 个人座右铭: 1 ...
- Linux套接字与虚拟文件系统
引言 在Unix的世界里,万物皆文件,通过虚拟文件系统VFS,程序可以用标准的Unix系统调用对不同的文件系统,甚至不同介质上的文件系统进行读写操作.对于网络套接字socket也是如此,除了专属 ...
- Linux内核设计与实现---虚拟文件系统
虚拟文件系统 1 通用文件系统 2 文件系统抽象层 3 Unix文件系统 4 VFS对象及其数据结构 其他VFS对象 5 超级快对象 超级块操作 6 索引节点对象 索引节点操作 7 目录项对象 目录项 ...
- linux 文件系统路径,Linux编程 1 (文件系统路径说明, 目录结构说明)
一. Linux文件系统路径说明 熟悉windows系统的,都知道文件路径表示,如C:\User\rich\Documnets\test.doc. 在linux中目录称为虚拟目录(virtual di ...
- linux文件系统体系结构 和 虚拟文件系统(VFS)
图 1. Linux 文件系统组件的体系结构 用户空间包含一些应用程序(例如,文件系统的使用者)和 GNU C 库(glibc),它们为文件系统调用(打开.读取.写和关闭)提供用户接口.系统调用接口的 ...
- linux c 判断路径是 目录还是文件
主要函数: stat(),opendir(),readdir(), 主要结构体:struct dirent 和 struct stat 主要宏:S_ISDIR(), S_ISREG() 函数 ...
- linux C传入路径递归创建目录和文件接口实现
本文封装了C 传入路径递归创建目录和文件接口实现,文末有提供示例代码: eg:传入./dir1/dir2/dir3/dir4/file0 可自动在当前目录创建dir1/dir2/dir3/dir4/四 ...
最新文章
- 人工智能产业发展深度报告:格局、潜力与展望
- 无法对jar进行签名,Android jar signer问题
- java finalize逃脱_关于Java中的finalize()方法
- Python函数之初体验
- 计算机与数学文化论文参考文献,数学文化与人类文明论文.doc
- IEnumerable.EachTSource(FuncTSource, TSource predicate) 逐个更改列表成员的值
- Base64编码解码
- TDSQL 安装部署(多图预警)
- sql server alter权限_SQL
- vue源码解析推荐文章
- 手把手教你用Vue.js封装Form组件
- 使用libevhtp搭建HTTPS SERVER(单向验证身份)
- android 重新点击图标显示不出来了,android开发怎么弄成,点击图标后弹出一个消息框。主界面不显示...
- 开通写scdn博客第一天
- armbian php7.1_N1 + armbian+宝塔面板+apache+MySQL+php
- python 等值线_绘图系列(1):利用matplotlib绘制等值线图
- 今日运势 酷q_《意大利grand老妇人》电影_意大利grand老妇人老版国语字幕-内蒙古呼和浩特铁路预防职务犯协会...
- 2019西电复试计科,软件机试真题
- 计算机组成原理笔试,农村信用社招聘笔试--计算机组成原理重点总结.doc
- python统计套利