文件系统内部机构(4)

5. UNIX 目录

UNIX目录类似于前面介绍的符号文件目录(SFD)。如前所示,UNIX中的索引节点扮演了和基本文件目录(BFD)条目的相同角色。UNIX目录包括目录下的文件以及子目录的条目。每个条目包括一个符号文件或子目录名以及对应的索引节点号,如图13-6所示。每个条目16个字节长:14个字节用于文件名,2个字节用于索引节点号(这与具体的实现相关)。

6. 路径名解析

本书在符号文件目录(SFD)和基本文件目录(BFD)一节中已经讨论过解析路径名的方法。现在以UNIX的另一个例子重新诠释这个概念。想象一下路径"../x/y"从当前目录开始,一直到父目录,也就是路径名中的"..",到父目录中的另一个目录"x",从而最终到达目录"x"中名字为"y"的文件。

UNIX执行下面的步骤遍历该路径(参考图13-20)。图中的步骤(i~xi)对应下面的步骤(1)到(11)。

① 内核访问u区(u区类似于该进程的PCB),其中存储了当前目录。可以将其作为绝对路径名或当前目录的索引节点存储。无论哪一种情况,如果没有明确指明,那么可以通过相同的算法得到当前目录的索引节点号,下述从根目录(/)开始。

② 现在内核访问当前目录的索引节点。

③ 索引节点把分配给当前目录的"文件"的磁盘块链接在一起。索引节点将它们作为直接块(0到9)和不同级别索引的间接块列出。内核检查它们,并实际读取内存中的当前目录文件。

④ 目录有一个预先定义的格式,例如,本例中它有16个字节的条目。内核现在搜索作为目录中符号名的".."条目。SFD的格式参见图13-6。内核解析相对路径名并一直提取到下一个"/"内容为止。路径名是"../x/y"。因此,一开始,这个解析过程产生"..",".."指明父目录。每个目录有一个"."条目,表明当前目录,以及另一个".."条目,它表示父目录(参见图13-6)。

⑤ 内核使用该条目为".."从当前目录中提取出父目录的索引节点号。

⑥ 内核访问父目录的索引节点,并通过再次检索该文件的直接/间接数据块读取有关该父目录的实际内容。

⑦ 现在内核在父目录中搜索符号文件名"x"。这是内核解析相对路径名到下一个"/"后得到的符号名。

⑧ 现在,内核从父目录中提取目录"x"的索引节点,并如前一样读取该目录的内容。

⑨ 现在,内核在目录"x"中搜索符号文件名"y"。这种情况下,这是内核在解析到下一个"/"或相对路径名的结尾处得到的名称。

⑩ 对"y"提取索引节点号,并取回该索引节点。

现在,可以读取文件"y"或是对其进行其他任意操作。可以对数据块在索引节点中使用直接地址和间接地址从而完成该工作。

 
图13-20  路径名解析步骤

7. UNIX中的ACL

诚如所知,系统管理员为每个用户分配一个用户名,假定该用户在登录系统时输入这个用户名。系统在创建用户的时候,在内部为用户名分配唯一一个被称作用户id(uid)的数字。这些uid及其用户名也由系统存储在/etc/passwd文件中以备将来引用。

除了用户id(uid)之外,UNIX还有一个组id(gid)的概念。典型的,如果项目需要15个程序员,那么所有的15个程序员有不同的uid,但他们可以有相同的gid。一个用户可以只属于一个组。这两者(uid,gid)的组合构成域。对每个用户而言,这个(uid,gid)保存在密码文件/etc/passwd的记录中。本书已经介绍过索引节点还为每个文件保存了uid和gid,其中uid是文件所有者的用户id而gid是文件所有者的组id(参见13.4.5(3)节)。所有者就是创建文件的人。通过为用户匹配uid和gid(在/etc/passwd文件中指明)以及对应文件的内容(在其索引节点中已给出),UNIX可以确定该用户可以对该文件采取什么样的操作(读/写/执行)。

如果UNIX采用AOS/VS设置访问权限的方式(也就是为每个用户明确指明访问权限),那么ACL会很长,而且会占用大量的磁盘空间,还要耗费很长的时间进行验证。所以,UNIX进行了一种妥协。它将每个文件的用户分成广泛的三类:第一类被称作所有者(Owner)--创建文件的人。因此,所有者的uid定义了这个类。第二类就是组(Group)--由所有者的gid定义。第三类是其他的(Others)--它不属于前两类。除了所有者之外,所有用户要么属于"组"类,要么属于"其他"类。

