第十五章 文件属性类的实现

来源:互联网 发布:家居室内设计软件 编辑:程序博客网 时间:2024/04/30 16:00

 

                第十五章    文件属性类的实现

 

     根用户的权限也不能是无限大、必须考虑到保护用户的隐私!用户的文件内容、程序代码可设置为根用户也不能观看,只能是文件拥有者可以查看、修改。但根用户可以删除一切非根用户的文件、也可以查看用户的目录。所以,i_mode字符更改如下:

 

   BU16 i_mode; // 描述文件的访问权限;文件的读、写、执行权限 

// i_mode.15-13  ftype; 文件类型: 0-符号软连接文件,

// 1-硬连接文件,2-普通文件, 3-块设备文件,4-字符设备文件,

// 5-文件系统根目录型文件。

// i_mode.12  ACL;  文件访问权限是否由ACL文件描述。

// i_mode.11-0 FWQX; 文件访问权限: rwx-rwx-rwx-rwx,读、写、执行权限,分别是:

// 文件拥有者owner - 根root - 文件所属组 – 其它用户

 

文件的权限设置、必须是文件的拥有者才行!根用户也不行、除非文件拥有者在i_mode中、允许root对文件拥有读、写权限!


目录执行权限:允许搜索该目录、寻找一个特定文件。

目录读权限:允许列出目录中的所有文件的目录属性项。

删除、创建目录下的一个文件,必须对该目录有写、执行权限。

对文件内容的读、写、执行权限,取决于i_mode的12个权限位的设置。

i节点属性表为只读。


对文件的目录项属性表读,取决于i_mode的12个权限位的设置。部分变量的写、只能是文件拥有者。其中:inode索引i节点号(文件名字哈希值)、i_uid描述文件的拥有者标识、i_gid描述文件的用户组标识、i_count到本目录项的软连接计数器、i_ycount硬连接的计数器指针、i_size描述文件最后块或页的剩余行数或记录大小、i_blocks描述文件的数据块数或页数或记录数、i_fop文件名长度和操作方法表指针号、i_mblock描述文件的第一个连续数据块数或连续页数、i_mblockp指向第一个连续m个数据块或页或单位的首指针、i_ctime索引节点最后改变的时间,单位n秒、i_mtime文件最后修改时间标识,单位n秒、i_crtime文件的出生时间标识,单位nS、i_atime文件最后访问时间标识,单位n秒、共14项是只读属性。可改写的有:i_mode描述文件的访问权限,i_flags文件标志的i_flags.15-9的7个位,文件名字name;共3项。

 

         i_uid、i_gid为登录时,在系统登录文件数据库中注册项中自动提取的、通常是靠前的、有效的项;i_uid是注册后、系统自动分配;除root可以注销该i_uid用户外、其它官都不行、但root也不能更改用户号;用户也可以申请注销其用户号、或组号。一个用户可以属于最多16个组,i_gid = 0xFFFF表示是无效组号;组长以上的官可以设置用户不属于该组,即在该组注销该用户;即是将其原来所属的组项i_gid_j(j = 0-15)= 0xFFFF。每个小组最多64K个用户,每60个小组设一个大队长;每100个大队、设一个军团长。每个用户可以有多种身份,用户i_uid 号:root 0、系统服务进程和保留1-799、军团长800-810、元老811-999、大队长1000-1999、组长2000-65000。登录时,如果你有职称、系统会提示你用什么身份登录。官大一级压死人、上级可以撤销下级的职称ID;但军团长不能撤销元老,root则可以。组长有的权利、大队长以上也当然有;至于职称的福利、那是另外定义。每个用户最多可以注册拥有8个用户号,0xFFFFFFFF是空号。用户号、组号等等相关应用是属于用户数据库管理,说起来话长、以后再论。这样一来,进程的v节点(进程PCB)要改为8E(可执行文件v节点5E,用户、组号2E,task块1E);当用户登录时,系统从用户数据库读入2E的用户号、组号到用户shell进程v节点;用户再打开其它进程时,会自动继承这2E。

 

