上文介绍了解析文件路径名的一个通体的过程,这里再把其中的一些细节拿出来进行分析。首先对于文件名的特点,可以分为三类:普通文件名,'.'和'..',对于'.'的处理很简单,因为它表示当前目录,因此直接通过continue进入下一轮查找即可,对于'..',也就是退回到父目录,本身也不是一件难事,但是这里要考虑到几个特殊情况,先看看内核处理'..'的方法:
static __always_inline void follow_dotdot(struct nameidata *nd)
{
set_root(nd);
while(1) {
struct vfsmount *parent;
struct dentry *old = nd->path.dentry;
/*如果当前所处的目录即为根目录则break*/
if (nd->path.dentry == nd->root.dentry &&
nd->path.mnt == nd->root.mnt) {
break;
}
spin_lock(&dcache_lock);
//如果当前所处的目录不为当前路径所属文件系统的根目录,也就是说可以直接向上退一级
if (nd->path.dentry != nd->path.mnt->mnt_root) {
nd->path.dentry = dget(nd->path.dentry->d_parent);//当前的目录退到上一级
spin_unlock(&dcache_lock);
dput(old);
break;
}
/*下面的情况对应于当前所处的目录为文件系统的根目录*/
spin_unlock(&dcache_lock);
spin_lock(&vfsmount_lock);
parent = nd->path.mnt->mnt_parent;//取父文件系统
if (parent == nd->path.mnt) {//父文件系统即为本身,则表明没有父文件系统,直接break
spin_unlock(&vfsmount_lock);
break;
}
mntget(parent);//增加父文件系统的引用计数
nd->path.dentry = dget(nd->path.mnt->mnt_mountpoint);//取当前文件系统的挂载点,这样就退回到了父文件系统
spin_unlock(&vfsmount_lock);
dput(old);
mntput(nd->path.mnt);
nd->path.mnt = parent;//设置当前路径的mnt为父文件系统
}
/*一般情况下,前面的操作可以保证返回到上级目录,但是有一种情况就是
当前目录的上级目录有可能还挂载了其他的文件系统,这样会隐藏之前的文件系统,
follow_mount()用来处理这种情况*/
follow_mount(&nd->path);
}
while循环里面的路径可以分为三种:
1.当前目录为nd中已经预设好的根目录,也就是说无法再向上退一层了,这种情况直接break
2.当前目录不为所属文件系统的根目录,这种情况是最常见的,可以向上退一层
3.当前目录为所属文件系统的挂载点,这种情况下,后退一层的话则会进入到父文件系统中,所以先要做一个文件系统的交换,再通过while(1)循环回到前面两种情况
在一般情况下while(1)循环中的内容可以保证正确的退到父目录,但是考虑一种情况就是,当用户进入了一个目录后,其父目录上又重新挂载了一个文件系统,这时新的文件系统会覆盖旧的文件系统,使得之前的内容都被隐藏,因此这时要后退到上级目录则不是退回到原本所属的文件系统的目录了,而是退回到了最新的那个文件系统的挂载点。下面的一个例子可以用来说明这种情况:
1. 通过mkdir -p /mnt/test在/mnt目录下创建一个test目录
2. cd /mnt/test
3. ls .. 这时可以看到我们后退到的目录对应的是原文件系统,因此显示的是test
4. mount /dev/cdrom /mnt
5.ls .. 这时因为重新挂载了一个文件系统,因此test对应的文件系统被覆盖,所以显示的内容是cdrom根目录下的内容而看不到test了。
follow_mount()函数就是用来解决这么一个问题,即保证后退(或者前进)的目录是最新的那个文件系统对应的目录
static void follow_mount(struct path *path)
{
while (d_mountpoint(path->dentry)) {//目录下有文件系统被安装
struct vfsmount *mounted = lookup_mnt(path);//找到最先被挂载的子文件系统
if (!mounted)//如果mounted为0,也就表示之前处理的子文件系统是最后一个子文件系统了,
break; //这个文件系统的mnt才是所要返回的上级目录的真正mnt
dput(path->dentry);
mntput(path->mnt);
path->mnt = mounted;//保存vfsmount
path->dentry = dget(mounted->mnt_root);//保存dentry,并更新引用计数
}
}
分享到:
相关推荐
Linux虚拟文件系统方面的分析 主要是源代码的注释、原理分析,内核版本为2.6.32
Linux 基础 26-文件和目录命令-08-相对路径和绝对路径.flv
Linux 刚刚开始学,挺实用的。Linux-C++-遍历指定文件夹路径下的文件列表并将路径写到txt文件。 如果没有积分,请私信我留下邮箱,我会尽快发过去
C#路径-文件-目录-I-O常见操作汇总
Linux操作系统基础
第一步:将arm-linux-gcc-4.3.2.bz2拷贝到虚拟机的任意目录 第二步:查看当前系统是否支持arm-linux-gcc 如果不存在 则继续如下步骤: 第三步:在/usr/local创建一个文件夹为arm mkdir /usr/local/arm 第四步:将arm...
2.模拟Linux文件系统,功能如下: (1)info: 显示整个系统信息 (2)cd …: 改变目录:改变当前工作目录,目录不存在时给出出错信息。 (3)dir …: 显示目录:显示指定目录下或当前目录下的信息,包括文件名、物理地址、...
Linux-修改-Mysql-数据库-存放路径
linux根文件系统的目录以及相关文件的说明
系统工具-文件下载-谷歌浏览器缓存路径修改 1.0.zip
2 虚拟文件系统架构 11 2.1 VFS对象数据结构 11 2.1.1 超级块对象 11 2.1.2 索引节点对象 15 2.1.3 文件对象 18 2.1.4 目录项对象 22 2.2 把Linux中的VFS对象串联起来 24 2.2.1 与进程相关的文件 25 2.2.2 索引节点...
还支持host文件系统与模拟Linux文件系统间的文件拷贝,host文件系统的文件命名为…,如:将windows下D:盘的文件\data\sample\test.txt文件拷贝到模拟Linux文件系统中的/test/data目录,windows下D:盘的当前目录为D...
cd 目录名(路径名) 切换当前目录到指定目录 mkdir 目录名 在当前目录创建新目录 rmdir 目录名 在当前目录删除指定目录 create 文件名 在当前目录下创建指定文件 rm 文件名 在当前目录下删除指定...
放置到`openarkcompiler/tools`目录,打开`openarkcompiler/build/config/BUILDCONFIG.gn`文件,将`GN_C_COMPILER`、`GN_CXX_COMPILER`和`GN_AR`三个变量配置为Clang编译器所在路径,例如: ``` GN_C_COMPILER = "$...
matlab开发-父路径返回路径共享的多个子路径。返回由多个子路径共享的文件系统路径
--WisFileRead.transformWisToCsv(String inputFile,String outPutPath) --单wis文件转csv ... --outPutPath --解析结果输出路径 --F:\\wisout --sourceFolderPath--批量wis文件所在目录--F:\\wis
目录名和文件名支持全路径名和相对路径名,路径名各分量间用“/”隔开。 (2) 改变目录:改变当前工作目录,目录不存在时给出出错信息。 (3) 显示目录:显示指定目录下或当前目录下的信息,包括文件名、物理地址、...
用系统提供的API编程实现文件系统中相关操作的对应命令,相关命令具体如下所示: -mkdir : 创建一个或多个目录; -rmdir: 删除一个或多个目录; -ls: 列出当前目录下个文件 -mvdir: 目录改名和移动...
C# 路径-文件-目录常见操作汇总 文件操作是程序中非常基础和重要的内容,而路径、文件、目录以及I/O都是在进行文件操作时的常见主题,这里想把这些常见的问题作个总结,对于每个问题, 尽量提供一些解决方案,即使...
这是一个用于获取指定目录下所有文件的信息的C++代码, 是用于linux系统的