Linux中文件名解析处理源码分析

前言

Linux中对一个文件进行操作的时候,一件很重要的事情是对文件名进行解析处理,并且找到对应文件的inode对象,然后创建表示文件的file对象。在此,对文件名解析过程,并且如何找到对应inode的过程进行源码分析。分析代码基于Linux-3.2版本。

关键函数分析

不管是通过应用层的API函数还是在内核中打开一个文件,最终都需要调用filp_open函数,该函数的主要职责就是解析文件名,找到文件对应的inode对象,然后分配内存创建file对象,最后执行该文件对应的file->open函数。

filp_open的核心处理函数是path_openat,该函数分析如下:

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;

}

小结

文件名解析处理是文件系统的必备功能,通过文件名的解析索引到表示文件的inode内存对象,并且创建文件对象file。在文件名解析的过程中,首先需要确定的是检索起始点,然后通过hash table查找目录项以及检索文件。在查找的过程中,需要考虑文件访问的权限以及符号连接等问题。总体来说这些代码难度不是很大,但是需要有一个整体的思路,就可以更好的理解分析代码了,这里只是对名字解析过程中的几个关键函数进行抛砖引玉式的分析。不正之处,敬请指出。

linux源码文件名,Linux中文件名解析处理源码分析相关推荐

  1. 【老生谈算法】matlab实现灰度图处理源码——灰度图处理

    matlab灰度图的处理源码 1.文档下载: 本算法已经整理成文档如下,有需要的朋友可以点击进行下载 序号 文档(点击下载) 本项目文档 [老生谈算法]matlab灰度图的处理程序.doc 2.算法详 ...

  2. js 将微信二维码转为url,qrcodeJs解析二维码,qrcode.decode is not a function报错

    前言 工作中遇到的需求:用户上传相册中选中的图片,判断这个图片里的二维码是不是微信二维码,如果是则上传到服务器:不是,则提示用户重新上传. 百度了下,qrcode.js是一个用于生成二维码的 Java ...

  3. ACM试题 - ASCII码排序 - Java中字符与对应ASCII码的转换

    Java中字符转换对应ASCII码有两种方式: 第一种: char c = 'a'; byte b = (byte)c; // b=97 第二种: char c = 'a'; int b = c; / ...

  4. ZXing 二维码库之生成与解析二维码

    博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载.本文由博主 威威喵 原创,请多支持与指教. 本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/ ...

  5. (转)Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义

    1.从Spring2.0以后的版本中,Spring也引入了基于注解(Annotation)方式的配置,注解(Annotation)是JDK1.5中引入的一个新特性,用于简化Bean的配置,某些场合可以 ...

  6. linux下反向解析文件的权限应该是什么,Linux 下的DNS服务器中,反向解析文件的内容包括( )...

    [判断题]内部排序是指排序过程在内存中进行的排序.( ) [多选题]当事人有确切证据证明对方有下列情形之一( )可以实施不安抗辩权的. [多选题]机能主义的代表人物的是: [判断题]知能类知识和知人类 ...

  7. php 模糊文件名链接,推荐10款模糊处理源码(收藏)

    本文实例讲述了php使用高斯算法实现图片的模糊处理功能.分享给大家供大家参考,具体如下:<?php class image_blur{ function gaussian_blur($srcIm ...

  8. vb6源码 ymodem_任意字符的ASCII码转换工具,基于VB6的源代码VB字符串处理源码下载...

    内容索引:VB源码,字符措置惩罚,ASCII,字符转换 任意字符的ASCII码转换工具,鉴于VB6的源代码,能够把任意字符(数字.字母.汉字)转化成ascii码,也能够把ascii码还原成最初的字符. ...

  9. java 德文转码_web开发中的JAVA字符转码

    二.基本概念 2.1 JAVA中字符的表达 JAVA中有char.byte.String这几个概念. char 指的是一个UNICODE字符,为16位的整数.java抓取网页保存的乱码问题解决 byt ...

最新文章

  1. ESXi6.5环境搭建(一:VMware Workstations 12 Pro 环境的安装及配置)
  2. C4.5决策树 此博文包含图片 (2011-10-20 23:22:19)转载▼ 标签: 分类树
  3. 使用myeclipse创建带注解的model实体类
  4. socket编程流程与函数(实用篇)
  5. 【VS C++ 2010】查看内存的方法详解
  6. iis设置导致python调用urllib.request.urlopen出错问题
  7. go read text file into string array
  8. 113_Power Pivot 销售订单之重复购买率及购买间隔天数相关
  9. jenkins 备份配置信息
  10. 腾讯面试Android高级岗。居然被一个多线程基础面倒了?
  11. 经典神经网络 -- ResNet : 设计原理与pytorch实现
  12. dpkg-buildpackage: error: debian/rules binary subprocess was killed by signal 2
  13. 中行网银安全控件 v1.0 官方版
  14. oppo9s刷机教程_OPPO R9s刷机教程_OPPO R9s卡刷升级更新官方系统包
  15. 固态硬盘接口类型介绍
  16. 动名词到底什么时候才用? ———— 英语菜鸟最后的倔强!
  17. 《当程序员的那些狗日日子》(五十三)破局(中)
  18. 数学之美阅读笔记(1)
  19. WinXP/Win2003系统ISO镜像文件PE安装步骤
  20. CMake | include_guard命令详解

热门文章

  1. 「拨云见日」英特尔揭秘短视频背后的二三事
  2. java jndi使用_Java项目中使用JNDI连接数据库
  3. python冒泡排序实验报告_python中的冒泡排序
  4. 什么叫做石英表_石英表 是什么意思??
  5. uniapp 封装网络请求
  6. Linux7/Redhat7/Centos7 安装Oracle 12C_配置VNC远程安装数据库_03
  7. 项目管理过程组和知识领域 简介重点记忆
  8. Centos7 安装maven
  9. gblfy_IDEA常用快捷键技巧
  10. python迷宫小游戏大全_Python迷宫小游戏源代码、源程序