code:namei - ikarishinjieva/unixV6-code-analyze-chs GitHub Wiki
总体说明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);
7535 while(c == ’/’)
- 若 文件路径 以 '/' 开头,则使用根目录inode
- 否则,使用当前目录的inode
- iget 在此处 由于根目录或当前目录的inode已经读入内存(常驻内存),所以不需要从磁盘读,而只是置锁
7536 c = (*func)();
7537 if(c == ’\0’ && flag != 0) {
- 诸如 "///a//b" 这样的路径也可以被解析,多余的'/'在此被屏蔽
7538 u.u_error = ENOENT;
7539 goto out;
7540 }
7541
- 若 企图对 当前目录或根目录 进行操作(如删除),则抛出错误
- 错误代码:ENOENT
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))
- 若 当前元素 不是目录项,则抛出错误
- 错误代码:ENOTDIR
- 7559用法参考文件系统之inode类型
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)();
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);
7590 bp = NULL;
- u.u_count置为 当前inode的目录项总数
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 }
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 }
7628
- 若 读完了当前目录项块,则读取下一个目录项块
- 7626 由于 u.u_offset[1] 单位为字节,所以除以512
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,
7637 (DIRSIZ+2)/2);
- 读取下一个目录项,复制到u.u_dent
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 }
7645 for(cp = &u.u_dbuf[0]; cp < &u.u_dbuf[DIRSIZ]; cp++)
- 若读到了空目录项(指向第0块),则用eo标识
7646 if(*cp != cp[u.u_dent.u_name])
7647 goto eloop;
7648
- 匹配 当前目录项 和 欲查找的目录项,若不匹配,则继续循环
- 7646实际比较了 cp的内容 和 与cp对应的u.u_dent.u_name数组中的内容
- u.u_dent.u_name - u.u_dbuf 的用法是 用地址偏移寻址
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 }
7662 bp = dp->i_dev;
- 若为删除模式,进行权限检查,并返回dp
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 /* ------------------------- */
返回指向匹配inode的指针
- 若 要添加的目录项已经存在,则返回指向匹配inode的指针,与查找模式相同
- 否则
- 返回null
- u-pdir指向 新目录项欲填入 的内存inode
- u-offset指向 新目录项欲填入的位置
- 返回欲删除的目录项所在的内存inode(即其父目录inode)指针
- u-offset指向欲删除项的下一个位置