根用户权限,特权:

1、可以进行 目录下文件的删除、新建、搜索和列出目录的的文件项。

2、可以读进程属性v节点8E、或改写一部分变量。

3、可以注销用户。

其它权限、以i_mode字符的 rwx设置为准。

 

小组长以上的用户权限,特权:

可以注销下级的职称、或用户所属组号。

 

文件拥有者权限,对拥有的文件:可读、部分可写文件属性(文件i节点和对应目录项),如果是可执行文件、那可读、部分写进程属性v节点8E,可读本进程的方法表512E。对文件内容的读写,对目录下文件的删除、新建、搜索和列出目录的的文件项,以i_mode字符的 rwx设置为准。

 

文件组权限:如组rwx允许读、写,那只可读文件属性(文件i节点和对应目录项),可对文件内容读写。如果是可执行文件、那可读进程属性v节点8E(包含读寄存器组R0-R31),可读文件内容。

 

    系统的各个类的属性表、和方法表都归类到一个内核类。文件属性类主要是针对文件属性、进程属性的读、和写;即是API方法fileget(),fileset()。在前面的第六章已经介绍了文件、进程的属性,这里就介绍实现方法。

     文件、进程的属性都是属于系统管理的变量,用户程序只能调用系统方法来获取、或设置;这需要有相应的权限,才能进行。UINX、LINUX都是把这2个功能、搞成一大堆函数来实现、显得不清晰、和啰嗦;也势必使代码不精炼、和重复。

     文件名指的是不带路径的文件名,而路径名(路径名变量pathname)的含义则较广泛,它既包括含路径的文件名,也包括单个文件名。文件、进程属性有:i节点2W、对应目录项4E、打开文件表项1E、文件v节点4E、进程v节点8E、路径名最大256E(4K字符)的属性、进程的方法表512E。常量字符串是以行为单位存放,不足一行的空余地方为0;const常量表通常编译到文件属性表中的D根对象后面。

      静态变量只能是挂靠在某个Di对象号下,编译器也是给出对象号、相对偏移地址的结果,由程序装入时、安装相应对象号的真实地址、长度。不管是动态、静态变量你要读完整的属性表,都要给出足够大的容器来装属性数据;要不会被截断、或报错。前提是你必须有足够的权限,通常是根、或拥有者才行。

// 规定行的单位:E,页的单位是:Y,数据块的单位是:C,单元的单位是:D。

// 字符的单位:Z,字的单位:W,字节的单位:B,扇区的单位:S。

// 硬件规定:第0号数据块中的方法(实时CPU线路、和用户CPU线路,的内核方法库),

// 只能是第0、1号数据块中的方法可以调用;其它数据块中的方法最多能调用第1号

// 数据块中的方法(API库)及 >1的公开方法库。

 

      CPU中有方法调用硬件监视器,CALL时、新的PPC就是目的地,而(PSP).7.W中的PPC就是源地的下一条指令,即返回点。硬件监视源地、目的地;目的地是0号数据块,那么需要源地不大于1号数据块。如果目的地是1号数据块API,那么许可。0、1号的方法是系统方法不可能去调用用户方法的,用户方法只能最多是调用1号数据块API库中的方法;不能调用内核方法;违者异常侍候。API中的方法可以调用0号数据块中的内核方法。这书编写的方法如果不注明是API,那隐含指是0号数据块的内核方法。

 

获取pid进程v节点指针方法:R28 = getpidvnode(,pid); 内核方法。

获取当前进程v节点指针方法:R28= getpidvnode(,B1L); B1L是只读寄存器。

入口:pid进程号送R1L寄存器,当前进程号是在B1L只读寄存器。

出口:R28 = 进程v节点指针。

占用:R28、4W

耗时:4ns

getpidvnode(,pid){// 传送参数1W、1ns

  R28 = Process_vnode_tab; // R28指向进程v节点表首指针。

  R28 = +R1L<<3;  // R28指向相应pid的v节点项首指针。

  RET 

}

 

