⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 namei.c

📁 带中文注释的 linux 0.11 源代码0.11,很好的
💻 C
📖 第 1 页 / 共 4 页
字号:
	    return NULL;// 如果读取磁盘块返回的指针为空,则跳过该块继续。	  if (!(bh = bread (dir->i_dev, block)))	    {	      i += DIR_ENTRIES_PER_BLOCK;	      continue;	    }// 否则,让目录项结构指针de 志向该块的高速缓冲数据块开始处。	  de = (struct dir_entry *) bh->b_data;	}// 如果当前所操作的目录项序号i*目录结构大小已经超过了该目录所指出的大小i_size,则说明该第i// 个目录项还未使用,我们可以使用它。于是对该目录项进行设置(置该目录项的i 节点指针为空)。并// 更新该目录的长度值(加上一个目录项的长度,设置目录的i 节点已修改标志,再更新该目录的改变时// 间为当前时间。      if (i * sizeof (struct dir_entry) >= dir->i_size)	{	  de->inode = 0;	  dir->i_size = (i + 1) * sizeof (struct dir_entry);	  dir->i_dirt = 1;	  dir->i_ctime = CURRENT_TIME;	}// 若该目录项的i 节点为空,则表示找到一个还未使用的目录项。于是更新目录的修改时间为当前时间。// 并从用户数据区复制文件名到该目录项的文件名字段,置相应的高速缓冲块已修改标志。返回该目录// 项的指针以及该高速缓冲区的指针,退出。      if (!de->inode)	{	  dir->i_mtime = CURRENT_TIME;	  for (i = 0; i < NAME_LEN; i++)	    de->name[i] = (i < namelen) ? get_fs_byte (name + i) : 0;	  bh->b_dirt = 1;	  *res_dir = de;	  return bh;	}// 如果该目录项已经被使用,则继续检测下一个目录项。      de++;      i++;    }// 执行不到这里。也许Linus 在写这段代码时是先复制了上面find_entry()的代码,而后修改的?。  brelse (bh);  return NULL;}/** get_dir()** Getdir traverses the pathname until it hits the topmost directory.* It returns NULL on failure.*//** get_dir()* 该函数根据给出的路径名进行搜索,直到达到最顶端的目录。* 如果失败则返回NULL。*///// 搜寻指定路径名的目录。// 参数:pathname - 路径名。// 返回:目录的i 节点指针。失败时返回NULL。static struct m_inode *get_dir (const char *pathname){  char c;  const char *thisname;  struct m_inode *inode;  struct buffer_head *bh;  int namelen, inr, idev;  struct dir_entry *de;// 如果进程没有设定根i 节点,或者该进程根i 节点的引用为0,则系统出错,死机。  if (!current->root || !current->root->i_count)    panic ("No root inode");// 如果进程的当前工作目录指针为空,或者该当前目录i 节点的引用计数为0,也是系统有问题,死机。  if (!current->pwd || !current->pwd->i_count)    panic ("No cwd inode");// 如果用户指定的路径名的第1 个字符是'/',则说明路径名是绝对路径名。则从根i 节点开始操作。  if ((c = get_fs_byte (pathname)) == '/')    {      inode = current->root;      pathname++;// 否则若第一个字符是其它字符,则表示给定的是相对路径名。应从进程的当前工作目录开始操作。// 则取进程当前工作目录的i 节点。    }  else if (c)    inode = current->pwd;// 否则表示路径名为空,出错。返回NULL,退出。  else    return NULL;		/* empty name is bad *//* 空的路径名是错误的 */// 将取得的i 节点引用计数增1。  inode->i_count++;  while (1)    {// 若该i 节点不是目录节点,或者没有可进入的访问许可,则释放该i 节点,返回NULL,退出。      thisname = pathname;      if (!S_ISDIR (inode->i_mode) || !permission (inode, MAY_EXEC))	{	  iput (inode);	  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 节点指针。intopen_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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -