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

📄 ul_namei.cpp

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

	// 计算指定目录中现有目录项的个数(应该起码有2 个,即"."和".."两个文件目录项)。
	len = inode->i_size / sizeof (struct dir_entry);
	// 如果目录项个数少于2 个或者该目录i 节点的第1 个直接块没有指向任何磁盘块号,或者相应磁盘
	// 块读不出,则显示警告信息“设备dev 上目录错”,返回0(失败)。
	if (len < 2 || !inode->i_zone[0] ||
		!(bh = bread (inode->i_dev, inode->i_zone[0])))
	{
		printk ("warning - bad directory on dev %04x\n", inode->i_dev);
		return 0;
	}
	// 让de 指向含有读出磁盘块数据的高速缓冲区中第1 项目录项。
	de = (struct dir_entry *) bh->b_data;
	// 如果第1 个目录项的i 节点号字段值不等于该目录的i 节点号,或者第2 个目录项的i 节点号字段
	// 为零,或者两个目录项的名字字段不分别等于"."和"..",则显示出错警告信息“设备dev 上目录错”
	// 并返回0。
	if (de[0].inode != inode->i_num || !de[1].inode ||
		strcmp (".", de[0].name) || strcmp ("..", de[1].name))
	{
		printk ("warning - bad directory on dev %04x\n", inode->i_dev);
		return 0;
	}
	// 令nr 等于目录项序号;de 指向第三个目录项。
	nr = 2;
	de += 2;
	// 循环检测该目录中所有的目录项(len-2 个),看有没有目录项的i 节点号字段不为0(被使用)。
	while (nr < len)
	{
		// 如果该块磁盘块中的目录项已经检测完,则释放该磁盘块的高速缓冲区,读取下一块含有目录项的
		// 磁盘块。若相应块没有使用(或已经不用,如文件已经删除等),则继续读下一块,若读不出,则出
		// 错,返回0。否则让de 指向读出块的首个目录项。
		if ((void *) de >= (void *) (bh->b_data + BLOCK_SIZE))
		{
			brelse (bh);
			block = bmap (inode, nr / DIR_ENTRIES_PER_BLOCK);
			if (!block)
			{
				nr += DIR_ENTRIES_PER_BLOCK;
				continue;
			}
			if (!(bh = bread (inode->i_dev, block)))
				return 0;
			de = (struct dir_entry *) bh->b_data;
		}
		// 如果该目录项的i 节点号字段不等于0,则表示该目录项目前正被使用,则释放该高速缓冲区,
		// 返回0,退出。
		if (de->inode)
		{
			brelse (bh);
			return 0;
		}
		// 否则,若还没有查询完该目录中的所有目录项,则继续检测。
		de++;
		nr++;
	}
	// 到这里说明该目录中没有找到已用的目录项(当然除了头两个以外),则返回缓冲区,返回1。
	brelse (bh);
	return 1;
}

//// 系统调用函数 - 删除指定名称的目录。
// 参数: name - 目录名(路径名)。
// 返回:返回0 表示成功,否则返回出错号。
int UL_rmdir (const char *pathname)
{
	const char *basename;
	int namelen;
	struct m_inode *dir, *inode;
	struct buffer_head *bh;
	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 节点,返回文件已经存在出错码,退出。否则dir 是包含要被删除目录名的目录i 节点,de
	// 是要被删除目录的目录项结构。
	bh = find_entry (&dir, basename, namelen, &de);
	if (!bh)
	{
		iput (dir);
		return -ENOENT;
	}
	// 取该目录项指明的i 节点。若出错则释放目录的i 节点,并释放含有目录项的高速缓冲区,返回
	// 出错号。
	if (!(inode = iget (dir->i_dev, de->inode)))
	{
		iput (dir);
		brelse (bh);
		return -EPERM;
	}
	// 若该目录设置了受限删除标志并且进程的有效用户id 不等于该i 节点的用户id,则表示没有权限删
	// 除该目录,于是释放包含要删除目录名的目录i 节点和该要删除目录的i 节点,释放高速缓冲区,返
	// 回出错码。
	/*
	if ((dir->i_mode & S_ISVTX) && current->euid &&
		inode->i_uid != current->euid)
	{
		iput (dir);
		iput (inode);
		brelse (bh);
		return -EPERM;
	}
	*/
	// 如果要被删除的目录项的i 节点的设备号不等于包含该目录项的目录的设备号,或者该被删除目录的
	// 引用连接计数大于1(表示有符号连接等),则不能删除该目录,于是释放包含要删除目录名的目录
	// i 节点和该要删除目录的i 节点,释放高速缓冲区,返回出错码。
	if (inode->i_dev != dir->i_dev || inode->i_count > 1)
	{
		iput (dir);
		iput (inode);
		brelse (bh);
		return -EPERM;
	}
	// 如果要被删除目录的目录项i 节点的节点号等于包含该需删除目录的i 节点号,则表示试图删除"."
	// 目录。于是释放包含要删除目录名的目录i 节点和该要删除目录的i 节点,释放高速缓冲区,返回
	// 出错码。
	if (inode == dir)
	{				/* we may not delete ".", but "../dir" is ok */
		iput (inode);		/* 我们不可以删除".",但可以删除"../dir" */
		iput (dir);
		brelse (bh);
		return -EPERM;
	}
	// 若要被删除的目录的i 节点的属性表明这不是一个目录,则释放包含要删除目录名的目录i 节点和
	// 该要删除目录的i 节点,释放高速缓冲区,返回出错码。
	if (!S_ISDIR (inode->i_mode))
	{
		iput (inode);
		iput (dir);
		brelse (bh);
		return -ENOTDIR;
	}
	// 若该需被删除的目录不空,则释放包含要删除目录名的目录i 节点和该要删除目录的i 节点,释放
	// 高速缓冲区,返回出错码。
	if (!empty_dir (inode))
	{
		iput (inode);
		iput (dir);
		brelse (bh);
		return -ENOTEMPTY;
	}
	// 若该需被删除目录的i 节点的连接数不等于2,则显示警告信息。
	if (inode->i_nlinks != 2)
		printk ("empty directory has nlink!=2 (%d)", inode->i_nlinks);
	// 置该需被删除目录的目录项的i 节点号字段为0,表示该目录项不再使用,并置含有该目录项的高速
	// 缓冲区已修改标志,并释放该缓冲区。
	de->inode = 0;
	bh->b_dirt = 1;
	brelse (bh);
	// 置被删除目录的i 节点的连接数为0,并置i 节点已修改标志。
	inode->i_nlinks = 0;
	inode->i_dirt = 1;
	// 将包含被删除目录名的目录的i 节点引用计数减1,修改其改变时间和修改时间为当前时间,并置
	// 该节点已修改标志。
	dir->i_nlinks--;
	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
	dir->i_dirt = 1;
	// 最后释放包含要删除目录名的目录i 节点和该要删除目录的i 节点,返回0(成功)。
	iput (dir);
	iput (inode);
	return 0;
}

