当前位置: 首页 > news >正文

实验28.文件删除 sys_unlink

已完成实验

《操作系统真相还原》部分实验记录

简介

实验 28. 文件删除 sys_unlink

总结

  • 删除文件: 1 删除目录项,2 释放 inode 的数据块和 inode 结构体

主要代码

  • 实现 inode_release 和 inode_delete (inode.c)

  • 实现 delete_dir_entry (dir.c)

  • 实现 sys_unlink (fs.c)

inode.c

/// @brief 释放inode
/// 在硬盘inode位图中标志该inode为空闲,并在块位图中标记他的所有块为空闲
/// @param part 分区
/// @param inode_no inode号
void inode_release(struct partition* part, uint32_t inode_no) {// 1. 打开inodestruct inode* inode_to_del = inode_open(part, inode_no);ASSERT(inode_to_del->i_no == inode_no);// 2.回收inode占用的所有块uint32_t all_blocks[140] = {0};  // 12个直接块+128个间接块// 2.1 先复制前12个直接块uint8_t block_idx = 0;while (block_idx < 12) {all_blocks[block_idx] = inode_to_del->i_sectors[block_idx];block_idx++;}// 2.2 再复制128个间接块uint32_t block_bitmap_idx;if (inode_to_del->i_sectors[12] != 0) {// 2.2.1 从硬盘间接块ide_read(part->my_disk, inode_to_del->i_sectors[12], all_blocks + 12, 1);// 2.2.2 回收一级间接块表占用的扇区block_bitmap_idx = inode_to_del->i_sectors[12] - part->sb->data_start_lba;  // 计算块偏移ASSERT(block_bitmap_idx > 0);bitmap_set(&part->block_bitmap, block_bitmap_idx, 0);   // 设置比特为空bitmap_sync(cur_part, block_bitmap_idx, BLOCK_BITMAP);  // 同步内存中的块位图到硬盘}// 2.3 inode所有的块地址已经收集到all_blocks中,下面逐个回收block_idx = 0;while (block_idx < 140) {if (all_blocks[block_idx] != 0) {block_bitmap_idx = 0;block_bitmap_idx = all_blocks[block_idx] - part->sb->data_start_lba;  // 计算块偏移ASSERT(block_bitmap_idx > 0);bitmap_set(&part->block_bitmap, block_bitmap_idx, 0);   // 设置位图比特为0bitmap_sync(cur_part, block_bitmap_idx, BLOCK_BITMAP);  // 同步块位图}block_idx++;}// 3 回收该inodebitmap_set(&part->inode_bitmap, inode_no, 0);bitmap_sync(cur_part, inode_no, INODE_BITMAP);// 以下inode_delete是调试用的// 把inode表中的inode结构全部归0起始没有意义// 因为位图已经标记为空闲了,下次用时也会重新初始化void* io_buf = sys_malloc(1024);inode_delete(part, inode_no, io_buf);sys_free(io_buf);// 4 关闭inodeinode_close(inode_to_del);
}/// @brief 初始化inode
/// 除了inode号全部默认值
/// @param inode_no inode号
/// @param new_inode inode指针
void inode_init(uint32_t inode_no, struct inode* new_inode) {new_inode->i_no = inode_no;new_inode->i_size = 0;new_inode->i_open_cnts = 0;new_inode->write_deny = false;// 初始化块索引数组i_sectoruint8_t sec_idx = 0;while (sec_idx < 13) {// i_sectors[12]为一级间接块地址new_inode->i_sectors[sec_idx] = 0;sec_idx++;}
}

dir.c

