文章目录

  • 专栏博客链接
  • 相关查阅博客链接
  • 本书中错误勘误
  • 闲聊时刻
  • 部分缩写熟知
  • 实现文件描述符的原理
    • 文件描述符的介绍
    • 文件描述符与inode的介绍
    • 文件描述符与PCB的描述符数组的介绍
  • 实现文件操作基础函数(仅实现到文件建立sys_open)
    • 编写完的inode.c
    • 编写完的inode.h
    • 编写完的file.c
    • 编写完的file.h
    • 编写完的dir.c
    • 编写完的dir.h
    • 编写完的fs.c
    • 编写完的fs.h
    • 修改后的MakeFile
    • 修改后的main.c
  • make all 验证sys_open功能实现成功
    • xxd.sh文件代码
    • 得到sda1起始数据扇区号
    • 验证根目录是否建立成功
    • 第一次调用sys_open
    • 第二次调用sys_open

专栏博客链接


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


相关查阅博客链接



本书中错误勘误



闲聊时刻


由于第十四章的内容超级多 而且都是重活累活 各种地方到处都是函数 所以可能我预计的是分上中下三篇来写 这里是第二次编辑 现在来看肯定三篇是写不完的 可能要分 上中下续一续二 可以肯定的是 这个第十四章 绝对是所有章节中 最难啃最难啃的 代码超级多 你说实现起来难吧 思路难吧 肯定是相比进线程切换 内存分配那些更简单的 但由于各种函数的问题 而且细节也还是挺多的 尤其是代码量超级超级多 我做一天下来 可能才能做个几章 而且还需要debug 所以进度更慢了

我其实操作系统预计应该8.7日就应该写完的 但是现在已经是8.7日的晚上的11点了 我晚上7点才回到的成都 9点才到的家 而文件操作的函数才把最基本的inode操作写完 所以 哎 希望这两天加把力 早点完结这个系列

至于为什么回成都 因为学校里面各种事情心情很烦 不可抗力我就回到了家里面了 哎 一言难尽 呜呜


部分缩写熟知


fd file description 文件描述符
slot 空隙 间隙
RDONLY Read Only只读
WRONLY Write Only只写
RDWR Read Write 可写可读
CREAT Create 创造


实现文件描述符的原理


说实话 刚哥如果把文件系统放在最前面的话 我就已经被劝退了 后面肯定都写不下去了 但是呢 现在又写了很多了 就差最后一章半了 很多函数真的写起来太多了 而且很容易写错 哎 只能再咬咬牙坚持写一点

这里来说一下文件描述符的原理 为什么要出现这个东西
首先我们上一节实现了文件系统 那我们怎么管理文件呢 系统建立好了 我们总得有方法打开文件吧 所有的文件操作得由东西管理吧 就比如权限 访问


文件描述符的介绍


这就得引出一个概念了 文件描述符
我们先从底层原理说 我们怎么用 我们的文件描述表是全局变量 我们可以这样理解 就是一个操作系统最大打开文件的数量 我们每打开一个文件 无论是相同的还是不同的 都会创建一个文件描述符 里面具体有什么内容呢 我下面贴一个图 就大概是这样的


文件描述符与inode的介绍


每打开一个新文件就会创建一个文件描述符 在文件描述符管理表中 对的 可能这个时候你想得到了 文件和什么有关 肯定是inode相关啊 我们在文件系统访问文件全靠着inode来寻找扇区号来访问

那我们就需要把文件描述符和inode结点相关到一起了 这个时候有个关系就是
文件描述符->inode 可以这样理解吧 每次我们访问文件的时候都是通过目录文件路径来访问的 对吧 这个就和上面的文件系统有关了
我先谈一嘴 sys_open的函数定义是int sys_open(const char* pathname,uint8_t flags) 先可以不用太管flags flags是你访问这个文件的目的 有WRITE READ WRITE READ CREATE 这个后面会将

然后你看我们访问文件就是给的路径 由于有目录可以寻找都inode 我们是不是就得到了inode号了 前面说了 我们每访问一个文件 就要创建一个描述符表 我们可以同时打开多个相同文件 每个也都必须要创建一个 我们就可以在全局描述符表中找到空位然后把描述符写了 并指向那个inode即可


文件描述符与PCB的描述符数组的介绍


这里就完了吗 还差一两步 由于我们在操作系统中 我们执行的每个任务我们都是以进程的方式来访问的 所以每次访问文件 同样进程的PCB中是需要局部的描述符数组的 但是呢 里面的每个只是数字 负责只向全局描述符的每一项 最后sys_open的返回值 就是返回的PCB中的全部描述符数组的数组下标 我们通过那个下标 即可得到那个文件的描述符 最后再得到访问文件 一切都make sense了 感觉这样说起来有点乱 这样 我下面放个图 一目了然

那话就不多说了 原理就是这样 剩下的只有很多的函数底层实现 和 高层功能实现 把所有的底层实现函数串联起来实现功能而已 任务很多 代码很多 任务艰巨啊 各位看官往下看吧


实现文件操作基础函数(仅实现到文件建立sys_open)


下面的文件后面实现其他函数的时候可能还会更迭修改
这里是仅仅实现到sys_open


编写完的inode.c


路径fs/inode.c

