Coder
分类: LINUX
2010-07-30 21:07:27
link_path_walk()对于路径名最后一个分量的处理
此时,除了最后一个分量,原路径名的所有分量都已被解析。再来了解一下这时的环境,局部变量inode保存有父路径的目录的inode地址,nd->flags被设置了LOOKUP_CONTINUE标志,已经调用exec_permission(inode)对于父路径目录的执行权限进行了检查并通过。局部变量this中保存有最后一个分量的文件名信息,包括哈希值等,lookup_flags被设置了合适的标志值。link_path_walk()对于路径名最后一个分量的处理执行如下操作:
1、如果路径名是一反斜线“/”结尾的,则设置lookup_flags标志的LOOKUP_FOLLOW和LOOKUP_DIRECTORY位,以说明要查找的一定要是一个目录。
2、清除nd->flags中的LOOKUP_CONTINUE标志。
3、检查lookup_flags变量中LOOKUP_PARENT标志的值。如果没有设置此值,则说明它不是一个父路径名查找。此时执行如下操作:
a. 检查路径名最后一个分量的文件名字,如果最后一个分量名是“.”(单个圆点),这是对当前目录的引用,所要查找的值此时已经保存在nd中了。则检查文件系统的FS_REVAL_DOT标志(始终在目录项高速缓存中使“.”和“..”路径重新生效(针对网络文件系统)),若没有设置,则终止执行并返回值0(无错误);若设置了该标志,则调用方法nd-> path.dentry->
d_op-> d_revalidate(nd->path.dentry, nd) ,这个方法在把目录项对象转换为一个文件路径名之前,判定该目录项对象是否仍然有效。大多数文件系统将它设置为NULL,而网络文件系统可以指定自己的函数,若仍然有效,则link_path_walk()返回值0(无错误),若无效,则返回ESTALE。
回忆一下,link_path_walk()的调用者path_walk()对于这个返回值的处理是设置nd->path(保存有要查找的路径名的基路径)为之前保存的路径值,重新设置current->total_link_count为0,设置nd->flags的LOOKUP_REVAL标志(link_path_walk()更底层的do_lookup会适当处理这个标志),重新调用link_path_walk()。
b. 如果最后一个分量名是“..”(两个圆点),则做跟前面说明的相似的工作,尝试回到父目录。之后检查文件系统的FS_REVAL_DOT标志(始终在目录项高速缓存中使“.”和“..”路径重新生效(针对网络文件系统)),若没有设置,则终止执行并返回值0(无错误);若设置了该标志,则调用方法nd-> path.dentry->
d_op-> d_revalidate(nd->path.dentry, nd) ,这个方法在把目录项对象转换为一个文件路径名之前,判定该目录项对象是否仍然有效。大多数文件系统将它设置为NULL,而网络文件系统可以指定自己的函数,若仍然有效,则link_path_walk()返回值0(无错误),若无效,则返回ESTALE。与上一种情况的最后处理一样。
c. 最后的分量名既不是“.”,也不是“..”,调用do_lookup(nd, &this, &next)(878行),得到与给定的父目录(nd->path)和文件名(要解析的路径名分量&this)相关的目录项对象,存放在结果参数next中。后面“do_lookup()路径名查找”会有更详细的说明。
d.检查刚解析的分量是否指向一个符号链接(next.dentry->d_inode具有一个i_op->follow_link方法)。如果是则调用do_follow_link(&next,
nd)做相应的处理。将在后面“符号链接的查找”有更详细的说明。
e. 刚解析的分量不是指向一个符号链接调用path_to_nameidata(&next,
nd),把nd->path.dentry和nd->path.mnt分别置为next.dentry和next.mnt,然后继续路径名的下一个分量。
f.检查lookup_flags的LOOKUP_DIRECTORY标志,若设置了该标志,则检查最后返回的路径指向的是否是一个目录,若是,则返回0;若不是则返回ENOENT。
lookup_flags的LOOKUP_DIRECTORY标志则直接返回0。
4、在很多情况下,查找操作的真正目的并不是路径名的最后一个分量,而是最后一个分量的前一个分量。例如,当文件被创建时,最后一个分量表示还不存在的文件的
文件名,而路径名中的其余路径指定新链接必须插入的目录。因此,查找操作应当取回最后分量的前一个分量的目录项对象。另举一个例子,我们执行rm -f /foo/bar,这里路径名/foo/bar表示的文件bar拆分出来就包含从其目录foo中移去bar。因此,内核真正的兴趣在于访问文件目录foo 而不是bar。
当查找操作必须解析的是包含路径名最后一个分量的目录而不是最后一个分量本身时,就使用LOOKUP_PARENT标志。当LOOKUP_PARENT标志被设置时,link_path_walk()函数也在nameidata数据结构中建立last和last_type字段。last字段存放路径名中的最后一个分量名。
ast_type字段标识最后一个分量的类型;可以把它置为如下所示的值之一:
LAST_NORM:最后一个分量是普通文件名
LAST_ROOT:最后一个分量是“/”(也就是整个路径名为“/”)
LAST_DOT:最后一个分量是“.”
LAST_DOTDOT:最后一个分量是“..”
LAST_BIND:最后一个分量是链接到特殊文件系统的符号链接
当整个路径名的查找操作开始时,LAST_ROOT标志是由path_lookup()设置的缺省值。如果路径名正好是“/”,则内核不改变last_type字段的初始值。last_type字段的其他值在LOOKUP_PARENT标志置位时由link_path_walk()设置
LOOKUP_PARENT标志的值,如果被置位则执行如下操作:
a. 把nd->last置为最后一个分量名。
b. 把nd->last_type初始化为LAST_NORM。
c. 如果最后一个分量名为“.”(一个圆点),则把nd->last_type置为LAST_DOT。
d. 如果最后一个分量名为“..”(两个圆点),则把nd->last_type置为LAST_DOTDOT
e. 通过返回值0(无错误)终止。
可以看到,最后一个分量根本就没有被解释。因此,当函数终止时,nameidata数据结构的dentry和mnt字段指向最后一个分量所在目录对应的对象。