文章目录

  • 专栏博客链接
  • 相关查阅博客链接
  • 本书中错误勘误
  • 实现文件删除
    • 编写完的inode.c(inode_delete函数)
    • 编写完的dir.c(delete_dir_entry函数)
    • 编写完的fs.c(sys_unlink函数)
    • 修改完的main.c
    • make all 验证成果
  • 实现创建目录
    • 编写完的fs.c(sys_mkdir)
    • 修改完的main.c
    • make all 验证成果

专栏博客链接


《操作系统真象还原》从零开始自制操作系统 全章节博客链接


相关查阅博客链接



本书中错误勘误


这个地方我思考了很久 我觉得应该而且是必须要这么做的 需要加两行代码
这个问题就是dir.c中的函数delete_dir_entry
在对于分配的块位图中只有一个目录项且刚好是我们要删除的目录项

且分配的块位图是在 间接块表中 间接块表刚好只分配了这一个块表
按理说 我们需要回收这个块 且要把分配给间接块的这个块也给回收了
书上认为 我们只把间接块回收了即可 那个在间接块中的那个块 就等于回收掉了 但我认为必须要把那个块给写成空白才可以 不然的话 下次再分配里面还是有这个目录项 而且分配目录项看空位的时候就是看是否有目录项在那里 是否是空白的
由于文件系统过于庞大 这里就先存疑吧 但是写了心里面总是放心的


实现文件删除


编写完的inode.c(inode_delete函数)


//清除inode_table中的inode
void inode_delete(struct partition* part,uint32_t inode_no,void* io_buf)
{ASSERT(inode_no < 4096);struct inode_position inode_pos;    //存储inode的pos的inode_locate(part,inode_no,&inode_pos);ASSERT(inode_pos.sec_lba <= (part->start_lba + part->sec_cnt));char* inode_buf = (char*)io_buf;if(inode_pos.two_sec){ide_read(part->my_disk,inode_pos.sec_lba,inode_buf,2); //夹在两个扇区间memset((inode_buf + inode_pos.off_size),0,sizeof(struct inode)); //把inode信息清除 再次写回硬盘ide_write(part->my_disk,inode_pos.sec_lba,inode_buf,2); }else{ide_read(part->my_disk,inode_pos.sec_lba,inode_buf,1);    //夹在两个扇区间memset((inode_buf + inode_pos.off_size),0,sizeof(struct inode)); //把inode信息清除 再次写回硬盘ide_write(part->my_disk,inode_pos.sec_lba,inode_buf,1); }
}

编写完的dir.c(delete_dir_entry函数)


//把pdir中编号为inode_no目录项删除
bool delete_dir_entry(struct partition* part,struct dir* pdir,uint32_t inode_no,void* io_buf)
{struct inode* dir_inode = pdir->inode;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);//目录项存储不像inode那样存在夹在两个扇区间的情况    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;     //目录的第一个块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);ide_read(part->my_disk,all_blocks[block_idx],io_buf,1);//挨个挨个遍历寻找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){ASSERT(dir_entry_found == NULL);dir_entry_found = dir_e + dir_entry_idx;//继续遍历 统计共有多少目录项}}}++dir_entry_idx;}//这个扇区没找到 到一下个扇区继续找if(dir_entry_found == NULL){++block_idx;continue;}ASSERT(dir_entry_cnt >= 1);//不包括根目录 该块且只有一个目录项 这个目录项刚好是我们需要删除的if(dir_entry_cnt == 1 && !is_dir_first_block){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);  //块同步进去if(block_idx < 12)dir_inode->i_sectors[block_idx]  = 0;else //还需要判断是否要把间接块表回收回去{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; //那个地方的块地址写成0ide_write(part->my_disk,dir_inode->i_sectors[12],all_blocks+ 12,1);}else //先回收那个块表{/*这里是我加的*/all_blocks[block_idx] = 0; //那个地方的块地址写成0ide_write(part->my_disk,dir_inode->i_sectors[12],all_blocks+ 12,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);}}}else{memset(dir_entry_found,0,dir_entry_size);//把那里的目录项清一条即可ide_write(part->my_disk,all_blocks[block_idx],io_buf,1);}    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);   //把inode写入硬盘return true;}return false;
}

编写完的fs.c(sys_unlink函数)


//删除普通文件
int32_t sys_unlink(const char* pathname)
{ASSERT(strlen(pathname) < MAX_PATH_LEN);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("cant delete a directory with unlink(),use rmdir() to instead\n");dir_close(searched_record.parent_dir);return -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 allowed to delete!\n",pathname);return -1;}ASSERT(file_idx == MAX_FILE_OPEN);void* io_buf = sys_malloc(1024);if(io_buf == NULL){dir_close(searched_record.parent_dir);printk("sys_unlink: malloc for io_buf failed!\n");return -1;}struct dir* parent_dir = searched_record.parent_dir;delete_dir_entry(cur_part,parent_dir,inode_no,io_buf);//删除目录项inode_release(cur_part,inode_no);                //删除inodesys_free(io_buf);dir_close(searched_record.parent_dir);return 0;   //成功删除}

修改完的main.c


#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
#include "memory.h"
#include "../thread/thread.h"
#include "interrupt.h"
#include "../device/console.h"
#include "../device/ioqueue.h"
#include "../device/keyboard.h"
#include "../userprog/process.h"
#include "../lib/user/syscall.h"
#include "../userprog/syscall-init.h"
#include "../lib/stdio.h"
#include "../lib/kernel/stdio-kernel.h"
#include "../fs/fs.h"
#include "../fs/file.h"int main(void)
{put_str("I am kernel\n");init_all();intr_enable();char buf[64] = {0};int fd = sys_open("/file1",O_CREAT);sys_close(fd);   fd = sys_open("/file1",O_RDWR);sys_write(fd,"hello,world\n",12);sys_close(fd);printk("/file1 delete %s!\n",sys_unlink("/file1") == 0 ? "done" : "fail");while(1);return 0;
}

make all 验证成果


实话实说 在make all 调试的路上

下面是创建了文件/file1 写入文件hello,world\n字符串 没有删除的时候的截图
第一个表是 块位图的表
第二个是inode位图的表

第三个是inode_table的表
第四个是根目录所在扇区的内容


main.c那行
printk("/file1 delete %s!\n",sys_unlink("/file1") == 0 ? "done" : "fail")取消注释

重新编译 得到下面结果 但是保险期间 表面的输出并不能让我们信服 我们还是看看硬盘中的信息吧


我们可以很明显的看到
块位图中只有1个了 剩下的那个是根目录要分配的块
inode也只有一个 也是根目录的那个

再下面的inode_table可以看到之前在的inode信息也已经被置空了
最下面的是根目录所在扇区 只有一个目录项了

从这里看 实现应该是成功了


实现创建目录


编写完的fs.c(sys_mkdir)


//创建目录 成功返回0 失败返回-1
int32_t sys_mkdir(const char* pathname)
{uint8_t rollback_step = 0;void* io_buf = sys_malloc(SECTOR_SIZE * 2);if(io_buf == NULL){printk("sys_mkdir: sys_malloc for io_buf failed\n");return -1;}struct path_search_record searched_record;memset(&searched_record,0,sizeof(struct path_search_record));int inode_no = -1;inode_no = search_file(pathname,&searched_record);if(inode_no != -1)  //如果找到同名的 目录或者文件 则inode_no 肯定不为-1 则进入逆转{printk("sys_mkdir: file or directory %s exist\n",pathname);rollback_step = 1;goto rollback;}else{uint32_t pathname_depth = path_depth_cnt((char*)pathname); uint32_t path_searched_depth = path_depth_cnt(searched_record.searched_path);//看深度是否相同 不相同说明到中间某处就找不到停止了 可带入两个路径看看效果if(pathname_depth != path_searched_depth){printk("sys_mkdir: cannot access %s: Not a directory,subpath %s isnt exist\n",pathname,searched_record.searched_path);rollback_step = 1;goto rollback;}}struct dir* parent_dir = searched_record.parent_dir; //得到最后路径的直接父路径char* dirname = strrchr(searched_record.searched_path,'/') + 1; //得到最后目标目录名称inode_no = inode_bitmap_alloc(cur_part);  //得到新分配的inode结点 if(inode_no == -1){printk("sys_mkdir: allocate inode failed\n");rollback_step = 1;goto rollback;}//即将要使用的inode 负责memcpy到硬盘中struct inode new_dir_inode;inode_init(inode_no,&new_dir_inode);//再分配一个块uint32_t block_bitmap_idx = 0;int32_t  block_lba = -1;block_lba = block_bitmap_alloc(cur_part);if(block_lba == -1){printk("sys_mkdir: block_bitmap_alloc for create directory failed\n");rollback_step = 2; //把之前的inode给回滚了goto rollback;}   new_dir_inode.i_sectors[0] = block_lba;block_bitmap_idx = block_lba - cur_part->sb->data_start_lba;ASSERT(block_bitmap_idx != 0);bitmap_sync(cur_part,block_bitmap_idx,BLOCK_BITMAP);//'.' 和 '..'写入目录中memset(io_buf,0,SECTOR_SIZE * 2);struct dir_entry* p_de = (struct dir_entry*)io_buf;//第一个目录项 .memcpy(p_de->filename,".",1);p_de->i_no = inode_no;p_de->f_type = FT_DIRECTORY;//移动到下一个目录项的位置 ..p_de++;  memcpy(p_de->filename,"..",2);p_de->i_no = parent_dir->inode->i_no;;p_de->f_type = FT_DIRECTORY;ide_write(cur_part->my_disk,new_dir_inode.i_sectors[0],io_buf,1);new_dir_inode.i_size = 2 * cur_part->sb->dir_entry_size;struct dir_entry new_dir_entry;memset(&new_dir_entry,0,sizeof(struct dir_entry));memset(io_buf,0,SECTOR_SIZE * 2);//目录项存放在new_dir_entry中 new_inode已经初始化好了 里面的数据也都填了create_dir_entry(dirname,inode_no,FT_DIRECTORY,&new_dir_entry); //失败了if(!sync_dir_entry(parent_dir,&new_dir_entry,io_buf)){printk("sys_mkdir: sync_dir_entry to disk_failed\n");rollback_step = 2;goto rollback;}//父结点的inode写入到硬盘中memset(io_buf,0,SECTOR_SIZE * 2);inode_sync(cur_part,parent_dir->inode,io_buf);//新建立的写入到硬盘中memset(io_buf,0,SECTOR_SIZE * 2);inode_sync(cur_part,&new_dir_inode,io_buf);bitmap_sync(cur_part,inode_no,INODE_BITMAP);sys_free(io_buf);dir_close(searched_record.parent_dir);return 0;rollback:switch(rollback_step){case 2:bitmap_set(&cur_part->inode_bitmap,inode_no,0);case 1:dir_close(searched_record.parent_dir);break;}sys_free(io_buf);return -1;
}

修改完的main.c


#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
#include "memory.h"
#include "../thread/thread.h"
#include "interrupt.h"
#include "../device/console.h"
#include "../device/ioqueue.h"
#include "../device/keyboard.h"
#include "../userprog/process.h"
#include "../lib/user/syscall.h"
#include "../userprog/syscall-init.h"
#include "../lib/stdio.h"
#include "../lib/kernel/stdio-kernel.h"
#include "../fs/fs.h"
#include "../fs/file.h"int main(void)
{put_str("I am kernel\n");init_all();intr_enable();printk("/dir1/subdir1 create %s!\n",(sys_mkdir("/dir1/subdir1") == 0) ? "done" : "fail");printk("/dir1 create %s!\n",(sys_mkdir("/dir1") == 0) ? "done" : "fail");printk("/dir1/subdir1 create %s!\n",(sys_mkdir("/dir1/subdir1") == 0) ? "done" : "fail");int fd = sys_open("/dir1/subdir1/file2",O_CREAT | O_RDWR);if(fd != -1){printk("/dir1/subdir1/file2 create done!\n");sys_write(fd,"Catch me if u can!\n",19);sys_lseek(fd,0,SEEK_SET);char buf[32] = {0};sys_read(fd,buf,19);printf("/dir1/subdir1/file2 says:\n%s",buf);sys_close(fd);}while(1);return 0;
}

make all 验证成果


先看看bochs屏幕输出了些什么 嗯?感觉应该是对的 但是表面现象不能迷惑住我们 我们要透过里面看内在 再来看我们是否成功建立了目录了

我们的思路是
先去看看根目录所在的扇区下的/dir1 再根据目录项/dir1继续往下找
lets go


我们根据之前得到的数据 root_start_lba是在0xA67
0XA67 * 512得到了 1363456

我们可以可以清楚看到右边的字节显示dir1 嗯 没错
我们看到64下面的字节01 我们根据类型推测 02是存储的type
那么01肯定是inode_no 我们即刻转战inode_table

当然这里我把他们放在了一张图 方便嘛 各位看官理解一下 哈哈
然后我们锁定 01 下面的68 0A 根据之前的定位 和 在0号inode 里面有个67 0A 我们可以大胆且自信的确定 这个是/dir1所在的直接扇区号 那我们走着
0XA68(小端序)


ok 来到了0XA68 * 512 1363968的扇区号
可以清楚的看到 subdir1目录项 映入眼帘了啊
同样的道理 73下方的02inode_table中的inode编号
这张图里面还好还有02 inode的扇区号 可以看到02下面的69 0A
可以锁定 subdir1所在扇区号0xA69 继续转战!

可以看到最下方的 1364480 就是subdir1所在的扇区 里面存储着普通文件file2的目录项 我们可以清楚的看见66 下方的03 转来转去的 人都快要绕晕了 但是不急 各位看官坚持一下 继续往下看


终于到了最后一张图了 由于03 inodeinode_table 512字节不够显示了
我就特意增加了显示字数 1024

可以清楚的看到 03编号下面的 扇区号 6A 0A 就是0XA6A 这里就是普通文件/file2所在的扇区了 里面就是我们写入的信息了

啊 功夫不负有心人 终于逮住它了 Catch me if u can!\n ok了
从这里看应该很成功的实现了功能了 现在也是凌晨1点了 很晚了 各位最后早点休息!收摊下班!

《操作系统真象还原》第十四章 ---- 实现文件系统 任务繁多 饭得一口口吃路得一步步走啊(下一)相关推荐

  1. 《操作系统真象还原》第十四章 ---- 实现文件系统 任务繁多 饭得一口口吃路得一步步走啊(上一)

    文章目录 专栏博客链接 相关查阅博客链接 本书中错误勘误 部分缩写熟知 闲聊时刻 实现文件系统的原理 inode构建原理 目录构建原理 超级块构建思路 创建文件系统 编写完的super_block.h ...

  2. 《操作系统真象还原》第十四章 ---- 实现文件系统 任务繁多 饭得一口口吃路得一步步走啊(上二)

    文章目录 专栏博客链接 相关查阅博客链接 本书中错误勘误 闲聊时刻 部分缩写熟知 实现文件描述符的原理 文件描述符的介绍 文件描述符与inode的介绍 文件描述符与PCB的描述符数组的介绍 实现文件操 ...

  3. 《操作系统真象还原》第十四章 ---- 实现文件系统 任务繁多 饭得一口口吃路得一步步走啊(总结篇)

    文章目录 专栏博客链接 闲聊时刻 第十四章代码总览 编写完的fs.c(fs/fs.c) 编写完的fs.h(fs/fs.h) 编写完的dir.c(fs/dir.c) 编写完的dir.h(fs/dir.h ...

  4. 《操作系统真象还原》第四章 ---- 剑指Loader 刃刺GDT 开启新纪元保护模式 解放32位

    文章目录 专栏博客链接 相关查阅博客链接 本书中错误勘误 看到第四章的一些很有趣的话 想记录下来 修改MBR.S 更新配置文件boot.inc 忽生疑惑(怎么是平坦模型?) 编写Loader.S 调用 ...

  5. 《操作系统真象还原》第七章

    <操作系统真象还原>第七章 本篇对应书籍第七章的内容 本篇内容介绍了操作系统的中断处理机制,建立中断描述符表,填充门描述符,以及中断处理程序,初始化8259A中断控制器实现外部中断功能,控 ...

  6. 《操作系统真象还原》第六章 ---- 开启c语言编写函数时代 首挑打印函数小试牛刀 费心讨力重回gcc降级 终尝多日调试之喜悦

    文章目录 专栏博客链接 相关查阅博客链接 本书中错误勘误 部分缩写熟知 修改代码的小闲聊 编写print.S(实现打印函数) print.S代码 print.h代码和stdint.h代码 修改main ...

  7. 《操作系统真象还原》第十三章 ---- 编写硬盘驱动软件 行百里者半九十终成时喜悦溢于言表

    文章目录 专栏博客链接 相关查阅博客链接 本书中错误勘误 部分缩写熟知 闲聊时刻 提前需要准备编写的函数 实现printk 实现sprintf函数 创建从盘 创建从盘的步骤 修改后的bochsrc.d ...

  8. 《操作系统真象还原》第五章 ---- 轻取物理内存容量 启用分页畅游虚拟空间 力斧直斩内核先劈一角 闲庭信步摸谈特权级

    文章目录 专栏博客链接 相关查阅博客链接 本书中错误勘误 部分缩写熟知 + 小建议 修改代码前的小闲聊 修改loader.S(读取内存大小) 检验是否成功读取内存大小 开始分页新篇章的分页理解 一级页 ...

  9. 操作系统真象还原第1.5章 NASM汇编学习

    第二章有使用 NASM 汇编写主引导记录 MBR 的内容. 在写第二章的代码前,每天晚上下班后花一些时间简单地回顾了 NASM 汇编的内容,只复习了最简单的语法,之后写 OS 时再边写边查资料. 指令 ...

最新文章

  1. C#用 SendKyes 结合 Process 或 API FindWindow、SendMessage(PostMessage) 等控制外部程序
  2. 包教包会!7段代码带你玩转Python条件语句(附代码)
  3. 怎样打造高效节能的数据中心
  4. opencv python3 找图片色块_如何使用OpenCV在Python中找到图像的平均颜色?
  5. github推荐好玩项目
  6. 【英语学习】【Daily English】U05 Places L03 I'd like to open an account
  7. public 返回一数组_数组:滑动窗口拯救了你
  8. jquery 后代元素_在jQuery中查找元素的所有后代
  9. 2008 China MVP Open Day 小记
  10. 使用阿里云npm镜像加速
  11. JavaScript实现HTML导航栏下拉菜单[悬浮显示]
  12. 【bug解决】上传图片后,取消这次上传 再次执行上传,上次的图片还存在
  13. Linux之pure-ftpd安装和使用
  14. linux对IO口控制remap,ioremap/remap_page_range [经典]Linux内核中ioremap映射的透彻理解...
  15. 基于人脸识别技术实战开发人证比对访客系统
  16. C++ Deque的使用
  17. 第四十七章 SQL命令 GRANT(一)
  18. Glide 4.9源码解析-缓存策略
  19. c语言编程题改错题怎么改,c语言编程改错题.doc
  20. 小黑为四川大学实习金融专业同学解决了困扰好久的一个代码小bug,获得成就感,和清华实习同学约饭啦(被请客),继续向前的leetcode之旅:145. 二叉树的后序遍历

热门文章

  1. 证券公司的核心业务及部门
  2. 10大项目管理图表(附制图软件)
  3. Linux环境搭建和基础指令介绍
  4. html5 百度收录,百度网站收录教程(个人版)
  5. 数据记录仪自动测量与记录加速度:振动,颠簸,冲击和定位
  6. 7-25 说反话-加强版 (20分)
  7. android 横向滑动 回弹,android ScrollView水平滑动回弹
  8. 转载——Cisco ASA5510防火墙IP secure 配置
  9. 计算机应用技术目标地域分析100字,【计算机应用论文】威客模式计算机应用论文(共3100字)...
  10. 机器学习算法——逻辑回归(LR)