#include "inode.h"
#include "ide.h"
#include "debug.h"
#include "../thread/thread.h"
#include "memory.h"
#include "string.h"
#include "list.h"
#include "interrupt.h"//得到inode 所在位置 给inode_pos赋值
void inode_locate(struct partition* part,uint32_t inode_no,struct inode_position* inode_pos)
{ASSERT(inode_no < 4096);uint32_t inode_table_lba = part->sb->inode_table_lba; //得到起始扇区lbauint32_t inode_size = sizeof(struct inode);uint32_t off_size = inode_no * inode_size;uint32_t off_sec  = off_size / 512;         //得到偏移扇区数uint32_t off_size_in_sec = off_size % 512;        //得到在扇区内偏移字节数uint32_t left_in_sec = 512 - off_size_in_sec;     //在扇区内剩余字节数 不满sizeof(struct inode)即在两扇区间if(left_in_sec < inode_size) inode_pos->two_sec = true;else       inode_pos->two_sec = false;inode_pos->sec_lba = inode_table_lba + off_sec;inode_pos->off_size = off_size_in_sec;
}//把inode写回硬盘 io_buf是提前申请的缓冲区 防止内存申请失败前面回读状态时前面任务全白做
void inode_sync(struct partition* part,struct inode* inode,void* io_buf)
{uint8_t inode_no = inode->i_no;            struct inode_position inode_pos;                //inode_positioninode_locate(part,inode_no,&inode_pos);ASSERT(inode_pos.sec_lba <= (part->start_lba + part->sec_cnt));struct inode pure_inode;memcpy(&pure_inode,inode,sizeof(struct inode));//这些都只在内存中有用pure_inode.i_open_cnts = 0;pure_inode.write_deny  = false;pure_inode.inode_tag.prev = pure_inode.inode_tag.next = NULL;char* inode_buf = (char*)io_buf;//如果跨分区if(inode_pos.two_sec){//一次性读两个扇区的内容 复制粘贴完了回读回去ide_read(part->my_disk,inode_pos.sec_lba,inode_buf,2);memcpy((inode_buf + inode_pos.off_size),&pure_inode,sizeof(struct 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);memcpy((inode_buf + inode_pos.off_size),&pure_inode,sizeof(struct inode));ide_write(part->my_disk,inode_pos.sec_lba,inode_buf,1);}
}//返回相对应的inode指针
struct inode* inode_open(struct partition* part,uint32_t inode_no)
{//先从inode链表找到inode 为了提速而创建的struct list_elem* elem = part->open_inodes.head.next; //第一个结点开始struct inode* inode_found;               //返回while(elem != &part->open_inodes.tail){inode_found = elem2entry(struct inode,inode_tag,elem);if(inode_found->i_no == inode_no){inode_found->i_open_cnts++;return inode_found;}elem = elem->next;}//缓冲链表没找到 则需要在硬盘区找struct inode_position inode_pos;inode_locate(part,inode_no,&inode_pos);//由于我们的sys_malloc 看当前线程处于用户还是内核是根据 pgdir是否有独立页表 //而不管是我们处在用户还是内核 为了让所有进程都能看到这个inode 我们必须把内存分配在内核struct task_struct* cur = running_thread();uint32_t* cur_pagedir_back = cur->pgdir;cur->pgdir = NULL; inode_found = (struct inode*)sys_malloc(sizeof(struct inode));cur->pgdir = cur_pagedir_back;char* inode_buf;if(inode_pos.two_sec){inode_buf = (char*)sys_malloc(1024);ide_read(part->my_disk,inode_pos.sec_lba,inode_buf,2);}else{inode_buf = (char*)sys_malloc(512);ide_read(part->my_disk,inode_pos.sec_lba,inode_buf,1);}memcpy(inode_found,inode_buf + inode_pos.off_size,sizeof(struct inode));   //放在队首 因为很有可能接下来要访问list_push(&part->open_inodes,&inode_found->inode_tag);inode_found->i_open_cnts = 1;sys_free(inode_buf);return inode_found;
}//关闭inode 或减少inode打开数
void inode_close(struct inode* inode)
{enum intr_status old_status = intr_disable();//减少次数后 当发现为0了 直接释放即可if(--inode->i_open_cnts == 0){struct task_struct* cur = running_thread();uint32_t* cur_pagedir_back = cur->pgdir;cur->pgdir = NULL;sys_free(inode);cur->pgdir = cur_pagedir_back;}intr_set_status(old_status);
}//初始化inode inode第一个编号是0
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;uint8_t sec_idx = 0;while(sec_idx < 13)new_inode->i_sectors[sec_idx++] = 0;
}

编写完的inode.h


路径fs/inode.h

#ifndef __FS_INODE_H
#define __FS_INODE_H#include "list.h"
#include "global.h"
#include "stdint.h"
#include "ide.h"struct inode
{uint32_t i_no;             //inode 编号uint32_t i_size;              //文件大小 或者 目录项总大小 inode不管是什么文件的uint32_t i_open_cnts;         //记录此文件被打开的次数bool write_deny;               //写文件不能并行uint32_t i_sectors[13];        //这里只实现了一级简介块 12为一级简介块指针 0-11直接是inode编号struct list_elem inode_tag;  //从硬盘读取速率太慢 此list做缓冲用 当第二次使用时如果list中有//直接通过list_elem得到inode而不用再读取硬盘
};struct inode_position
{bool two_sec;          //是否inode存储位置在两个扇区间uint32_t sec_lba;            //inode所在的扇区号uint32_t off_size;         //在所存储的扇区的偏移位置
};void inode_locate(struct partition* part,uint32_t inode_no,struct inode_position* inode_pos);
void inode_sync(struct partition* part,struct inode* inode,void* io_buf);
struct inode* inode_open(struct partition* part,uint32_t inode_no);
void inode_close(struct inode* inode);
void inode_init(uint32_t inode_no,struct inode* new_inode);#endif

编写完的file.c


路径fs/file.c

#include "file.h"
#include "stdio-kernel.h"
#include "../thread/thread.h"
#include "ide.h"
#include "fs.h"
#include "memory.h"
#include "string.h"
#include "global.h"
#include "debug.h"struct file file_table[MAX_FILE_OPEN];//全局文件表中获取
uint32_t get_free_slot_in_global(void)
{uint32_t fd_idx = 3;while(fd_idx < MAX_FILE_OPEN){if(file_table[fd_idx].fd_inode == NULL)break;++fd_idx;}if(fd_idx == MAX_FILE_OPEN){printk("exceed max open files\n");return -1;}return fd_idx;
}//安装到pcb中的文件描述符数组中
uint32_t pcb_fd_install(int32_t global_fd_idx)
{struct task_struct* cur = running_thread();uint8_t local_fd_idx = 3;         //从3开始while(local_fd_idx < MAX_FILES_OPEN_PER_PROC){if(cur->fd_table[local_fd_idx] == -1){cur->fd_table[local_fd_idx]  = global_fd_idx;break;}++local_fd_idx;}if(local_fd_idx == MAX_FILES_OPEN_PER_PROC){printk("exceed max open files\n");return -1;}return local_fd_idx;
}//分配一个inode 并且返回其结点号
int32_t inode_bitmap_alloc(struct partition* part)
{int32_t bit_idx = bitmap_scan(&part->inode_bitmap,1);if(bit_idx == -1)  return -1;bitmap_set(&part->inode_bitmap,bit_idx,1);return bit_idx;
}//分配一个扇区 并且返回扇区号
int32_t block_bitmap_alloc(struct partition* part)
{int32_t bit_idx = bitmap_scan(&part->block_bitmap,1);if(bit_idx == -1)   return -1;bitmap_set(&part->block_bitmap,bit_idx,1);return part->sb->data_start_lba + bit_idx;
}//将内存中的bitmap第bit_idx位所在的512字节同步到硬盘
void bitmap_sync(struct partition* part,uint32_t bit_idx,uint8_t btmp)
{   uint32_t off_sec = bit_idx / 4096;uint32_t off_size = off_sec * 512;uint32_t sec_lba;uint8_t* bitmap_off;switch(btmp){case INODE_BITMAP:sec_lba = part->sb->inode_bitmap_lba + off_sec;bitmap_off = part->inode_bitmap.bits + off_size;break;case BLOCK_BITMAP:sec_lba = part->sb->block_bitmap_lba + off_sec;bitmap_off = part->block_bitmap.bits + off_size;  break;}ide_write(part->my_disk,sec_lba,bitmap_off,1);
}/*创建文件 成功则返回文件描述符*/
int32_t file_create(struct dir* parent_dir,char* filename,uint8_t flag)
{void* io_buf = sys_malloc(1024);if(io_buf == NULL){printk("in file_create: sys_malloc for io_buf failed\n");return -1;}uint8_t rollback_step = 0;    // 用于回滚资源状态计数int32_t inode_no = inode_bitmap_alloc(cur_part);if(inode_no == -1){printk("in file_create: allocate inode failed\n");return -1;}struct inode* new_file_inode = (struct inode*)sys_malloc(sizeof(struct inode));if(new_file_inode == NULL){printk("file_create: sys_malloc for inode failed\n");rollback_step = 1;goto rollback;}inode_init(inode_no,new_file_inode);int fd_idx = get_free_slot_in_global();if(fd_idx == -1){printk("exceed max open files\n");rollback_step = 2;goto rollback;}file_table[fd_idx].fd_inode = new_file_inode;file_table[fd_idx].fd_inode->write_deny = false;file_table[fd_idx].fd_pos   = 0;file_table[fd_idx].fd_flag  = flag;struct dir_entry new_dir_entry;memset(&new_dir_entry,0,sizeof(struct dir_entry));create_dir_entry(filename,inode_no,FT_REGULAR,&new_dir_entry);if(!sync_dir_entry(parent_dir,&new_dir_entry,io_buf)){printk("sync dir_entry to disk failed\n");rollback_step = 3;goto rollback;}memset(io_buf,0,1024);inode_sync(cur_part,parent_dir->inode,io_buf);memset(io_buf,0,1024);inode_sync(cur_part,new_file_inode,io_buf);bitmap_sync(cur_part,inode_no,INODE_BITMAP);list_push(&cur_part->open_inodes,&new_file_inode->inode_tag);new_file_inode->i_open_cnts = 1;sys_free(io_buf);return pcb_fd_install(fd_idx);rollback:switch(rollback_step) //从上到下执行{case 3:memset(&file_table[fd_idx],0,sizeof(struct file));case 2:sys_free(new_file_inode);case 1:bitmap_set(&cur_part->inode_bitmap,inode_no,0);break;}sys_free(io_buf);return -1;
}

编写完的file.h


#ifndef __FS_FILE_H
#define __FS_FILE_H#include "inode.h"
#include "stdint.h"
#include "dir.h"#define MAX_FILE_OPEN 32  //系统最大打开文件数
struct file
{uint32_t fd_pos;       //文件偏移位置uint32_t fd_flag;       struct inode* fd_inode;    //指向下一级的inode指针
};enum std_fd
{stdin_no,          //标准输入stdout_no,            //标准输入stderr_no         //标准错误
};enum bitmap_type
{INODE_BITMAP,      //inode位图BLOCK_BITMAP       //块位图
};extern struct file file_table[MAX_FILE_OPEN];uint32_t get_free_slot_in_global(void);
uint32_t pcb_fd_install(int32_t global_fd_idx);
int32_t inode_bitmap_alloc(struct partition* part);
int32_t block_bitmap_alloc(struct partition* part);
void bitmap_sync(struct partition* part,uint32_t bit_idx,uint8_t btmp);
int32_t file_create(struct dir* parent_dir,char* filename,uint8_t flag);#endif

编写完的dir.c


#include "dir.h"
#include "ide.h"
#include "fs.h"
#include "inode.h"
#include "memory.h"
#include "string.h"
#include "stdint.h"
#include "stdio-kernel.h"
#include "debug.h"
#include "file.h"struct dir root_dir;//打开根目录
void open_root_dir(struct partition* part)
{root_dir.inode = inode_open(part,part->sb->root_inode_no);root_dir.dir_pos = 0;
}//打开指定inode结点中的目录 返回目录指针
struct dir* dir_open(struct partition* part,uint32_t inode_no)
{struct dir* pdir = (struct dir*)sys_malloc(sizeof(struct dir));pdir->inode = inode_open(part,inode_no);pdir->dir_pos = 0;return pdir;
}//在part分区找名字为name的文件或者目录
//找到后返回true 并且把目录项存放到dir_e中 以后可能解析目录的时候通过递归来实现
bool search_dir_entry(struct partition* part,struct dir* pdir,const char* name,struct dir_entry* dir_e)
{uint32_t block_cnt = 140; //inode中12个直接指 + 1个128间接 = 140 128 = 512/4uint32_t* all_blocks = (uint32_t*)sys_malloc(block_cnt*4);if(all_blocks == NULL){printk("search_dir_entry: sys_malloc for all_blocks failed\n");return false;}uint32_t block_idx = 0;while(block_idx < 12){all_blocks[block_idx] = pdir->inode->i_sectors[block_idx];++block_idx;}block_idx = 0;//如果存在一级间接块表if(pdir->inode->i_sectors[12] != 0)ide_read(part->my_disk,pdir->inode->i_sectors[12],all_blocks,1);//每次只分配一个扇区大小 之后我们把目录项不会再出现放到两个扇区之间的情况uint8_t* buf = (uint8_t*)sys_malloc(SECTOR_SIZE);struct dir_entry* p_de = (struct dir_entry*)buf;uint32_t dir_entry_size = part->sb->dir_entry_size;uint32_t dir_entry_cnt  = SECTOR_SIZE / dir_entry_size;while(block_idx < block_cnt){//说明此处没有目录文件 继续遍历if(all_blocks[block_idx] == 0){++block_idx;continue;}//把其内容读出来ide_read(part->my_disk,all_blocks[block_idx],buf,1);uint32_t dir_entry_idx = 0;while(dir_entry_idx < dir_entry_cnt){if(!strcmp(p_de->filename,name)){memcpy(dir_e,p_de,dir_entry_size);  //把目录项内容复制到dir_e指针区sys_free(buf);sys_free(all_blocks);return true;}++p_de;++dir_entry_idx;}++block_idx;p_de = (struct dir_entry*)buf;        //赋值还原回去memset(buf,0,SECTOR_SIZE);              //全部设置为0 初始化buf}sys_free(buf);sys_free(all_blocks);return false;
}//关闭目录
void dir_close(struct dir* dir)
{if(dir == &root_dir)return;inode_close(dir->inode);sys_free(dir);
}//在内存中初始化目录项
void create_dir_entry(char* filename,uint32_t inode_no,uint8_t file_type,struct dir_entry* p_de)
{ASSERT(strlen(filename) <= MAX_FILE_NAME_LEN);memcpy(p_de->filename,filename,strlen(filename));p_de->i_no = inode_no;p_de->f_type = file_type;
}//将目录项p_de 写入父目录parent_dir io_buf由主调函数提供
bool sync_dir_entry(struct dir* parent_dir,struct dir_entry* p_de,void* io_buf)
{struct inode* dir_inode = parent_dir->inode;uint32_t dir_size = dir_inode->i_size;uint32_t dir_entry_size = cur_part->sb->dir_entry_size;ASSERT(dir_size % dir_entry_size == 0);uint32_t dir_entrys_per_sec = (512 / dir_entry_size);    //得到每扇区最多多少个目录项int32_t block_lba = -1;                 uint8_t block_idx = 0;uint32_t all_blocks[140] = {0};             //局部变量 所有块//先看直接块 后面再看简介块while(block_idx < 12){all_blocks[block_idx] = dir_inode->i_sectors[block_idx];  //直接块读取block_idx++;}struct dir_entry* dir_e = (struct dir_entry*)io_buf;     //遍历目录项的临时指针int32_t block_bitmap_idx = -1;                 //位图idxblock_idx = 0;while(block_idx < 140){block_bitmap_idx = -1;if(all_blocks[block_idx] == 0)             //此块还没有分配{block_lba = block_bitmap_alloc(cur_part);if(block_lba == -1){printk("alloc block bitmap for sync_dir_entry failed\n");return false;}block_bitmap_idx = block_lba - cur_part->sb->data_start_lba;//由分配扇区号 - 起始扇区号 = 位图的相对偏移bitmap_sync(cur_part,block_bitmap_idx,BLOCK_BITMAP);        //同步到硬盘block_bitmap_idx = -1;if(block_idx < 12)        //直接块dir_inode->i_sectors[block_idx] = all_blocks[block_idx] = block_lba;else if(block_idx == 12)    //一级间接表 间接表{dir_inode->i_sectors[block_idx] = block_lba;block_lba = -1;block_lba = block_bitmap_alloc(cur_part);  //再给到一个块 给简介块第0个赋值if(block_lba == -1) //分配失败则需要回退之前的分配{block_bitmap_idx = dir_inode->i_sectors[12] - cur_part->sb->data_start_lba;bitmap_set(&cur_part->block_bitmap,block_bitmap_idx,0);dir_inode->i_sectors[12] = 0;printk("alloc block bitmap for sync_dir_entry failed\n");return false;}block_bitmap_idx = block_lba - cur_part->sb->data_start_lba;ASSERT(block_bitmap_idx != -1);bitmap_sync(cur_part,block_bitmap_idx,BLOCK_BITMAP);all_blocks[12] = block_lba;ide_write(cur_part->my_disk,dir_inode->i_sectors[12],all_blocks + 12,1);    //一级间接块复制到硬盘中}else  //已经有一级间接表了 {all_blocks[block_idx] = block_lba;ide_write(cur_part->my_disk,dir_inode->i_sectors[12],all_blocks + 12,1); //一级间接表复制到硬盘中}memset(io_buf,0,512);memcpy(io_buf,p_de,dir_entry_size);ide_write(cur_part->my_disk,all_blocks[block_idx],io_buf,1);           //把目录项放到新分配的区块dir_inode->i_size += dir_entry_size;return true;}//此块已经被分配 寻找空余空间 ide_read(cur_part->my_disk,all_blocks[block_idx],io_buf,1);uint8_t dir_entry_idx = 0;while(dir_entry_idx < dir_entrys_per_sec)  //由于我们存放目录项不再出现存放于两个扇区间的情况 即<dir_entrys_per_sec即可{if((dir_e + dir_entry_idx)->f_type == FT_UNKNOWN)    //这个位置还没有存放目录项{memcpy(dir_e + dir_entry_idx,p_de,dir_entry_size);ide_write(cur_part->my_disk,all_blocks[block_idx],io_buf,1);   //写回去dir_inode->i_size += dir_entry_size;              //文件大小增加return true;}++dir_entry_idx;}++block_idx;  //遍历完140个块}printk("directory is full!\n");return false;
}