因此,UNIX只针对这三类用户为每个文件定义访问权限。UNIX只提供三类访问权限--读(r)、写(w)和执行(x)。它为这三种存取权限预留3个位。0表示拒绝此权限,1表示授权。因此,如果给定文件的访问权限是101,那么意味着用户可以读该文件,但不能向该文件写内容,同时可以执行该文件。假定它是一个包含编译过的、二进制可执行程序的文件。这就是为什么有时候将其写成r-x的原因,虽然在ACL中内部是按照101的形式保存该信息的。类似的,如果组对文件有001或--x的访问权限,那么就意味着组中的任何人都只能执行该文件,但没有人可以执行读/写操作。因此,在索引节点中有9个位(每一类有3位),它们完整地定义了对该文件的访问权限。

现在,存取控制验证按照以下步骤进行:

① 如上所述,系统管理员为用户分配uid和gid。uid和gid存储在/etc/passwd文件中。这里分别称其为uid-u和gid-u,以备将来引用。

② 任何时候,当用户登录系统时,他键入自己的用户名和密码。如前所示,系统查询/etc/passwd文件之后检索该用户的uid。UNIX (本例中的登录过程)通过存储在/etc/passwd文件中的内容验证这些信息。只有在确认信息匹配之后,用户才被授权访问该系统。此时,用户可以向shell提交命令。当该用户登录并启动任一进程时,就会将该用户的uid-u和gid-u从/etc/passwd文件中复制到该进程的u区。如果该进程创建子进程,那么这个子进程同样也有一个继承父进程的包括相同uid-u和gid-u的u区。

③ 现在假定用户提交命令执行一个名为PAY.COB的COBOL程序。PAY.COB是UNIX目录系统中的一个文件,它包括可执行程序也就是该程序的二进制代码。还假定在编译程序创建该文件之后,系统分析员确定可以执行该程序的人员,并且系统管理员会据此使用只可以执行的优先命令设定该文件的存取控制位。在接收到来自用户执行该程序的命令后,内核通过前面介绍过的符号文件目录的链表以及用于解析文件路径名的索引节点访问PAY.COB的索引节点。

在最终得到PAY.COB的索引节点之后,内核将它保存在PAY.COB索引节点中的uid和gid保存起来。这里称其为uid-i和gid-i以备将来引用。这些就是该文件所有者的uid和gid。现在,将进程u区可执行进程中的uid和gid(uid-u、gid-u)以及进程想要访问的文件索引节点中的uid和gid(uid-i、gid-i)进行匹配。该工作通过以下步骤完成。

④ 内核现在执行以下算法,确定用户类别(假定用户不是超级用户)。

 

 



⑤ 除了索引节点中为这三个类别存储的9个位之外,现在内核可以访问到步骤(4)中对应该类别的3个位。

 

⑥ 现在内核检查该类的最后一个(x)位,确保当前用户可以执行该程序。如果可以执行,就让其继续,否则提示错误消息拒绝用户的执行。

⑦ 当运行PAY.COB程序时,形成新的u区,并将父进程的uid和gid复制到该u区。如果PAY.COB调用另一个名为TAX.COB的子程序,通常,内核创建包含另一个u区的新的子进程。再次的,将父进程的u区中的uid-u和gid-u复制给子进程的u区。此时,如果TAX.COB提交打开另一个文件的指令(系统调用),也就是读EMP.DAT文件,存取控制验证可以按照以下步骤继续:

内核根据层次结构目录可以解析路径名,从而到达包含EMP.DAT文件的目录,这在路径名解析中已经做过介绍。

内核搜索目录中的EMP.DAT文件,并获取该文件的索引节点号。

内核读取EMP.DAT的索引节点,并且将uid和gid存为uid-i和gid-i。

将其和存储在TAX.COB的u区中的uid-u和gid-u比较,内核可以得到对应该文件的用户类别(参见前面例子中的步骤(4))。

内核将查看索引节点中对应该类别的3个访问权限位。

最终,内核根据用户类别,通过检查存取控制位的第一位(r)确保用户对该文件可以进行"读"操作,从而允许或禁止用户请求的操作。

posted @ 2012-03-17 22:44  CobbLiu  阅读(338)  评论(0编辑  收藏  举报