/// @brief 删除目录项
/// 遍历目录pdir中的目录项,删除inode号为inode_no的目录项
/// @param part
/// @param pdir
/// @param inode_no
/// @param io_buf
/// @return 成功返回1, 失败返回0
bool delete_dir_entry(struct partition* part, struct dir* pdir, uint32_t inode_no, void* io_buf) {struct inode* dir_inode = pdir->inode;// 1.收集父目录全部块地址uint32_t block_idx = 0, all_blocks[140] = {0};while (block_idx < 12) {all_blocks[block_idx] = dir_inode->i_sectors[block_idx];block_idx++;}if (dir_inode->i_sectors[12]) { ide_read(part->my_disk, dir_inode->i_sectors[12], all_blocks + 12, 1); }/* 目录项在存储时保证不会跨扇区 */uint32_t dir_entry_size = part->sb->dir_entry_size;uint32_t dir_entrys_per_sec = (SECTOR_SIZE / dir_entry_size);  // 每扇区最大的目录项数目struct dir_entry* dir_e = (struct dir_entry*)io_buf;struct dir_entry* dir_entry_found = NULL;uint8_t dir_entry_idx, dir_entry_cnt;bool is_dir_first_block = false;  // 目录的第1个块// 2 遍历所有块,寻找目录项block_idx = 0;while (block_idx < 140) {is_dir_first_block = false;if (all_blocks[block_idx] == 0) {block_idx++;continue;}dir_entry_idx = dir_entry_cnt = 0;memset(io_buf, 0, SECTOR_SIZE);// 2.1 读取扇区,获得目录项ide_read(part->my_disk, all_blocks[block_idx], io_buf, 1);// 2.2 遍历所有的目录项,统计该扇区的目录项数量及是否有待删除的目录项while (dir_entry_idx < dir_entrys_per_sec) {if ((dir_e + dir_entry_idx)->f_type != FT_UNKNOWN) {if (!strcmp((dir_e + dir_entry_idx)->filename, ".")) {is_dir_first_block = true;} else if (strcmp((dir_e + dir_entry_idx)->filename, ".") &&strcmp((dir_e + dir_entry_idx)->filename, "..")) {  // 是普通文件dir_entry_cnt++;if ((dir_e + dir_entry_idx)->i_no == inode_no) {  // 如果找到此i结点,就将其记录在dir_entry_found// 确保目录中只有一个编号为inode_no的inode,找到一次后dir_entry_found就不再是NULLASSERT(dir_entry_found == NULL);dir_entry_found = dir_e + dir_entry_idx;  // 找到后也继续遍历,统计总共的目录项数}}}dir_entry_idx++;}// 2.3 若此扇区未找到该目录项,继续在下个扇区中找if (dir_entry_found == NULL) {block_idx++;continue;}// 2.4 在此扇区中找到目录项后,清除该目录项并判断是否回收扇区,随后退出循环直接返回ASSERT(dir_entry_cnt >= 1);// 2.4.1 除目录第1个扇区外,若该扇区上只有该目录项自己,则将整个扇区回收if (dir_entry_cnt == 1 && !is_dir_first_block) {/* a 在块位图中回收该块 */uint32_t block_bitmap_idx = all_blocks[block_idx] - part->sb->data_start_lba;bitmap_set(&part->block_bitmap, block_bitmap_idx, 0);bitmap_sync(cur_part, block_bitmap_idx, BLOCK_BITMAP);/* b 将块地址从数组i_sectors或索引表中去掉 */if (block_idx < 12) {dir_inode->i_sectors[block_idx] = 0;} else {  // 在一级间接索引表中擦除该间接块地址/*先判断一级间接索引表中间接块的数量,如果仅有这1个间接块,连同间接索引表所在的块一同回收 */uint32_t indirect_blocks = 0;uint32_t indirect_block_idx = 12;while (indirect_block_idx < 140) {if (all_blocks[indirect_block_idx] != 0) { indirect_blocks++; }}ASSERT(indirect_blocks >= 1);  // 包括当前间接块if (indirect_blocks > 1) {  // 间接索引表中还包括其它间接块,仅在索引表中擦除当前这个间接块地址all_blocks[block_idx] = 0;ide_write(part->my_disk, dir_inode->i_sectors[12], all_blocks + 12, 1);} else {  // 间接索引表中就当前这1个间接块,直接把间接索引表所在的块回收,然后擦除间接索引表块地址/* 回收间接索引表所在的块 */block_bitmap_idx = dir_inode->i_sectors[12] - part->sb->data_start_lba;bitmap_set(&part->block_bitmap, block_bitmap_idx, 0);bitmap_sync(cur_part, block_bitmap_idx, BLOCK_BITMAP);/* 将间接索引表地址清0 */dir_inode->i_sectors[12] = 0;}}} else {  // 仅将该目录项清空memset(dir_entry_found, 0, dir_entry_size);ide_write(part->my_disk, all_blocks[block_idx], io_buf, 1);}//  更新i结点信息并同步到硬盘ASSERT(dir_inode->i_size >= dir_entry_size);dir_inode->i_size -= dir_entry_size;memset(io_buf, 0, SECTOR_SIZE * 2);inode_sync(part, dir_inode, io_buf);return true;}return false;
}

fs.c