编写完的dir.h


#ifndef __FS_DIR_H
#define __FS_DIR_H#define MAX_FILE_NAME_LEN 16 //最长16个字
#include "ide.h"
#include "fs.h"struct dir         //在内存中用的目录结构
{struct inode* inode;   //指向已经打开的inode指针uint32_t dir_pos;       //目录偏移位置uint8_t  dir_buf[512];  //目录的数据缓冲
};struct dir_entry          //目录项
{char filename[MAX_FILE_NAME_LEN];  //16个字的名字uint32_t i_no;         //inode编号enum file_types f_type;        //文件类型 由此看是目录还是文件类型
};extern struct dir root_dir;void open_root_dir(struct partition* part);
struct dir* dir_open(struct partition* part,uint32_t inode_no);
bool search_dir_entry(struct partition* part,struct dir* pdir,const char* name,struct dir_entry* dir_e);
void dir_close(struct dir* dir);
void create_dir_entry(char* filename,uint32_t inode_no,uint8_t file_type,struct dir_entry* p_de);
bool sync_dir_entry(struct dir* parent_dir,struct dir_entry* p_de,void* io_buf);#endif

编写完的fs.c


#include "fs.h"
#include "stdint.h"
#include "global.h"
#include "../device/ide.h"
#include "inode.h"
#include "dir.h"
#include "super_block.h"
#include "stdio-kernel.h"
#include "string.h"
#include "debug.h"
#include "list.h"
#include "file.h"struct partition* cur_part;  //默认操作分区void partition_format(struct disk* hd,struct partition* part)
{uint32_t boot_sector_sects = 1;       //引导块一个块uint32_t super_block_sects = 1;        //超级块一个块uint32_t inode_bitmap_sects = DIV_ROUND_UP(MAX_FILES_PER_PART,BITS_PER_SECTOR);  //inode位图占的块数//inode数组所占的块数uint32_t inode_table_sects = DIV_ROUND_UP((sizeof(struct inode) * MAX_FILES_PER_PART),SECTOR_SIZE);//注意这里的used_sects 肯定是不准确 差了那么一点点的 因为还没有包含block_bitmap_sects 但是为了简单处理 要先得到free_sects才能推  所以到后面block_bitmap_sects 要除两次uint32_t used_sects = boot_sector_sects + super_block_sects + inode_bitmap_sects + inode_table_sects;uint32_t free_sects = part->sec_cnt - used_sects;uint32_t block_bitmap_sects = DIV_ROUND_UP(free_sects,BITS_PER_SECTOR); //一位一块uint32_t block_bitmap_bit_len = free_sects - block_bitmap_sects; //再减去block_bitmap的block_bitmap_sects = DIV_ROUND_UP(block_bitmap_bit_len,BITS_PER_SECTOR);struct super_block sb;                   //利用栈来初始化超级块 我们的栈此刻在sb.magic         = 0x23333333;         //魔数sb.sec_cnt       = part->sec_cnt;       //该分区总扇区数sb.inode_cnt     = MAX_FILES_PER_PART;        //该分区总inode数sb.part_lba_base = part->start_lba;     //该分区lba起始扇区位置// 引导块 超级块 空闲块位图 inode位图 inode数组 根目录 空闲块区域//挨着挨着顺序赋值即可sb.block_bitmap_lba   = part->start_lba + boot_sector_sects + super_block_sects;sb.block_bitmap_sects = block_bitmap_sects;sb.inode_bitmap_lba   = sb.block_bitmap_lba + block_bitmap_sects;sb.inode_bitmap_sects = inode_bitmap_sects;sb.inode_table_lba    = sb.inode_bitmap_lba + inode_bitmap_sects;sb.inode_table_sects  = inode_table_sects;sb.data_start_lba     = sb.inode_table_lba + inode_table_sects;sb.root_inode_no       = 0;            //根目录inode起始编号 0 sb.dir_entry_size     = sizeof(struct dir_entry); //目录项大小printk("%s  info:\n",part->name);printk("    magic:0x%x\n    part_lba_base:0x%x\n    all_sectors:0x%x\n    \
inode_cnt:0x%x\n    block_bitmap_lba:0x%x\n    block_bitmap_sectors:0x%x\n    \
inode_bitmap_lba:0x%x\n    inode_bitmap_sectors:0x%x\n    \
inode_table_lba:0x%x\n    inode_table_sectors:0x%x\n    \
data_start_lba:0x%x\n", \sb.magic,sb.part_lba_base,sb.sec_cnt,sb.inode_cnt,sb.block_bitmap_lba,sb.block_bitmap_sects,\sb.inode_bitmap_lba,sb.inode_bitmap_sects,sb.inode_table_lba,\sb.inode_table_sects,sb.data_start_lba);   //把元信息挨个挨个写进硬盘ide_write(hd,part->start_lba + boot_sector_sects,&sb,super_block_sects);printk("    super_block_lba:0x%x\n",part->start_lba + 1);//找一个最大的数据缓冲区 我们的栈已经不足以满足我们的各种信息的储存了 之后还要把元信息给腾到硬盘中uint32_t buf_size = (sb.block_bitmap_sects >= sb.inode_bitmap_sects) ? sb.block_bitmap_sects : sb.inode_bitmap_sects;buf_size = ((buf_size >= inode_table_sects) ? buf_size : inode_table_sects) * SECTOR_SIZE;//申请缓冲空间 给元信息腾空间 设置成uint8_t* 原因是 先弄块位图的初始化uint8_t* buf = (uint8_t*)sys_malloc(buf_size);/* 初始化块位图了 */buf[0] |= 0x1;uint32_t block_bitmap_last_byte = block_bitmap_bit_len / 8; //先算算占用多少字节uint8_t block_bitmap_last_bit  = block_bitmap_bit_len % 8; //最后还有剩余多少位uint32_t last_size = SECTOR_SIZE - (block_bitmap_last_byte % SECTOR_SIZE); //先除余数 算出来多少字节空的//处理字节 把可能多的一字节全部置成1 这几步处理的很细节阿memset(&buf[block_bitmap_last_byte],0xff,last_size);     //全部置1 保证不会被使用//处理最后的位 有效位变成0 用~来处理 真的很妙uint8_t bit_idx = 0;while(bit_idx <= block_bitmap_last_bit)buf[block_bitmap_last_byte] &= ~(1 << (bit_idx++));   //有效位//把位图元信息给写到硬盘中 块位图的部分就结束了 还有inode位图 inode数组等着我们ide_write(hd,sb.block_bitmap_lba,buf,sb.block_bitmap_sects);/*初始化inode位图了*/memset(buf,0,buf_size);buf[0] |= 0x1;                                             //第一个inode用于存根目录ide_write(hd,sb.inode_bitmap_lba,buf,sb.inode_bitmap_sects); //第一个inode初始化在后面/*初始化inode数组了*/memset(buf,0,buf_size);struct inode* i = (struct inode*)buf;         //先初始化第一个inode 根目录所在的i->i_size = sb.dir_entry_size * 2;         //. 和 .. i->i_no   = 0;i->i_sectors[0]  = sb.data_start_lba;            //根目录所在扇区就是最开始的第一个扇区ide_write(hd,sb.inode_table_lba,buf,sb.inode_table_sects);/*写根目录文件进入 第一个扇区了*/memset(buf,0,buf_size);struct dir_entry* p_de = (struct dir_entry*)buf;memcpy(p_de->filename,".",1);             //名称p_de->i_no = 0;                     //根目录. inode仍然是自己p_de->f_type = FT_DIRECTORY;p_de++;                          //移动到下一条目录项memcpy(p_de->filename,"..",2);p_de->i_no = 0;                       //根目录的父目录仍然是自己 因为自己是固定好的 根基p_de->f_type = FT_DIRECTORY;ide_write(hd,sb.data_start_lba,buf,1);           //把根目录文件写到第一个扇区中printk("    root_dir_lba:0x%x\n",sb.data_start_lba);printk("%s format done\n",part->name);sys_free(buf);                     //临时借用的 现在得还回去了
}//除了挂载 还需要在内存中把超级块指针 块位图 i结点位图 i结点指针给初始化赋值了 方便使用
bool mount_partition(struct list_elem* pelem,int arg)
{char* part_name = (char*)arg;struct partition* part = elem2entry(struct partition,part_tag,pelem);//得到分区指针 partition*if(!strcmp(part->name,part_name))                       //字符串相匹配{cur_part = part;                          //赋值指针struct disk* hd = cur_part->my_disk;struct super_block* sb_buf = (struct super_block*)sys_malloc(SECTOR_SIZE);if(sb_buf == NULL)PANIC("alloc memory failed!");memset(sb_buf,0,SECTOR_SIZE);ide_read(hd,cur_part->start_lba + 1,sb_buf,1);cur_part->sb = sb_buf;cur_part->block_bitmap.bits = (uint8_t*)sys_malloc(sb_buf->block_bitmap_sects * SECTOR_SIZE);if(cur_part->block_bitmap.bits == NULL)PANIC("alloc memory failed!");cur_part->block_bitmap.btmp_bytes_len = sb_buf->block_bitmap_sects * SECTOR_SIZE;ide_read(hd,sb_buf->block_bitmap_lba,cur_part->block_bitmap.bits,sb_buf->block_bitmap_sects);cur_part->inode_bitmap.bits = (uint8_t*)sys_malloc(sb_buf->inode_bitmap_sects * SECTOR_SIZE);if(cur_part->inode_bitmap.bits == NULL)PANIC("alloc memory failed!");cur_part->inode_bitmap.btmp_bytes_len = sb_buf->inode_bitmap_sects * SECTOR_SIZE;ide_read(hd,sb_buf->inode_bitmap_lba,cur_part->inode_bitmap.bits,sb_buf->inode_bitmap_sects);list_init(&cur_part->open_inodes);printk("mount %s done!\n",part->name);return true;   //停止循环}return false;    //继续循环
}//解析路径 并把下一级路径的字符串赋值给name_store 返回现在已经解析完的指针位置
char* path_parse(char* pathname,char* name_store)
{if(pathname[0] == '/')while(*(++pathname) == '/');   //直到pathname位置不是while(*pathname != '/' && *pathname != '\0')*(name_store++) = *(pathname++);if(pathname[0] == 0)   return NULL;return pathname;
}//返回路径的层数
int32_t path_depth_cnt(char* pathname)
{ASSERT(pathname != NULL);char* p = pathname;char name[MAX_FILE_NAME_LEN];uint32_t depth = 0;p = path_parse(p,name);while(name[0]){++depth;memset(name,0,MAX_FILE_NAME_LEN);if(p)p = path_parse(p,name);}return depth;
}//搜索文件 找到则返回inode号 否则返回-1
int search_file(const char* pathname,struct path_search_record* searched_record)
{//如果是根目录 则直接判定返回即可 下面的工作就不需要做了if(!strcmp(pathname,"/") || !strcmp(pathname,"/.") || !strcmp(pathname,"/..")){searched_record->parent_dir = &root_dir;searched_record->file_type  = FT_DIRECTORY;searched_record->searched_path[0] = 0;       //置空return 0;   //根目录inode编号为0}uint32_t path_len = strlen(pathname);ASSERT(pathname[0] == '/' && path_len > 1 && path_len < MAX_PATH_LEN);       char* sub_path = (char*)pathname;struct dir* parent_dir = &root_dir;          //每个刚开始都是从根目录开始struct dir_entry dir_e;                  //存放目录项的临时变量char name[MAX_FILE_NAME_LEN] = {0};searched_record->parent_dir = parent_dir;searched_record->file_type  = FT_UNKNOWN;uint32_t parent_inode_no = 0;                //父目录的inode号sub_path = path_parse(sub_path,name);          //解析目录while(name[0]){ASSERT(strlen(searched_record->searched_path) < 512);strcat(searched_record->searched_path,"/");strcat(searched_record->searched_path,name);if(search_dir_entry(cur_part,parent_dir,name,&dir_e)){memset(name,0,MAX_FILE_NAME_LEN);if(sub_path)    sub_path = path_parse(sub_path,name);   if(FT_DIRECTORY == dir_e.f_type)   //打开的是目录继续解析即可{parent_inode_no = parent_dir->inode->i_no;dir_close(parent_dir);parent_dir = dir_open(cur_part,dir_e.i_no);searched_record->parent_dir = parent_dir;}else if(FT_REGULAR == dir_e.f_type){searched_record->file_type = FT_REGULAR;return dir_e.i_no;}}else  return -1;}dir_close(searched_record->parent_dir);searched_record->parent_dir = dir_open(cur_part,parent_inode_no);searched_record->file_type = FT_DIRECTORY;return dir_e.i_no;
}//文件系统初始化 磁盘上搜索 如果没有则格式化分区 并创建文件系统
void filesys_init(void)
{uint8_t channel_no = 0,dev_no,part_idx = 0;struct super_block* sb_buf = (struct super_block*)sys_malloc(SECTOR_SIZE);if(sb_buf == NULL)   PANIC("alloc memory failed!");printk("searching filesysteam......\n");while(channel_no < channel_cnt){dev_no = 1;while(dev_no < 2){if(!dev_no)   //跳过hd60M.img主盘{++dev_no; continue;}struct disk* hd = &channels[0].devices[1];       //得到硬盘指针struct partition* part = hd->prim_parts;                //先为主区创建文件系统while(part_idx < 12)     //4个主区 + 8个逻辑分区{if(part_idx == 4)part = hd->logic_parts; if(part->sec_cnt != 0)      //分区存在 如果没有初始化 即所有成员都为0{memset(sb_buf,0,SECTOR_SIZE);ide_read(hd,part->start_lba +1,sb_buf,1);  //读取超级块的扇区if(sb_buf->magic != 0x23333333)           //还没有创建文件系统{printk("formatting %s's partition %s......\n",\hd->name,part->name);partition_format(hd,part);}elseprintk("%s has filesystem\n",part->name);}++part_idx;++part;   //到下一个分区看}++dev_no;       //切换盘号}++channel_no;      //增加ide通道号}sys_free(sb_buf);char default_part[8] = "sdb1";   //参数为int 4字节字符串指针传的进去list_traversal(&partition_list,mount_partition,(int)default_part);open_root_dir(cur_part);uint32_t fd_idx = 0;while(fd_idx < MAX_FILE_OPEN)file_table[fd_idx++].fd_inode = NULL;
}int32_t sys_open(const char* pathname,uint8_t flags)
{//最后一位是'/'则无法辨析 这里是打开文件if(pathname[strlen(pathname) - 1] == '/'){printk("cant open a directory %s\n",pathname);return -1;}ASSERT(flags <= 7);int32_t fd = -1;struct path_search_record searched_record;        //记录访问记录memset(&searched_record,0,sizeof(struct path_search_record));uint32_t pathname_depth = path_depth_cnt((char*)pathname);int inode_no = search_file(pathname,&searched_record); //搜索文件bool found = (inode_no == -1) ? false : true;if(searched_record.file_type == FT_DIRECTORY)       //如果是目录文件类型{printk("cant open a directory with open(),use opendir() to instead\n");dir_close(searched_record.parent_dir);return -1;}uint32_t path_searched_depth = path_depth_cnt(searched_record.searched_path);if(pathname_depth != path_searched_depth){printk("cannot access %s:Not a directory,subpath %s isnt exist\n",pathname,searched_record.searched_path);dir_close(searched_record.parent_dir);return -1;    }if(!found && !(flags & O_CREAT)){printk("in path %s: Not a directory, subpath %s isnt exist\n",pathname,searched_record.searched_path);dir_close(searched_record.parent_dir);return -1;}else if(found && (flags & O_CREAT)){printk("%s has already exist!\n",pathname);dir_close(searched_record.parent_dir);return -1;}switch(flags & O_CREAT){case O_CREAT:printk("creating file\n");fd = file_create(searched_record.parent_dir,strrchr(pathname,'/') + 1,flags);dir_close(searched_record.parent_dir);}return fd;
}

编写完的fs.h


#ifndef __FS_FS_H
#define __FS_FS_H
#include "ide.h"#define MAX_FILES_PER_PART     4096  //每个扇区最大支持文件数
#define BITS_PER_SECTOR 4096  //每扇区的位数 512字节 * 8
#define SECTOR_SIZE     512   //每扇区的字节数 512字节
#define BLOCK_SIZE  SECTOR_SIZE   //块字节大小 我们这里一块 == 一扇区
#define MAX_PATH_LEN           512   //最大路径长度extern struct partition* cur_part;enum file_types
{FT_UNKNOWN,    //未知文件类型FT_REGULAR, //普通文件类型FT_DIRECTORY    //目录文件类型
};enum oflags
{O_RDONLY,      //只读属性O_WRONLY,     //只写属性O_RDWR,       //可读写O_CREAT = 4   //创建
};struct path_search_record
{char searched_path[MAX_PATH_LEN]; //父路径struct dir* parent_dir;        //文件直接的父路径 或者说上一级的路径enum file_types file_type;        //普通文件 目录 或者未知类型
};void partition_format(struct disk* hd,struct partition* part);
bool mount_partition(struct list_elem* pelem,int arg);
void filesys_init(void);
char* path_parse(char* pathname,char* name_store);
int32_t path_depth_cnt(char* pathname);
int search_file(const char* pathname,struct path_search_record* searched_record);
int32_t sys_open(const char* pathname,uint8_t flags);#endif

修改后的MakeFile


BUILD_DIR = ./build
ENTRY_POINT = 0xc0001500
AS = nasm
CC = gcc
LD = ld
LIB = -I lib/ -I lib/kernel/ -I lib/user/ -I kernel/ -I device/
ASFLAGS = -f elf
CFLAGS = -Wall -m32 -fno-stack-protector $(LIB) -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototypes
LDFLAGS =  -m elf_i386 -Ttext $(ENTRY_POINT) -e main -Map $(BUILD_DIR)/kernel.map
OBJS = $(BUILD_DIR)/main.o $(BUILD_DIR)/init.o $(BUILD_DIR)/interrupt.o \$(BUILD_DIR)/timer.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o $(BUILD_DIR)/switch.o \$(BUILD_DIR)/debug.o $(BUILD_DIR)/string.o $(BUILD_DIR)/memory.o \$(BUILD_DIR)/bitmap.o $(BUILD_DIR)/thread.o $(BUILD_DIR)/list.o \$(BUILD_DIR)/sync.o $(BUILD_DIR)/console.o $(BUILD_DIR)/keyboard.o \$(BUILD_DIR)/ioqueue.o $(BUILD_DIR)/tss.o $(BUILD_DIR)/process.o \$(BUILD_DIR)/syscall-init.o $(BUILD_DIR)/syscall.o $(BUILD_DIR)/stdio.o \$(BUILD_DIR)/stdio-kernel.o $(BUILD_DIR)/ide.o $(BUILD_DIR)/fs.o $(BUILD_DIR)/inode.o \$(BUILD_DIR)/file.o $(BUILD_DIR)/dir.o##############     c代码编译     ###############
$(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h \lib/stdint.h kernel/init.h lib/string.h kernel/memory.h \thread/thread.h kernel/interrupt.h device/console.h \device/keyboard.h device/ioqueue.h userprog/process.h \lib/user/syscall.h userprog/syscall-init.h lib/stdio.h \lib/kernel/stdio-kernel.h fs/file.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/init.o: kernel/init.c kernel/init.h lib/kernel/print.h \lib/stdint.h kernel/interrupt.h device/timer.h kernel/memory.h \thread/thread.h device/console.h device/keyboard.h userprog/tss.h \userprog/syscall-init.h device/ide.h fs/fs.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/interrupt.o: kernel/interrupt.c kernel/interrupt.h \lib/stdint.h kernel/global.h lib/kernel/io.h lib/kernel/print.h \kernel/kernel.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/timer.o: device/timer.c device/timer.h lib/kernel/io.h lib/kernel/print.h \kernel/interrupt.h thread/thread.h kernel/debug.h kernel/global.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/debug.o: kernel/debug.c kernel/debug.h \lib/kernel/print.h lib/stdint.h kernel/interrupt.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/string.o: lib/string.c lib/string.h \kernel/debug.h kernel/global.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/memory.o: kernel/memory.c kernel/memory.h \lib/stdint.h lib/kernel/bitmap.h kernel/debug.h lib/string.h kernel/global.h \thread/sync.h thread/thread.h lib/kernel/list.h kernel/interrupt.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/bitmap.o: lib/kernel/bitmap.c lib/kernel/bitmap.h kernel/global.h \lib/string.h kernel/interrupt.h lib/kernel/print.h kernel/debug.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/thread.o: thread/thread.c thread/thread.h \lib/stdint.h lib/string.h kernel/global.h kernel/memory.h \kernel/debug.h kernel/interrupt.h lib/kernel/print.h \userprog/process.h thread/sync.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/list.o: lib/kernel/list.c lib/kernel/list.h \kernel/interrupt.h lib/stdint.h kernel/debug.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/sync.o: thread/sync.c thread/sync.h \lib/stdint.h thread/thread.h kernel/debug.h kernel/interrupt.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/console.o: device/console.c device/console.h \lib/kernel/print.h thread/sync.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/keyboard.o: device/keyboard.c device/keyboard.h \lib/kernel/print.h lib/kernel/io.h kernel/interrupt.h \kernel/global.h lib/stdint.h device/ioqueue.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/ioqueue.o: device/ioqueue.c device/ioqueue.h \kernel/interrupt.h kernel/global.h kernel/debug.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/tss.o: userprog/tss.c userprog/tss.h \kernel/global.h thread/thread.h lib/kernel/print.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/process.o: userprog/process.c userprog/process.h \lib/string.h kernel/global.h kernel/memory.h lib/kernel/print.h \thread/thread.h kernel/interrupt.h kernel/debug.h device/console.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/syscall-init.o: userprog/syscall-init.c userprog/syscall-init.h \lib/user/syscall.h lib/stdint.h lib/kernel/print.h kernel/interrupt.h thread/thread.h \kernel/memory.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/syscall.o: lib/user/syscall.c lib/user/syscall.h $(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/stdio.o: lib/stdio.c lib/stdio.h lib/stdint.h lib/string.h lib/user/syscall.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/stdio-kernel.o: lib/kernel/stdio-kernel.c lib/kernel/stdio-kernel.h \lib/stdio.h device/console.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/ide.o: device/ide.c device/ide.h lib/stdint.h kernel/debug.h \lib/kernel/stdio-kernel.h lib/stdio.h kernel/global.h thread/sync.h \lib/kernel/io.h device/timer.h kernel/interrupt.h lib/kernel/list.h fs/fs.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/fs.o: fs/fs.c fs/fs.h lib/stdint.h kernel/global.h device/ide.h fs/inode.h fs/dir.h \fs/super_block.h lib/kernel/stdio-kernel.h lib/string.h kernel/debug.h lib/kernel/list.h \fs/file.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/inode.o: fs/inode.c fs/inode.h device/ide.h kernel/debug.h thread/thread.h \kernel/memory.h lib/string.h lib/kernel/list.h kernel/interrupt.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/file.o: fs/file.c fs/file.h lib/kernel/stdio-kernel.h thread/thread.h device/ide.h \fs/file.h kernel/global.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/dir.o: fs/dir.c fs/dir.h device/ide.h fs/fs.h fs/inode.h kernel/memory.h lib/string.h lib/stdint.h \lib/kernel/stdio-kernel.h kernel/debug.h fs/file.h kernel/memory.h lib/string.h kernel/debug.h$(CC) $(CFLAGS) $< -o $@##############    汇编代码编译    ###############
$(BUILD_DIR)/kernel.o: kernel/kernel.S$(AS) $(ASFLAGS) $< -o $@$(BUILD_DIR)/print.o: lib/kernel/print.S$(AS) $(ASFLAGS) $< -o $@$(BUILD_DIR)/switch.o: thread/switch.S$(AS) $(ASFLAGS) $< -o $@##############    链接所有目标文件    #############
$(BUILD_DIR)/kernel.bin: $(OBJS)$(LD) $(LDFLAGS) $^ -o $@.PHONY : mk_dir hd clean allmk_dir:if [ ! -d $(BUILD_DIR) ]; then mkdir $(BUILD_DIR); fihd:dd if=$(BUILD_DIR)/kernel.bin \of=/home/cooiboi/bochs/hd60M.img \bs=512 count=200 seek=9 conv=notruncclean:cd $(BUILD_DIR) && rm -f  ./*build: $(BUILD_DIR)/kernel.binall: mk_dir build hd

修改后的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();sys_open("/file1",O_CREAT);while(1);return 0;
}

make all 验证sys_open功能实现成功


这里其实我是真的很建议 大家一定要多做备份 我这里至少在windows备份了五六个版本了 而且硬盘hd80M.img由于我要把调试过程给重新写出来 弄成博客 所以就导致我需要重新备份很多次硬盘 那我们就先开始弄吧

debug我昨晚还是调试了很久 因为调试中途会发现 各种地方自己写错的地方 尤其还发现自己的原来写的string.c里面也有函数写错了 于是我又修改了之后再去把原来的博客里面的函数给更新了 一个地方写错了 后面多个地方就没办法运行


xxd.sh文件代码


这里温馨的把xxd.sh文件给出来 因为毕竟很久也没用了 我之前也没有用过 这一章才创建的 有点难翻 这里就直接给出来即可

xxd.sh

xxd -u -a -g 1 -s $2 -l $3 $1

得到sda1起始数据扇区号


我们要调试验证的话 我们先去看看我们的根目录实现成功没有
其实我经常调试着调试着 就会发现原来很多地方自己写错了 然后又回去改
这次也是这样 我就发现 我不仅根目录的名称写错了 而且也没有建立成功 我自己返回去改了代码和博客之后才成功

我们由于写到这里了 文件系统已经建立好了 那我们怎么得到sbb1的info
哈哈 我就重新把我原来一个星期以前的硬盘从windows复制到了ubuntu 并在sdb1的文件建立后面 设置了一个while(1); 就得到了下面的信息

ok 成功得到sdb1 root_dir_lba: 0XA67


验证根目录是否建立成功


我们通过进制转换 我的sdb1起始扇区号是0xA67 也就是2663
那么我们通过计算机算一下 2663*512 = 1363456 得到了起始的扇区号

此时用命令sh xxd.sh hd80M.img 1363456 512看一下起始扇区内的内容装了什么
由于我们的根目录的目录项就是放在其实第一个扇区的 所以下面就是结果

2E2E 2E 其实就是... 这里先看不出来 02就是f_type

之后我们把main.c中的sys_open("/file1",O_CREAT);给取消注释了 创建文件看看是否我们的file1放进去了


第一次调用sys_open


下面是第一次create file1的截图
可以明显看到显示结果 creating file 此时我们不妨xxd.sh看看我们的根目录所在扇区有没有存进去


退出虚拟机 sh xxd.sh hd80M.img 1363456 512 看看里面究竟是什么样子
可以很清楚的看到 file1存储了进去 并且分配了inode编号为1 f_type为1普通文件FT_REGULAR 我们再去调用一下sys_open看看结果


第二次调用sys_open


可以很清楚的看到
/file1 has already exist! 满足预期! 那这一部分也先宣告结束了

每一章内容太多的话 就只能分到多个博客来发了 各位看官下一章再见了

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

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

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

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

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

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

    文章目录 专栏博客链接 相关查阅博客链接 本书中错误勘误 实现文件删除 编写完的inode.c(inode_delete函数) 编写完的dir.c(delete_dir_entry函数) 编写完的fs ...

  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. 太神奇的 SQL 查询经历,group by 慢查询优化!
  2. 使用T-SQL配置数据库事务日志传送
  3. 那些把天聊死的神操作。。| 今日最佳
  4. word表格图片自动适应表格大小_Excel应用实践20:使用Excel中的数据自动填写Word表格...
  5. 几本人工智能入门书籍
  6. c语言的退出程序代码,C语言实现关机小程序
  7. 餐饮智能化:餐饮机器人正当时餐饮机器人的喜与忧
  8. 基于librtmp的推流实现
  9. java泊松分布随机数_泊松分布随机数
  10. 大学十年(一个程序员的路程)(林锐博士)《1----9》【林锐的大学10年】
  11. AOP切面之实现计算器加减乘除--基于注解的方式
  12. 记一次Selenium框架的爬虫遇到下拉框页面的解决经历
  13. 固态硬盘的坏块管理,你知道和不知道的
  14. 苍蝇也有自己的“领空”吗?
  15. ORA-04091: table xxxx is mutating, trigger/function may not see it
  16. 留学计算机美国硕士,美国硕士留学计算机专业录取情况
  17. Android广播(Broadcast)
  18. Arduino实验九——感光灯实验
  19. Linux:目录,文件
  20. 2021辽宁金融高考成绩查询,2021年辽宁金融职业学院高考录取结果什么时候出来及查询系统入口...

热门文章

  1. 音乐 美术 劳技 计算机教研组工作总结,综合教研组教学工作总结
  2. 一个web前端专科生面试后的感概
  3. PaddleOCR体检报告识别
  4. UVa 815 Flooded
  5. keep-alive的用法和作用
  6. 《微信公众平台应用开发实战(第2版)》一1.1 微信公众账号的注册
  7. Linux 28 岁了,我们总结了 28 个不为人知的事实
  8. VideoCodec 入门篇 - 00 (编解码简介)
  9. c代码生成matlab模块,使用 C Caller 模块集成 C 代码
  10. redux的原理、工作流程及其应用