Linux中文件名解析处理源码分析
- static struct file *path_openat(int dfd, const char *pathname,
- struct nameidata *nd, const struct open_flags *op, int flags)
- {
- struct file *base = NULL;
- struct file *filp;
- struct path path;
- int error;
- /* 创建一个file对象 */
- filp = get_empty_filp();
- if (!filp)
- return ERR_PTR(-ENFILE);
- filp->f_flags = op->open_flag;
- nd->intent.open.file = filp;
- nd->intent.open.flags = open_to_namei_flags(op->open_flag);
- nd->intent.open.create_mode = op->mode;
- /* 初始化检索的起始目录,判断起始目录是根目录还是当前目录,并且初始化nd->inode对象,为link_path_walk函数的解析处理做准备。 */
- error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base);
- if (unlikely(error))
- goto out_filp;
- current->total_link_count = 0;
- /* 关键的字符串解析处理函数,其核心思想是分级解析字符串,通过字符串对应的目录项找到下一级目录的inode节点。该函数的具体分析如下。 */
- error = link_path_walk(pathname, nd);
- if (unlikely(error))
- goto out_filp;
- /* do_last函数创建或者获取文件对应的inode对象,并且初始化file对象,至此一个表示打开文件的内存对象filp诞生 */
- filp = do_last(nd, &path, op, pathname);
- while (unlikely(!filp)) { /* trailing symlink */
- struct path link = path;
- void *cookie;
- if (!(nd->flags & LOOKUP_FOLLOW)) {
- path_put_conditional(&path, nd);
- path_put(&nd->path);
- filp = ERR_PTR(-ELOOP);
- break;
- }
- nd->flags |= LOOKUP_PARENT;
- nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
- error = follow_link(&link, nd, &cookie);
- if (unlikely(error))
- filp = ERR_PTR(error);
- else
- filp = do_last(nd, &path, op, pathname);
- put_link(nd, &link, cookie);
- }
- out:
- if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT))
- path_put(&nd->root);
- if (base)
- fput(base);
- release_open_intent(nd);
- return filp;
- out_filp:
- filp = ERR_PTR(error);
- goto out;
- }
link_path_walk函数完成了基本的名字解析功能,是名字字符串解析处理实现的核心。该函数的实现基于分级解析处理的思想。例如,当需要解析“/dev/mapper/map0”字符串时,其首先需要判断从何处开始解析?根目录还是当前目录?案例是从根目录开始解析,那么获取根目录的dentry对象并开始分析后继字符串。以’/’字符为界按序提取字符串,首先我们可以提取”dev”字符串,并且计算该字符串的hash值,通过该hash值查找detry下的inode hash表,就可以得到/dev/目录的inode对象。依次类推,最后解析得到”/dev/mapper/”目录的inode对象以及文件名”map0”。至此,link_path_walk函数的使命完成,最后可以通过do_last函数获取或者创建文件inode。link_path_walk函数分析如下:
- static int link_path_walk(const char *name, struct nameidata *nd)
- {
- struct path next;
- int err;
- /* 移除’/’字符 */
- while (*name=='/')
- name++;
- /* 如果解析已经完成,直接返回 */
- if (!*name)
- return 0;
- /* At this point we know we have a real path component. */
- for(;;) {
- unsigned long hash;
- struct qstr this;
- unsigned int c;
- int type;
- /* inode访问的permission检查 */
- err = may_lookup(nd);
- if (err)
- break;
- this.name = name;
- c = *(const unsigned char *)name;
- /* 初始化hash值 */
- hash = init_name_hash();
- do {
- name++;
- /* 累计计算名字字符串的hash值 */
- hash = partial_name_hash(c, hash);
- c = *(const unsigned char *)name;
- /* 如果遇到’/’字符,结束一次hash计算统计 */
- } while (c && (c != '/'));
- /* 得到字符串长度和hash结果 */
- this.len = name - (const char *) this.name;
- this.hash = end_name_hash(hash);
- type = LAST_NORM;
- /* LAST_DOT和LAST_DOTDOT情形判断 */
- if (this.name[0] == '.') switch (this.len) {
- case 2: /* LAST_DOTDOT是上级目录 */
- if (this.name[1] == '.') {
- type = LAST_DOTDOT;
- nd->flags |= LOOKUP_JUMPED;
- }
- break;
- case 1: /* LAST_DOT是当前目录 */
- type = LAST_DOT;
- }
- if (likely(type == LAST_NORM)) {
- /* LAST_NORM标记说明是需要通过本地目录进行字符串解析 */
- struct dentry *parent = nd->path.dentry;
- nd->flags &= ~LOOKUP_JUMPED;
- if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
- /* 如果该标记有效,需要重新计算hash值 */
- err = parent->d_op->d_hash(parent, nd->inode,
- &this);
- if (err < 0)
- break;
- }
- }
- /* 如果字符串已经解析完毕,直接跳转到last_component */
- /* remove trailing slashes? */
- if (!c)
- goto last_component;
- while (*++name == '/');
- if (!*name)
- goto last_component;
- /* 通过walk_component函数找到解析字符串对应的inode,并且将nd->inode改称最新inode,准备继续解析后面的字符串信息。因为目录项所管理的inode在系统中通过hash表进行维护,因此,通过hash值可以很容易的找到inode。如果内存中还不存在inode对象,对于ext3文件系统会通过ext3_lookup函数从磁盘上获取inode的元数据信息,并且构造目录项中所有的inode对象。 */
- err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW);
- if (err < 0)
- return err;
- if (err) {
- err = nested_symlink(&next, nd);
- if (err)
- return err;
- }
- if (can_lookup(nd->inode))
- continue;
- /* 字符串还没有解析完毕,但是当前的inode已经继续不允许解析处理了,所以,返回错误码 */
- err = -ENOTDIR;
- break;
- /* here ends the main loop */
- last_component:
- /* 最后一个字符串不需要解析处理,需要由do_last函数来处理,此处结束解析,正确返回 */
- nd->last = this;
- nd->last_type = type;
- return 0;
- }
- terminate_walk(nd);
- return err;
- }
小结
转载于:https://blog.51cto.com/alanwu/1120652
Linux中文件名解析处理源码分析相关推荐
- linux源码文件名,Linux中文件名解析处理源码分析
Linux中文件名解析处理源码分析 前言 Linux中对一个文件进行操作的时候,一件很重要的事情是对文件名进行解析处理,并且找到对应文件的inode对象,然后创建表示文件的file对象.在此,对文件名 ...
- (转)Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义
1.从Spring2.0以后的版本中,Spring也引入了基于注解(Annotation)方式的配置,注解(Annotation)是JDK1.5中引入的一个新特性,用于简化Bean的配置,某些场合可以 ...
- Go语言中间件框架 Negroni 的静态文件处理源码分析
Negroni是一个非常棒的中间件,尤其是其中间件调用链优雅的设计,以及对GO HTTP 原生处理器的兼容.我以前写过两篇文章,对Negroni进行了专门的分析,没有看过的朋友可以在看下. Go语言经 ...
- Hbase 预写日志WAL处理源码分析之 LogCleaner
Hlog WALs和oldWALs 这里先介绍一下Hlog失效和Hlog删除的规则 HLog失效:写入数据一旦从MemStore中刷新到磁盘,HLog(默认存储目录在/hbase/WALs下)就会自动 ...
- Hbase 预写日志WAL处理源码分析之 LogCleaner
目录 Hlog WALs和oldWALs 整体流程 HMaster 初始化 定时执行 LogCleaner 日志清理类 ReplicationLogCleaner 日志清理类 总结 Hlog WA ...
- Linux内核 eBPF基础:kprobe原理源码分析:源码分析
Linux内核 eBPF基础 kprobe原理源码分析:源码分析 荣涛 2021年5月11日 在 <Linux内核 eBPF基础:kprobe原理源码分析:基本介绍与使用>中已经介绍了kp ...
- Linux内核 eBPF基础:kprobe原理源码分析:基本介绍与使用示例
Linux内核 eBPF基础 kprobe原理源码分析:基本介绍与使用示例 荣涛 2021年5月11日 kprobe调试技术是为了便于跟踪内核函数执行状态所设计的一种轻量级内核调试技术. 利用kpro ...
- Linux内核 eBPF基础:Tracepoint原理源码分析
Linux内核 eBPF基础 Tracepoint原理源码分析 荣涛 2021年5月10日 1. 基本原理 需要注意的几点: 本文将从sched_switch相关的tracepoint展开: 关于st ...
- 动态代理原理源码分析
看了这篇文章非常不错转载:https://www.jianshu.com/p/4e14dd223897 Java设计模式(14)----------动态代理原理源码分析 上篇文章<Java设计模 ...
- Hhadoop-2.7.0中HDFS写文件源码分析(二):客户端实现(1)
一.综述 HDFS写文件是整个Hadoop中最为复杂的流程之一,它涉及到HDFS中NameNode.DataNode.DFSClient等众多角色的分工与合作. 首先上一段代码,客户端是如何写文件的: ...
最新文章
- MySQL 唯一索引 UNIQUE KEY 会导致死锁?
- java与json,java与json
- 【Python】matplotlib基础:数据可视化
- linux distribution timeline
- Ross《随机过程》(第二版)装填问题Python模拟实验
- 机器学习——决策树的三种学习方法
- 用python编辑word_使用PYTHON编辑和读取WORD文档
- 今天看到头条好多新手说摆摊不挣钱
- centos 6.8安装git_Centos(6/7)安装GitLab超详细教程
- Spark函数讲解: combineByKey
- 点云的无序性_三维点云分类与分割-PointNet
- java允许跨域设置
- 数学建模——粒子群优化算法(PSO)【有详细样例 + 工具:matlab】(万字总结)
- JQuery提交表单
- citypicker城市选择+高德定位,城市编码统一设置
- python哈希类型_Python散列类型和运算符
- 07年中国企业500强名单
- MATLAB与STK互联46:在场景中加入某个国家作为Area Target对象(GIS命令使用)
- 利用python与requests爬取猫眼上的电影数据
- java字符串转数组(JAVA把字符串转化为数组)