获取用户对象的指针方法:R29= getdxp(,对象名字); 内核方法。

入口:对象名字。

出口:R29 = 对象空间的首指针,长度在R30。

占用:R29-R30、8W

耗时:8ns

getdxp(,对象名字){// 对象的实际内存地址送PITR、并R1 = PITR; R2 =LENG; 5W、5ns。

  R29 =R1; R30 = R2;// 用户想这样做是不行的、指令不在系统代码区域错。

  RET 

}

 

进程对文件的权限判断方法:R31H= accesspath(,pathname); 系统API方法。

类似linux的int access(const char * pathname,int mode); 但APO是返回文件的所有权限测试结果。

   R31H; // 低8位错误代号、高8位权限、许可标志。

//R31H.15  FERR ;// 1、操作文件出错指示,0、否。

//R31H.14  root; // 1、是根用户,0、否。

//R31H.13  owner;// 1、是用户拥有者,0、否。

//R31H.12  grp; //  1、是组用户,0、否。

//R31H.11  Y_OK ;// 1、许可进程在目录中删除、或新建一个文件,0、否。

//R31H.10  RD_OK ;// 1、许可进程读文件内容,0、否。

//R31H.9   WR_OK ;// 1、许可进程写文件内容,0、否。

//R31H.8   X_OK ; // 1、许可进程执行该文件,0、否。

 

入口:路径名参数pathname。APO最多允许pathname 是4K字符,即256E,而路径的目录数最多允许1K个(包括/、平均4字符/个)。以“/”分割目录段,在APO中用硬件模块YJMK、一次10ns就可分割2K个字符,4K字符不就最多2次;耗时主要还是在对各个目录名的哈希运算。如果进程非根用户、那是须检查用户对路径上每一个目录的执行权限是否通过;否则还不到达最终的文件名、就给pass了;根用户就无需检查目录权限。而这一个过程是由API方法、checkpath()进行的,如果失败、就直接设标志后返回了。成功、R31H.15 =0。R31H.14 = 1、root是根用户,0、否。R31H.12 = 1、RDIR_OK许可进程读目录项,0、否。R31H.11 = 1、Y_OK许可进程在目录中删除、或新建一个文件,0、否。R31H.10-0 = 0。最后、返回文件名字哈希值到R0。

检查进程是否文件拥有者、或所属组;都是用硬件模块YJMK、一次约15ns就可得出。

出口:标志与错误码在R31H 寄存器。

占用:R0、R28、13W

耗时:13ns +

accesspath(,pathname){// 返回标志与错误码在R31H寄存器。

// pathname的实际内存地址送PITR、并R1 = PITR; 长度R2= LENG; 5W、5ns。

  R28 = getpidvnode(,B1L);// 获取当前进程v节点指针方法。

  R31H = 0; // 初始化

  checkpath(); // 检查路径权限。

  read_vnode();// 以R0读入i节点及相应目录项到临时temp_v节点区域(5E)

  BT1  (R0).v_dirnum.31,acs1; // 文件是存在的、跳。

acs0:

  R31H.15 = 0;  RET // 文件不存在、置错误标志返回

acs1:

  checkugid(); // 检查是否拥有者、和所属组用户,还是其它用户。

// 并置相应的权限到R31H.2-0;入口:R28、R0、R31H。

  RET

}

进程对另一个进程的权限判断方法:R31H= accesspid(,pid); 系统API方法。

入口:pid进程号送R1L寄存器,当前进程号是在B1L寄存器。

出口:标志与错误码在R31H 寄存器。

占用:R0、R28、9W

耗时:15ns +

