📄 namei.c
字号:
return NULL;}// 从路径名开始起搜索检测字符,直到字符已是结尾符(NULL)或者是'/',此时namelen 正好是当前处理// 目录名的长度。如果最后也是一个目录名,但其后没有加'/',则不会返回该最后目录的i 节点!// 比如:/var/log/httpd,将只返回log/目录的i 节点。for(namelen=0;(c=get_fs_byte(pathname++))&&(c!= '/');namelen++)/* nothing */ ;// 若字符是结尾符NULL,则表明已经到达指定目录,则返回该i 节点指针,退出。if (!c)return inode;// 调用查找指定目录和文件名的目录项函数,在当前处理目录中寻找子目录项。如果没有找到,则释放// 该i 节点,并返回NULL,退出。if (!(bh = find_entry(&inode,thisname,namelen,&de))) {iput(inode);return NULL;}// 取该子目录项的i 节点号inr 和设备号idev,释放包含该目录项的高速缓冲块和该i 节点。inr = de->inode;idev = inode->i_dev;brelse(bh);iput(inode);// 取节点号inr 的i 节点信息,若失败,则返回NULL,退出。否则继续以该子目录的i 节点进行操作。if (!(inode = iget(idev,inr)))return NULL;}}/** dir_namei()** dir_namei() returns the inode of the directory of the* specified name, and the name within that directory.*//** dir_namei()* dir_namei()函数返回指定目录名的i 节点指针,以及在最顶层目录的名称。*/// 参数:pathname - 目录路径名;namelen - 路径名长度。// 返回:指定目录名最顶层目录的i 节点指针和最顶层目录名及其长度。static struct m_inode * dir_namei(const char * pathname,int * namelen, const char ** name){char c;const char * basename;struct m_inode * dir;// 取指定路径名最顶层目录的i 节点,若出错则返回NULL,退出。if (!(dir = get_dir(pathname)))return NULL;// 对路径名pathname 进行搜索检测,查处最后一个'/'后面的名字字符串,计算其长度,并返回最顶// 层目录的i 节点指针。basename = pathname;while (c=get_fs_byte(pathname++))if (c== '/')basename=pathname;*namelen = pathname-basename-1;*name = basename;return dir;}/** namei()** is used by most simple commands to get the inode of a specified name.* Open, link etc use their own routines, but this is enough for things* like 'chmod' etc.*//** namei()* 该函数被许多简单的命令用于取得指定路径名称的i 节点。open、link 等则使用它们* 自己的相应函数,但对于象修改模式'chmod'等这样的命令,该函数已足够用了。*///// 取指定路径名的i 节点。// 参数:pathname - 路径名。// 返回:对应的i 节点。struct m_inode * namei(const char * pathname){const char * basename;int inr,dev,namelen;struct m_inode * dir;struct buffer_head * bh;struct dir_entry * de;// 首先查找指定路径的最顶层目录的目录名及其i 节点,若不存在,则返回NULL,退出。if (!(dir = dir_namei(pathname,&namelen,&basename)))return NULL;// 如果返回的最顶层名字的长度是0,则表示该路径名以一个目录名为最后一项。if (!namelen) /* special case: '/usr/' etc */return dir; /* 对应于'/usr/'等情况 */// 在返回的顶层目录中寻找指定文件名的目录项的i 节点。因为如果最后也是一个目录名,但其后没// 有加'/',则不会返回该最后目录的i 节点!比如:/var/log/httpd,将只返回log/目录的i 节点。// 因此dir_namei()将不以'/'结束的最后一个名字当作一个文件名来看待。因此这里需要单独对这种// 情况使用寻找目录项i 节点函数find_entry()进行处理。bh = find_entry(&dir,basename,namelen,&de);if (!bh) {iput(dir);return NULL;}// 取该目录项的i 节点号和目录的设备号,并释放包含该目录项的高速缓冲区以及目录i 节点。inr = de->inode;dev = dir->i_dev;brelse(bh);iput(dir);// 取对应节号的i 节点,修改其被访问时间为当前时间,并置已修改标志。最后返回该i 节点指针。dir=iget(dev,inr);if (dir) {dir->i_atime=CURRENT_TIME;dir->i_dirt=1;}return dir;}/** open_namei()** namei for open - this is in fact almost the whole open-routine.*//** open_namei()* open()所使用的namei 函数 - 这其实几乎是完整的打开文件程序。*///// 文件打开namei 函数。// 参数:pathname - 文件路径名;flag - 文件打开标志;mode - 文件访问许可属性;// 返回:成功返回0,否则返回出错码;res_inode - 返回的对应文件路径名的的i 节点指针。int open_namei(const char * pathname, int flag, int mode,struct m_inode ** res_inode){const char * basename;int inr,dev,namelen;struct m_inode * dir, *inode;struct buffer_head * bh;struct dir_entry * de;// 如果文件访问许可模式标志是只读(0),但文件截0 标志O_TRUNC 却置位了,则改为只写标志。if ((flag & O_TRUNC) && !(flag & O_ACCMODE))flag |= O_WRONLY;// 使用进程的文件访问许可屏蔽码,屏蔽掉给定模式中的相应位,并添上普通文件标志。mode &= 0777 & ~current->umask;mode |= I_REGULAR;// 根据路径名寻找到对应的i 节点,以及最顶端文件名及其长度。if (!(dir = dir_namei(pathname,&namelen,&basename)))return -ENOENT;// 如果最顶端文件名长度为0(例如'/usr/'这种路径名的情况),那么若打开操作不是创建、截0,// 则表示打开一个目录名,直接返回该目录的i 节点,并退出。if (!namelen) { /* special case: '/usr/' etc */if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {*res_inode=dir;return 0;}// 否则释放该i 节点,返回出错码。iput(dir);return -EISDIR;}// 在dir 节点对应的目录中取文件名对应的目录项结构de 和该目录项所在的高速缓冲区。bh = find_entry(&dir,basename,namelen,&de);// 如果该高速缓冲指针为NULL,则表示没有找到对应文件名的目录项,因此只可能是创建文件操作。if (!bh) {// 如果不是创建文件,则释放该目录的i 节点,返回出错号退出。if (!(flag & O_CREAT)) {iput(dir);return -ENOENT;}// 如果用户在该目录没有写的权力,则释放该目录的i 节点,返回出错号退出。if (!permission(dir,MAY_WRITE)) {iput(dir);return -EACCES;}// 在目录节点对应的设备上申请一个新i 节点,若失败,则释放目录的i 节点,并返回没有空间出错码。inode = new_inode(dir->i_dev);if (!inode) {iput(dir);return -ENOSPC;}// 否则使用该新i 节点,对其进行初始设置:置节点的用户id;对应节点访问模式;置已修改标志。inode->i_uid = current->euid;inode->i_mode = mode;inode->i_dirt = 1;// 然后在指定目录dir 中添加一新目录项。bh = add_entry(dir,basename,namelen,&de);// 如果返回的应该含有新目录项的高速缓冲区指针为NULL,则表示添加目录项操作失败。于是将该// 新i 节点的引用连接计数减1;并释放该i 节点与目录的i 节点,返回出错码,退出。if (!bh) {inode->i_nlinks--;iput(inode);iput(dir);return -ENOSPC;}// 初始设置该新目录项:置i 节点号为新申请到的i 节点的号码;并置高速缓冲区已修改标志。然后// 释放该高速缓冲区,释放目录的i 节点。返回新目录项的i 节点指针,退出。de->inode = inode->i_num;bh->b_dirt = 1;brelse(bh);iput(dir);*res_inode = inode;return 0;}// 若上面在目录中取文件名对应的目录项结构操作成功(也即bh 不为NULL),取出该目录项的i 节点号// 和其所在的设备号,并释放该高速缓冲区以及目录的i 节点。inr = de->inode;dev = dir->i_dev;brelse(bh);iput(dir);// 如果独占使用标志O_EXCL 置位,则返回文件已存在出错码,退出。if (flag & O_EXCL)return -EEXIST;// 如果取该目录项对应i 节点的操作失败,则返回访问出错码,退出。if (!(inode=iget(dev,inr)))return -EACCES;// 若该i 节点是一个目录的节点并且访问模式是只读或只写,或者没有访问的许可权限,则释放该i// 节点,返回访问权限出错码,退出。if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||!permission(inode,ACC_MODE(flag))) {iput(inode);return -EPERM;}// 更新该i 节点的访问时间字段为当前时间。inode->i_atime = CURRENT_TIME;// 如果设立了截0 标志,则将该i 节点的文件长度截为0。if (flag & O_TRUNC)truncate(inode);// 最后返回该目录项i 节点的指针,并返回0(成功)。*res_inode = inode;return 0;}//// 系统调用函数 - 创建一个特殊文件或普通文件节点(node)。// 创建名称为filename,由mode 和dev 指定的文件系统节点(普通文件、设备特殊文件或命名管道)。// 参数:filename - 路径名;mode - 指定使用许可以及所创建节点的类型;dev - 设备号。// 返回:成功则返回0,否则返回出错码。int sys_mknod(const char * filename, int mode, int dev){const char * basename;int namelen;struct m_inode * dir, * inode;struct buffer_head * bh;struct dir_entry * de;// 如果不是超级用户,则返回访问许可出错码。if (!suser())return -EPERM;// 如果找不到对应路径名目录的i 节点,则返回出错码。if (!(dir = dir_namei(filename,&namelen,&basename)))return -ENOENT;// 如果最顶端的文件名长度为0,则说明给出的路径名最后没有指定文件名,释放该目录i 节点,返回// 出错码,退出。if (!namelen) {iput(dir);return -ENOENT;}// 如果在该目录中没有写的权限,则释放该目录的i 节点,返回访问许可出错码,退出。if (!permission(dir,MAY_WRITE)) {iput(dir);return -EPERM;}// 如果对应路径名上最后的文件名的目录项已经存在,则释放包含该目录项的高速缓冲区,释放目录// 的i 节点,返回文件已经存在出错码,退出。bh = find_entry(&dir,basename,namelen,&de);if (bh) {brelse(bh);iput(dir);return -EEXIST;}// 申请一个新的i 节点,如果不成功,则释放目录的i 节点,返回无空间出错码,退出。inode = new_inode(dir->i_dev);if (!inode) {iput(dir);return -ENOSPC;}// 设置该i 节点的属性模式。如果要创建的是块设备文件或者是字符设备文件,则令i 节点的直接块// 指针0 等于设备号。inode->i_mode = mode;if (S_ISBLK(mode) || S_ISCHR(mode))inode->i_zone[0] = dev;// 设置该i 节点的修改时间、访问时间为当前时间。inode->i_mtime = inode->i_atime = CURRENT_TIME;inode->i_dirt = 1;// 在目录中新添加一个目录项,如果失败(包含该目录项的高速缓冲区指针为NULL),则释放目录的// i 节点;所申请的i 节点引用连接计数复位,并释放该i 节点。返回出错码,退出。bh = add_entry(dir,basename,namelen,&de);if (!bh) {iput(dir);inode->i_nlinks=0;iput(inode);return -ENOSPC;}// 令该目录项的i 节点字段等于新i 节点号,置高速缓冲区已修改标志,释放目录和新的i 节点,释放// 高速缓冲区,最后返回0(成功)。de->inode = inode->i_num;bh->b_dirt = 1;iput(dir);iput(inode);brelse(bh);return 0;}//// 系统调用函数 - 创建目录。// 参数:pathname - 路径名;mode - 目录使用的权限属性。// 返回:成功则返回0,否则返回出错码。int sys_mkdir(const char * pathname, int mode){const char * basename;int namelen;struct m_inode * dir, * inode;struct buffer_head * bh, *dir_block;struct dir_entry * de;// 如果不是超级用户,则返回访问许可出错码。if (!suser())return -EPERM;// 如果找不到对应路径名目录的i 节点,则返回出错码。if (!(dir = dir_namei(pathname,&namelen,&basename)))return -ENOENT;// 如果最顶端的文件名长度为0,则说明给出的路径名最后没有指定文件名,释放该目录i 节点,返回// 出错码,退出。if (!namelen) {iput(dir);return -ENOENT;}// 如果在该目录中没有写的权限,则释放该目录的i 节点,返回访问许可出错码,退出。if (!permission(dir,MAY_WRITE)) {iput(dir);return -EPERM;}// 如果对应路径名上最后的文件名的目录项已经存在,则释放包含该目录项的高速缓冲区,释放目录// 的i 节点,返回文件已经存在出错码,退出。bh = find_entry(&dir,basename,namelen,&de);if (bh) {brelse(bh);iput(dir);return -EEXIST;}// 申请一个新的i 节点,如果不成功,则释放目录的i 节点,返回无空间出错码,退出。inode = new_inode(dir->i_dev);if (!inode) {iput(dir);return -ENOSPC;}// 置该新i 节点对应的文件长度为32(一个目录项的大小),置节点已修改标志,以及节点的修改时间// 和访问时间。inode->i_size = 32;inode->i_dirt = 1;inode->i_mtime = inode->i_atime = CURRENT_TIME;// 为该i 节点申请一磁盘块,并令节点第一个直接块指针等于该块号。如果申请失败,则释放对应目录// 的i 节点;复位新申请的i 节点连接计数;释放该新的i 节点,返回没有空间出错码,退出。if (!(inode->i_zone[0]=new_block(inode->i_dev))) {iput(dir);inode->i_nlinks--;iput(inode);return -ENOSPC;}// 置该新的i 节点已修改标志。inode->i_dirt = 1;// 读新申请的磁盘块。若出错,则释放对应目录的i 节点;释放申请的磁盘块;复位新申请的i 节点// 连接计数;释放该新的i 节点,返回没有空间出错码,退出。if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) {iput(dir);free_block(inode->i_dev,inode->i_zone[0]);inode->i_nlinks--;iput(inode);return -ERROR;}// 令de 指向目录项数据块,置该目录项的i 节点号字段等于新申请的i 节点号,名字字段等于"."。de = (struct dir_entry *) dir_block->b_data;de->inode=inode->i_num;strcpy(de->name, ".");// 然后de 指向下一个目录项结构,该结构用于存放上级目录的节点号和名字".."。de++;de->inode = dir->i_num;strcpy(de->name, "..");inode->i_nlinks = 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -