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

📄 ul_namei.cpp

📁 类似Linux操作系统0.11版文件系统的文件系统设计和Windows下的操作程序
💻 CPP
📖 第 1 页 / 共 3 页
字号:
			return NULL;
	}
}

// 参数:pathname - 目录路径名;namelen - 路径名长度。
// 返回:指定目录名最顶层目录的i 节点指针和最顶层目录名及其长度。
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_byte (pathname++))
		if (c == '/')
			basename = pathname;
	*namelen = (int)(pathname - basename - 1);
	*name = basename;
	return dir;
}

//// 取指定路径名的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;
}
//// 文件打开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 = 0; //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;
}
//// 创建目录
// 参数:pathname - 路径名;mode - 目录使用的权限属性。
// 返回:成功则返回0,否则返回出错码。
int UL_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;

	// 如果找不到对应路径名目录的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_size = sizeof(struct dir_entry)*2;
	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;
	// 然后设置该高速缓冲区已修改标志,并释放该缓冲区。
	dir_block->b_dirt = 1;
	brelse (dir_block);
	// 初始化设置新i 节点的模式字段,并置该i 节点已修改标志。
	inode->i_mode = I_DIRECTORY | (mode & 0777);
	inode->i_dirt = 1;
	// 在目录中新添加一个目录项,如果失败(包含该目录项的高速缓冲区指针为NULL),则释放目录的
	// i 节点;所申请的i 节点引用连接计数复位,并释放该i 节点。返回出错码,退出。
	bh = add_entry (dir, basename, namelen, &de);
	if (!bh)
	{
		iput (dir);
		free_block (inode->i_dev, inode->i_zone[0]);
		inode->i_nlinks = 0;
		iput (inode);
		return -ENOSPC;
	}
	// 令该目录项的i 节点字段等于新i 节点号,置高速缓冲区已修改标志,释放目录和新的i 节点,释放
	// 高速缓冲区,最后返回0(成功)。
	de->inode = inode->i_num;
	bh->b_dirt = 1;
	dir->i_nlinks++;
	dir->i_dirt = 1;
	iput (dir);
	iput (inode);
	brelse (bh);
	return 0;
}



//// 检查指定目录是否是空的。
// 参数:inode - 指定目录的i 节点指针。
// 返回:0 - 是空的;1 - 不空。
static int empty_dir (struct m_inode *inode)
{
	int nr, block;
	int len;
	struct buffer_head *bh;
	struct dir_entry *de;

⌨️ 快捷键说明

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