/// @brief 删除文件(非目录)
/// @param pathname
/// @return 成功返回0,失败返回-1
int32_t sys_unlink(const char* pathname) {ASSERT(strlen(pathname) < MAX_PATH_LEN);// 0 先检查待删除的文件是否存在struct path_search_record searched_record;memset(&searched_record, 0, sizeof(struct path_search_record));int inode_no = search_file(pathname, &searched_record);ASSERT(inode_no != 0);if (inode_no == -1) {printk("file %s not found!\n", pathname);dir_close(searched_record.parent_dir);return -1;}if (searched_record.file_type == FT_DIRECTORY) {printk("can`t delete a direcotry with unlink(), use rmdir() to instead\n");dir_close(searched_record.parent_dir);return -1;}// 1 检查是否在已打开文件列表(文件表)中uint32_t file_idx = 0;while (file_idx < MAX_FILE_OPEN) {if (file_table[file_idx].fd_inode != NULL && (uint32_t)inode_no == file_table[file_idx].fd_inode->i_no) {break;}file_idx++;}if (file_idx < MAX_FILE_OPEN) {dir_close(searched_record.parent_dir);printk("file %s is in use, not allow to delete!\n", pathname);return -1;}ASSERT(file_idx == MAX_FILE_OPEN);// 3 删除这个文件void* io_buf = sys_malloc(SECTOR_SIZE + SECTOR_SIZE);if (io_buf == NULL) {dir_close(searched_record.parent_dir);printk("sys_unlink: malloc for io_buf failed\n");return -1;}// 3.1 删除目录项struct dir* parent_dir = searched_record.parent_dir;delete_dir_entry(cur_part, parent_dir, inode_no, io_buf);// 3.2 释放这个inodeinode_release(cur_part, inode_no);sys_free(io_buf);dir_close(searched_record.parent_dir);return 0;  // 成功删除文件
}

main.c

int main(void) {put_str("I am kernel\n");init_all();process_execute(u_prog_a, "user_prog_a");process_execute(u_prog_b, "user_prog_b");thread_start("k_thread_a", 31, k_thread_a, "argA ");thread_start("k_thread_b", 31, k_thread_b, "argB ");// 1 创建文件uint32_t fd = sys_open("/file1", O_CREAT);if (fd) printf("create /file1 %s\n", fd != -1 ? "success" : "failed");int r = sys_close(fd);if (fd) printf("close /file1 %s\n", r == 0 ? "success" : "failed");// 2 删除文件int ret = sys_unlink("/file1");printf("delete /file1 %s\n", ret == 0 ? "success" : "failed");while (1);return 0;
}

在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 微信小程序实战教程-1:京西购物商城实战
  • 【数据结构】B树
  • 【物联网】(指纹篇)在指纹录入的流程中,如何确保指纹信息的准确性?
  • 【星闪开发连载】WS63E开发板Windows环境的构建
  • Unity 输入模块 之 初识新输入系统(其实也不新)
  • Java高级Day26-绘制坦克大战
  • stm32入门学习13-时钟RTC
  • Ubuntu基础使用
  • Kylin系列(一)入门
  • 模板中class与typename的辨析
  • Chainlit快速实现AI对话应用并将聊天数据的AWS S3 和 Azure Blob云服务中
  • Android Studio本地加速安装gradle
  • DrawState与wms绘制流程梳理
  • RabbitMQ延迟队列
  • H5 优化手段
  • 【159天】尚学堂高琪Java300集视频精华笔记(128)
  • CSS居中完全指南——构建CSS居中决策树
  • iOS 系统授权开发
  • JavaScript DOM 10 - 滚动
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • PAT A1017 优先队列
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • Promise面试题,控制异步流程
  • TCP拥塞控制
  • WordPress 获取当前文章下的所有附件/获取指定ID文章的附件(图片、文件、视频)...
  • zookeeper系列(七)实战分布式命名服务
  • 笨办法学C 练习34:动态数组
  • 从setTimeout-setInterval看JS线程
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • 分布式熔断降级平台aegis
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 面试遇到的一些题
  • 如何设计一个微型分布式架构?
  • 使用 @font-face
  • 学习Vue.js的五个小例子
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • Java总结 - String - 这篇请使劲喷我
  • 关于Android全面屏虚拟导航栏的适配总结
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • #考研#计算机文化知识1(局域网及网络互联)
  • (2024,LoRA,全量微调,低秩,强正则化,缓解遗忘,多样性)LoRA 学习更少,遗忘更少
  • (55)MOS管专题--->(10)MOS管的封装
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (多级缓存)多级缓存
  • (二)PySpark3:SparkSQL编程
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (四)opengl函数加载和错误处理
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • .NET 5.0正式发布,有什么功能特性(翻译)
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .NET大文件上传知识整理
  • .net快速开发框架源码分享