//// 重命名
// 参数: pathname - 路径名
//		  name - 新名称
int UL_rename (const char *pathname, const char *name)
{
	const char *basename;
	int namelen;
	struct m_inode *dir, *inode;
	struct buffer_head *bh;
	struct dir_entry *de;

	if (strlen(name)>NAME_LEN)
		return -EPERM;

	// 如果找不到对应路径名目录的i 节点,则返回出错码。
	if (!(dir = dir_namei (pathname, &namelen, &basename)))
		return -ENOENT;

	// 如果最顶端的文件名长度为0,则说明给出的路径名最后没有指定文件名,释放该目录i 节点,返回
	// 出错码,退出。
	if (!namelen)
	{
		iput (dir);
		return -ENOENT;
	}

	if (namelen==2 && !strncmp(basename, "..", 2))
	{
		iput (dir);
		return -ENOENT;
	}
	
	if (namelen==1 && !strncmp(basename, ".", 1))
	{
		iput (dir);
		return -ENOENT;
	}
	// 同名
	if (!strncmp(basename, name, namelen))	
	{
		iput (dir);
		return -ENOENT;
	}


	// 如果在该目录中没有写的权限,则释放该目录的i 节点,返回访问许可出错码,退出。
	if (!permission (dir, MAY_WRITE))
	{
		iput (dir);
		return -EPERM;
	}

	// 如果新文件已经存在了
	bh = find_entry (&dir, name, strlen(name), &de);
	if (bh) 
	{
		iput (dir);
		brelse (bh);
		return -ENOENT;
	}

	// 如果对应路径名上最后的文件名的目录项不存在,则释放包含该目录项的高速缓冲区,释放目录
	// 的i 节点,返回文件已经存在出错码,退出。否则dir 是包含要被删除目录名的目录i 节点,de
	// 是要被删除目录的目录项结构。
	bh = find_entry (&dir, basename, namelen, &de);
	if (!bh)
	{
		iput (dir);
		return -ENOENT;
	}
	// 取该目录项指明的i 节点。若出错则释放目录的i 节点,并释放含有目录项的高速缓冲区,返回
	// 出错号。
	if (!(inode = iget (dir->i_dev, de->inode)))
	{
		iput (dir);
		brelse (bh);
		return -EPERM;
	}
	// 若该目录设置了受限删除标志并且进程的有效用户id 不等于该i 节点的用户id,则表示没有权限删
	// 除该目录,于是释放包含要删除目录名的目录i 节点和该要删除目录的i 节点,释放高速缓冲区,返
	// 回出错码。
	/*
	if ((dir->i_mode & S_ISVTX) && current->euid &&
	inode->i_uid != current->euid)
	{
	iput (dir);
	iput (inode);
	brelse (bh);
	return -EPERM;
	}
	*/
	// 如果要被删除的目录项的i 节点的设备号不等于包含该目录项的目录的设备号,或者该被删除目录的
	// 引用连接计数大于1(表示有符号连接等),则不能删除该目录,于是释放包含要删除目录名的目录
	// i 节点和该要删除目录的i 节点,释放高速缓冲区,返回出错码。
	if (inode->i_dev != dir->i_dev || inode->i_count > 1)
	{
		iput (dir);
		iput (inode);
		brelse (bh);
		return -EPERM;
	}

	// 若该需被删除目录的i 节点的连接数不等于2,则显示警告信息。
	if (inode->i_nlinks != 2)
		printk ("file renamed has nlink!=2 (%d)", inode->i_nlinks);

	// 置含有该目录项的高速缓冲区已修改标志,并释放该缓冲区。
	strcpy(de->name, name);
	bh->b_dirt = 1;
	brelse (bh);
	// 置被更名目录的i 节点已修改标志。
	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
	inode->i_dirt = 1;
	// 最后释放包含要删除目录名的目录i 节点和该要删除目录的i 节点,返回0(成功)。
	iput (dir);
	iput (inode);
	return 0;
}

⌨️ 快捷键说明

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