accesspath(,pid){// 返回标志与错误码在R31H寄存器。

   R31H = 0; // 初始化标志、错误号。

   R28 = getpidvnode();// 获取另一进程v节点指针方法。

   R0 = R28;

   if (R0).inode == 0 goto acs0; // 另一进程是不存在、跳。

   R28 = getpidvnode(,B1L);// 获取当前进程v节点指针方法。

   JMP  acs1;

 

检查是否拥有者、和所属组用户,还是其它用户及权限的方法checkugid();

入口:R0指向临时文件v节点、或另一进程的v节点,R28 = 当前进程v节点指针。

出口:标志、错误号在R31H。

占用:26W

耗时:48ns

checkugid(){//

   R1 = (R28).v_uid; // R1为当前进程的用户号。

   R2L= (R0).v_mode; // 读取文件、或另一进程的权限。

   R4L = 1; 

   if R1 != 0 goto che1; // 非根用户跳。

   R31H.14 = 1; // 置根用户标志。

   R31H.10-8 = R2L.8-6;// 提取根用户权限,位段赋值指令1W、1ns,

   RET

che1:

   R3 = (R28).p_uid.E; // R3指向当前进程的用户号数组行。

   B2 = 10.CMP.0.1;// 设置多功能模块为字比较相等指令

   B3 = (R0).v_uid; // B3为文件、或另一进程的用户号。

   ugcmp();// 比较,16ns

   BT0 PSR.YJ, che2; // 失败、为非拥有者、跳。

   R31H.13 = 1; // 置进程是拥有者标志。

   R31H.10-8 = R2L.11-9;// 提取拥有者权限,位段赋值指令1W、1ns,

   RET

che2:

   R3 = (R28).p_gid.E; // R3指向当前进程的用户组号数组行。

   B2 = 2.CMP.0.1;  // 设置多功能模块为字符比较相等指令

   B3 = (R0).v_gid; // B3为文件、或另一进程的组号。

   ugcmp(); // 比较,16ns

   BT0 PSR.YJ, che3; // 失败、为其它用户、跳。

   R31H.12 = 1; // 置进程是所属组成员标志。

   R31H.10-8 = R2L.5-3;// 提取组成员权限,位段赋值指令1W、1ns,

   RET

che3:

   R31H.10-8 = R2L.5-3;// 提取其它用户权限,位段赋值指令1W、1ns,

   RET

}

 

多功能硬件模块CMP(无符号比较指令):最多只是比较256行中的值;位图内容不变。
B2H: 高8位的低4位CMP属性: B2H.3  字比较1/字符比较0,其它3位:
000:最小值、   001:最大值

010:等于       011:不等于

100:小于、     101:大于

110:小于等于、 111:大于等于

如、比较B3的字与1-256行中字第一个相等的位置:低4位是、1010。

如、比较B3H的字符与1-256行中字符第一个相等的位置:低4位是、0010。

如、比较B3H的字符小于1-256行中字符第一个的位置:低4位是、0100。

如果要求出所有的位置、那只能是比较128行,另128E放位置结果。

如、比较B3H的字符与1-127行中字符相等的位置:低4位是、0010;高4位是0001。结果都在128E-255E里面,R4L为符合条件的位置序号数。

B3:  32位是你需要与n行中的32位值比较的数值。n <= 256

B3H: 16位是你需要与n行中的16位值比较的数值。

B4L: 返回结果:是第一个符合条件的字或字符开始地址;B4H不变,可作记录号高半字。如果已经比较完、并失败; PSR.YJ = 0;B2H.15 = 0。
   

比较API方法ugcmp();我们要使用多功能硬件模块来比较进程是否拥有者、和是否所属组;因为每个用户可以有最多8个用户号、和属于16个组。每次只需比较1行。

入口: R3 = 需要比较的行指针、R4L为须比较的行数。

出口:成功PSR.YJ = 1。

占用:6W

耗时:15ns

ugcmp(){

    COPY.E( YJMK,R3, R4L );// 编译后4条指令,耗时:4 ns

    SS1;    // 比较R4L行,找到相等序号。

    RET
}

 

获取进程属性API方法:fileget(0/1, pid, 容器变量 );  

入口:pid进程号,容器变量名。R0L = 0,是读取进程v节点;容器最少需要大于等于8E才行;R0L = 1,是读取进程方法表;容器最少需要大于等于512E才行。至于需要单独获取某个变量的属性、那是应用层软件的判断和编写;系统是一下给够。

出口:容器变量 = 读入的属性表,标志、错误号在R31H。

占用:R0、R28、30W

耗时:ns

 

fileget( 0/1,pid, 容器变量名 ){

// R0L = 0/1, R1 = pid,R2 = PITR; 长度R3 = LENG; 7W、7ns

   if R0L == 1 goto fig4; // 是读进程方法表、跳。 2W

// 编译后是: CMP.Z  R0L, 1; JZ  fig4; 后面类同不再说明。

   if R3 >= 4  goto fig2A; // 容器够大、跳

fig1:

   R31H.15 = 1; RET // 置错误标志返回。

fig2A:

   R3L = 4;

fig2:

   accesspath();

// 本进程对另一个pid进程的权限判断方法,如果pid为B1L就是对自己做权限判断。

fig3a:

   BT0 R31H.RD_OK, fig1; // 没有读权限、出错返回。

   BT1 R31H.root, fig3; // 是根用户可以读取属性。

   BT1  R31H.owner, fig3;// 的文件拥用者可以读取属性。

   JMP  fig1;  // 其它的、至错误标志返回。

fig3:

   COPY.E( R2, R0, R3L ); // 拷贝

   RET

fig4:

   if R3< 512  goto fig1; // 容器太小出错返回

   R0 = Process_method_tab; // R0指向进程方法表首指针。

   R0 =+R1<<9;  // R0指向相应pid的方法表项首指针。

   R3L = 512;  JMP  fig3; // 拷贝、返回

 }

 

据文件号fd获取文件属性API方法:fileget( 0/1, fd, 容器变量 );  

入口:fd文件号、容器变量名。0、读文件属性表,读打开文件表项,1、读文件i节点属性表及完整路径名字符串。

出口:容器变量 = 读入的属性表;标志、错误号在R31H。

占用:R0、R28、33W

耗时:读文件属性表,打开文件表项:50ns;读路径:130ns +

  

fileget(0/1, fd, 容器变量名 ){ // 11W、11ns

// R0L =0/1, R1 = fdp,R2 = fdlen, R3 = PITR; R4 = LENG;

   R31H = (R1).allow_err; // R1打开文件表项的指针、R2 = 1(E)。

   if R0L == 1 goto flgt2; // 是读文件i节点、和path跳。

flgt1:

   if R4 < 5 goto fig1; // 容器太小出错返回

   R0 = R1; R2 = R3; R3L = 1;

   CALL  fig3a;// 调用fig3a,拷贝打开文件表项。

   BT0 R31H.15, fig1; // 出错返回。

   R2+; R0 = (R1).vnode; // R0指向文件的v节点,R2为容器下一行。

   R3L = 4; // 拷贝4行。

   JMP fig3a;

flgt2:

   if R4 < 257  goto fig1; // 容器太小出错返回

   R0 = (R1).vnode;  R2 = R3;  R3L= 257;

   read_temp_v();// 以R0读入i节点及路径到临时v节点区域(257E)

   JMP  fig3a;

}

 

据参数pathname获取文件属性API方法:fileget(0/1, pathname, 容器变量 );  

入口:参数pathname,容器变量名。0、读文件属性表,读打开文件表项,1、读文件i节点属性表及完整路径名字符串。

出口:容器变量 = 读入的属性表,标志、错误号在R31H。

占用:R0、R28、17W

耗时:ns

 

fileget( 0/1, pathname,容器变量名 ){ 11W、11ns, R0L = 0/1, pathname

// 的实际内存地址送R1、长度R2;R3 = PITR; R4 = LENG;

   if R0L == 1 goto flgt3; // 是读文件i节点、和path跳。

   accesspath();// 进程据pathname对文件的权限判断方法。

   JMP flgt1;

flgt3:

   accesspath();// 进程据pathname对文件的权限判断方法。

   JMP flgt2;

}

 


。。。待续


0 0
原创粉丝点击