code:namei - ikarishinjieva/unixV6-code-analyze-chs GitHub Wiki

Table of Contents

Source

  • 根据 文件/目录路径 返回 对应的inode(并置锁)
  • 共传入两个参数 func , flag
    • func : 函数指针,该函数用于得到 文件路径的下一个字符,只能取以下两个函数
    • flag : 标志位,参看 标志位说明
      • flag = 0,查找模式
      • flag = 1,添加模式
      • flag = 2,删除模式
    • 返回值 : 参看 标志位说明
总体说明
  • igetiput 分别为申请和释放inode
  • eo变量 用于记录第一个空闲目录项位置
  • 所有抛出的错误 参看 错误代码
7506

7507 /*

7508  * Convert a pathname into a pointer to

7509  * an inode. Note that the inode is locked.

7510  *

7511  * func = function called to get next char of name

7512  * &uchar if name is in user space

7513  * &schar if name is in system space

7514  * flag = 0 if name is sought

7515  * 1 if name is to be created

7516  * 2 if name is to be deleted

7517  */

7518 namei(func, flag)

7519 int (*func)();

7520 {

7521     register struct inode *dp;

7522     register c;

7523     register char *cp;

7524     int eo, *bp;

7525

7526     /*

7527      * If name starts with ’/’ start from

7528      * root: otherwise start from current dir.

7529      */

7530

7531     dp = u.u_cdir;

7532     if((c=(*func)()) == ’/’);

7533          dp = rootdir;

7534     iget(dp->i_dev, dp->i_number);

  • 若 文件路径 以 '/' 开头,则使用根目录inode
  • 否则,使用当前目录的inode
  • iget 在此处 由于根目录或当前目录的inode已经读入内存(常驻内存),所以不需要从磁盘读,而只是置锁
7535     while(c == ’/’)

7536          c = (*func)();

  • 诸如 "///a//b" 这样的路径也可以被解析,多余的'/'在此被屏蔽
7537     if(c == ’\0’ && flag != 0) {

7538          u.u_error = ENOENT;

7539          goto out;

7540     }

  • 若 企图对 当前目录或根目录 进行操作(如删除),则抛出错误
  • 错误代码:ENOENT
7541

7542 cloop:

7543     /*

7544      * Here dp contains pointer

7545      * to last component matched.

7546      */

7547

7548     if(u.u_error)

7549          goto out;

7550     if(c == ’\0’)

7551          return(dp);

7552

7553     /*

7554      * If there is another component,

7555      * dp must be a directory and

7556      * must have x permission.

7557      */

7558

7559     if((dp->i_mode&IFMT) != IFDIR) {

7560          u.u_error = ENOTDIR;

7561          goto out;

7562     }

7563     if(access(dp, IEXEC))

7564          goto out;

  • 若 当前目录项 不具有执行权限(实为查找目录的权限),则抛出错误
7565

7566     /* Gather up name into

7567      * users’ dir buffer.

7568      */

7569

7570     cp = &u.u_dbuf[0];

7571     while(c!=’/’ && c!=’\0’ && u.u_error==0) {

7572          if(cp < &u.u_dbuf[DIRSIZ])

7573            *cp++ = c;

7574          c = (*func)();

7575     }

7576     while(cp < &u.u_dbuf[DIRSIZ])

7577          *cp++ = ’\0’;

7578     while(c == ’/’)

7579          c = (*func)();

  • 将 文件/目录名 复制到 u.u_dbuf
  • 文件名 多余 DIRSIZ(14)的部分将被删除
  • u.u_dbuf多余部分将以'/0'充填
  • 7578 - 7579 修正c的位置,参看 7535-7536的注释
7580     if(u.u_error)

7581          goto out;

7582

7583     /* Set up to search a directory. */

7584

7585     u.u_offset[1] = 0;

7586     u.u_offset[0] = 0;

7587     u.u_segflg = 1;

7588     eo = 0;

7589     u.u_count = ldiv(dp->i_size1, DIRSIZ+2);

  • u.u_count置为 当前inode的目录项总数
7590     bp = NULL;

7591

7592 eloop:

7593

7594     /*

7595      * If at the end of the directory,

7596      * the search failed. Report what

7597      * is appropriate as per flag.

7598      */

7599

7600     if(u.u_count == 0) {

7601          if(bp != NULL)

7602           brelse(bp);

7603          if(flag==1 && c==’\0’) {

7604           if(access(dp, IWRITE))

7605                goto out;

7606           u.u_pdir = dp;

7607           if(eo)

7608                u.u_offset[1] = eo-DIRSIZ-2; else

7609                     dp->i_flag =| IUPD;

7610           return(NULL);

7611          }

7612          u.u_error = ENOENT;

7613          goto out;

7614     }

  • 若搜索完成,且没有找到匹配的目录项
    • 若 为添加模式 ,则执行 7603 - 7611
    • 否则,抛出错误,错误代码:ENOENT
  • 7608行的用法 参看 标志位说明
  • 7609行 并未能理解,列入遗留问题
7615

7616     /*

7617      * If offset is on a block boundary,

7618      * read the next directory block.

7619      * Release previous if it exists.

7620      */

7621

7622     if((u.u_offset[1]&0777) == 0) {

7623          if(bp != NULL)

7624           brelse(bp);

7625          bp = bread(dp->i_dev,

7626                bmap(dp, ldiv(u.u_offset[1], 512)));

7627     }

  • 若 读完了当前目录项块,则读取下一个目录项块
  • 7626 由于 u.u_offset[1] 单位为字节,所以除以512
7628

7629     /* Note first empty directory slot

7630      * in eo for possible creat.

7631      * String compare the directory entry

7632      * and the current component.

7633      * If they do not match, go back to eloop.

7634      */

7635

7636     bcopy(bp->b_addr+(u.u_offset[1]&0777), &u.u_dent,

  • 读取下一个目录项,复制到u.u_dent
7637                         (DIRSIZ+2)/2);

7638     u.u_offset[1] =+ DIRSIZ+2;

7639     u.u_count--;

7640     if(u.u_dent.u_ino == 0) {

7641          if(eo == 0)

7642           eo = u.u_offset[1];

7643          goto eloop;

7644     }

  • 若读到了空目录项(指向第0块),则用eo标识
7645     for(cp = &u.u_dbuf[0]; cp < &u.u_dbuf[DIRSIZ]; cp++)

7646          if(*cp != cp[u.u_dent.u_name])

7647           goto eloop;

  • 匹配 当前目录项 和 欲查找的目录项,若不匹配,则继续循环
  • 7646实际比较了 cp的内容 和 与cp对应的u.u_dent.u_name数组中的内容
7648

7649

7650     /* Here a component matched is a directory.

7651      * If there is more pathname, go back to

7652      * cloop, otherwise return.

7653      */

7654

7655     if(bp != NULL)

7656          brelse(bp);

7657     if(flag==2 && c==’\0’) {

7658          if(access(dp, IWRITE))

7659           goto out;

7660          return(dp);

7661     }

  • 若为删除模式,进行权限检查,并返回dp
7662     bp = dp->i_dev;

7663     iput(dp);

7664     dp = iget(bp, u.u_dent.u_ino);

7665     if(dp == NULL)

7666          return(NULL);

7667     goto cloop;

7668

7669 out:

7670     iput(dp);

7671     return(NULL);

7672 }

7673 /* ------------------------- */

Extend

附图

标志位说明

查找模式

返回指向匹配inode的指针

添加模式

  • 若 要添加的目录项已经存在,则返回指向匹配inode的指针,与查找模式相同
  • 否则
    • 返回null
    • u-pdir指向 新目录项欲填入 的内存inode
    • u-offset指向 新目录项欲填入的位置

删除模式

  • 返回欲删除的目录项所在的内存inode(即其父目录inode)指针
  • u-offset指向欲删除项的下一个位置

Ref

Caller

⚠️ **GitHub.com Fallback** ⚠️