首先修正一个BUG,在初始化i结点数组的有关TTY的项中,在Make_FS函数中:
kernel/fs.c
- /* 填充TTY的i结点 */
- for(i = 0;i < TTY_NUM;i++)
- {
- //i_node++
- i_node = (I_Node*)(FS_BUF + I_NODE_SIZE * (i + 2));
- i_node->i_mode = INODE_MODE_SPECIAL; /* 文件类型为特殊的 */
- i_node->i_size = 0; /* 不占磁盘,当然为0 */
- i_node->i_start_sec = i; /* 这里表示TTY的编号 */
- i_node->i_sect_total = 0; /* 不占磁盘,当然为0 */
- }
在注释中这样是不对的。。因为这样自增把不存放在硬盘只存在于内存中的字段都包括了。。
好,首先增加一个Open函数,调用它就可以打开一个文件,返回一个fd。
kernel/fs.c
- /*--------------------------------------------------------------------------Open
- 根据提供的路径和打开模式打开一个文件
- 成功返回一个文件描述符,否则返回-1
- */
- int Open(const char *path,int flag)
- {
- Message m;
- m.msg_type = FS_OPEN_FILE;
- m.p1 = path;
- m.i1 = flag;
- m.i2 = Str_Len(path);
- Send_Receive_Shell(BOTH,PROC_FS_PID,&m); /* 发给文件系统进程 */
- return m.r1;
- }
那么在文件系统进程中要接收处理这个打开消息,在文件系统进程执行体末追加:
- /* 接收消息 */
- while(1)
- {
- Message m;
- Send_Receive_Shell(RECEIVE,ANY,&m);
- switch(m.msg_type)
- {
- /* 打开消息,则交给Do_Open_File函数处理 */
- case FS_OPEN_FILE:
- m.r1 = Do_Open_File(&m);
- break;
- default:
- Panic("UNKNOWN MSG TYPE!/n");
- break;
- }
- Send_Receive_Shell(SEND,m.src_proc_pid,&m);
- }
下面来看Do_Open_File函数等函数,详见注释:
- /*------------------------------------------------------------------Do_Open_File
- 打开(必要时创建一个文件并打开)一个文件
- */
- static int Do_Open_File(Message *m)
- {
- int fd = -1;
- int flags = m->i1; /* 取出打开模式 */
- PCB *p_caller = &PCB_Table[m->src_proc_pid]; /* 得到调用此进程的PCB */
- /* 把路径复制到栈中 */
- char path[MAX_PATH_SIZE];
- Str_Cpy(path,m->p1);
- /* 根据路径取得文件名 */
- char file_name[MAX_FILENAME_SIZE];
- if(Parse_Path(path,file_name) == 0)
- {
- return -1;
- }
- /* 在进程的PCB的文件描述符指针数组中寻找一个空的项 */
- int i;
- for(i = 0;i < MAX_FILE_PER_PROC;i++)
- {
- if(p_caller->fd_ptr_table[i] == 0)
- {
- fd = i; /* fd就是待返回的文件描述符 */
- break;
- }
- }
- /* 检验要返回的fd的正确性 */
- if(fd < 0 || fd >= MAX_FILE_PER_PROC)
- {
- Panic("fd_prt_table[] is full (PID:%d)/n",m->src_proc_pid);
- }
- /* 寻找一个未使用的文件描述符表的项 */
- for(i = 0;i < MAX_FILE;i++)
- {
- if(FD_Table[i].fd_inode == 0)
- {
- break;
- }
- }
- /* 检测是否超过表的大小,i就是在FD_Table中选中的项的索引 */
- if(i >= MAX_FILE)
- {
- Panic("FD_Table[] is full (PID:%d)/n",m->src_proc_pid);
- }
- /* 寻找文件,返回文件对应的i结点的索引,返回0表示文件不存在 */
- int file_inode_offset = Search_File(path);
- I_Node *p_inode = 0; /* 准备指向找到的文件在i结点缓冲表的i结点 */
- /* 如果Open时表示找不到就创建一个文件 */
- if(flags & O_CREATE)
- {
- /* 文件已存在,返回-1 */
- if(file_inode_offset != 0)
- {
- Printf("FILE EXISTS!/n");
- return -1;
- }
- /* 否则创建一个文件,返回对应的结点指针,指向i结点缓冲表的某项 */
- else
- {
- p_inode = Create_File(file_name);
- }
- }
- /* 表示读写 */
- else if(flags & O_RDWR)
- {
- char file_name[MAX_FILENAME_SIZE];
- if(Parse_Path(path,file_name) == 0)
- {
- return -1;
- }
- /* 取出对应的结点指针,指向i结点缓冲表的某项 */
- p_inode = Get_I_Node(FS_DEV,file_inode_offset);
- }
- /* 成功的话则把进程的fd_ptr_table,FD_Table和i结点缓冲表连接在一起 */
- if(p_inode != 0)
- {
- p_caller->fd_ptr_table[fd] = &FD_Table[i];
- FD_Table[i].fd_access_mode = flags;
- FD_Table[i].fd_pos = 0;
- FD_Table[i].fd_inode = p_inode;
- }
- /* 失败则返回-1 */
- else
- {
- return -1;
- }
- return fd;
- }
- /*-------------------------------------------------------------------Create_File
- 创建一个文件,逻辑很简单,就是函数调用
- */
- static I_Node *Create_File(const char *file_name)
- {
- u32 inode_index = Alloc_I_Node_Map_Bit(root_dir_inode->i_dev);
- u32 sec_index = Alloc_Sec_Map_Bit(root_dir_inode->i_dev);
- I_Node *new_inode = New_I_Node(root_dir_inode->i_dev,inode_index,sec_index);
- New_Dir_Entry(root_dir_inode,new_inode->inode_array_index,file_name);
- return new_inode;
- }
- /*----------------------------------------------------------Alloc_I_Node_Map_Bit
- 寻找device分区的i结点映射表的一个空闲的位,把此位置1表示占用
- 返回此位的在i结点映射表的索引
- */
- static u32 Alloc_I_Node_Map_Bit(u32 device)
- {
- u32 read_sec_begin = 1 + 1; /* i结点映射表的扇区偏移 */
- Super_Block *sb = Get_Super_Block(device); /* 获得device的超级块 */
- int i,j,k;
- u32 inode_index = 0; /* 待返回的i结点在表中的索引 */
- u8 *buf = (u8*)FS_BUF;
- /* 遍历i结点映射表的每一个扇区,其实只有1个扇区 */
- for(i = 0;i < sb->imap_sec_total;i++)
- {
- Read_Sector(device,read_sec_begin + i); /* 读到缓冲区 */
- /* 遍历当前的扇区的每一个字节 */
- for(j = 0;j < SECTOR_SIZE;j++)
- {
- /* 当前的字节都被占用,则继续下一次运行 */
- if(buf[j] == 0xff)
- {
- continue;
- }
- /* 到这里则表示这个字节有空位 */
- for(k = 0;((*buf >> k) & 1) != 0;k++); /* 将k定位到空闲的位上 */
- inode_index = (i * SECTOR_SIZE + j) * 8 + k; /* 求得待返回的值 */
- *buf |= (1 << k); /* 将该空闲位置1,表示已占用 */
- Write_Sector(device,read_sec_begin + i); /* 写回硬盘 */
- return inode_index;
- }
- }
- return 0;
- }
- /*-------------------------------------------------------------Alloc_Sec_Map_Bit
- 寻找数据区连续DEF_FILE_SEC_NUM个空闲扇区
- 寻找到占用后返回第一个扇区的相对于整个分区的索引
- 反之返回0
- */
- static u32 Alloc_Sec_Map_Bit(u32 device)
- {
- Super_Block *sb = Get_Super_Block(device); /* 取得超级块 */
- int i,j,k;
- int sec_to_alloc = DEF_FILE_SEC_NUM; /* 默认给一个文件的扇区大小,固定 */
- int is_find = 0;
- u32 read_sec_begin = 1 + 1 + sb->imap_sec_total; /* 扇区映射表的起始扇区 */
- u32 first_sector = 0; /* 待返回值 */
- u8 *buf = (u8*)FS_BUF;
- /* 遍历扇区映射表的每一个扇区 */
- for(i = 0;i < sb->smap_sec_total;i++)
- {
- Read_Sector(device,read_sec_begin + i); /* 读入缓冲区 */
- /* 遍历当前扇区的每一个字节 */
- for(j = 0;j < SECTOR_SIZE;j++)
- {
- /* 如果当前字节都被占用,继续下一次循环 */
- if(buf[j] == 0xff)
- {
- continue;
- }
- /* 来到这里则表示有空位 */
- for(k = 0;((buf[j] << k & 1)) != 0;k++); /* 把k定位到空闲的位上 */
- /* 待返回的值赋值 */
- first_sector = (i * SECTOR_SIZE + j) * 8 + k + sb->first_data_sec;
- /* 把当前字节的在k之后的空位置1,表示占用 */
- for(;k < 8;k++)
- {
- buf[j] |= (1 << k);
- sec_to_alloc--; /* 置1的次数自减1 */
- }
- is_find = 1; /* 表示找到连续的空间 */
- break;
- }
- /* 找到则跳出外循环 */
- if(is_find)
- {
- break;
- }
- }
- /* 表示找遍整张表都没找到空间,返回0表示失败 */
- if(is_find == 0)
- {
- return 0;
- }
- int is_finish = 0; /* 置1(表示被占用)完成的标记 */
- /* 还有位要置1则继续 */
- while(sec_to_alloc > 0)
- {
- j++; /* 跳到下一个字节 */
- /* 如果超过本扇区的界限,则考虑下一个扇区*/
- if(j >= SECTOR_SIZE)
- {
- Write_Sector(device,read_sec_begin + i); /* 写回当前扇区到硬盘 */
- i++;
- Read_Sector(device,read_sec_begin + i); /* 读下一个扇区 */
- j = 0; /* 读扇区开头开始分析 */
- }
- /* 继续把当前字节置1 */
- for(k = 0;k < 8;k++)
- {
- buf[j] |= (1 << k);
- sec_to_alloc--;
- /* 工作结束,标志置1 */
- if(sec_to_alloc == 0)
- {
- is_finish = 1;
- break;
- }
- }
- /* 还有未置1的位,则继续 */
- if(sec_to_alloc != 0)
- {
- continue;
- }
- /* 完成的话则把当前扇区写回硬盘 */
- if(is_finish)
- {
- Write_Sector(device,read_sec_begin + i);
- break;
- }
- }
- return first_sector; /* 返回空闲扇区的首扇区总偏移 */
- }
- /*--------------------------------------------------------------------New_I_Node
- 把inode_index表示的i结点存入i结点缓冲表,并初始化表中的i结点
- 并把改动后的值写回到硬盘中的i结点数组中
- 并返回在i结点缓冲表的该结点的指针
- */
- static I_Node * New_I_Node(u32 device,u32 inode_index,u32 sec_index)
- {
- /* 详见Get_I_Node函数说明 */
- I_Node *new_inode = Get_I_Node(device,inode_index);
- /* 初始化 */
- new_inode->i_mode = INODE_MODE_NORMAL; /* 文件模式 */
- new_inode->i_size = 0; /* 还未写入任何值,设为0 */
- new_inode->i_start_sec = sec_index; /* 文件起始扇区偏移 */
- new_inode->i_sect_total = DEF_FILE_SEC_NUM; /* 设为固定的文件大小扇区数 */
- new_inode->i_dev = device; /* 设备号 */
- new_inode->shared_count = 1; /* 新创建的文件的i结点,肯定设为1 */
- new_inode->inode_array_index = inode_index; /* 在硬盘中的i结点表的索引 */
- Syn_I_Node(new_inode); /* 写回硬盘 */
- return new_inode; /* 返回*/
- }
- /*-----------------------------------------------------------------New_Dir_Entry
- 在根目录区中添加一项,对应刚创建的文件
- */
- static void New_Dir_Entry(I_Node *root_dir_inode,u32 inode_index,const char *file_name)
- {
- /* 此时根目录中实际的字节数,中间有空洞的也算 */
- u32 dir_entry_num = root_dir_inode->i_size / DIR_ENTRY_SIZE;
- /* 求得根目录现有数据占几个扇区 */
- u32 root_dir_sec_num = root_dir_inode->i_size / SECTOR_SIZE;
- if((root_dir_inode->i_size % SECTOR_SIZE) != 0)
- {
- root_dir_sec_num++;
- }
- Dir_Entry *current_dir_entry = (Dir_Entry*)FS_BUF;
- Dir_Entry *new_dir_entry = 0;
- int i,j,n,is_find;
- is_find = n = 0;
- /* 遍历根目录的占有的每个扇区 */
- for(i = 0;i < root_dir_sec_num;i++)
- {
- /* 读入缓冲区 */
- Read_Sector(root_dir_inode->i_dev,root_dir_inode->i_start_sec + i + 1);
- /* 遍历当前扇区的每一项 */
- for(j = 0;j < SECTOR_SIZE / DIR_ENTRY_SIZE;j++,current_dir_entry++)
- {
- /* 如果检测的项数超过总项数,则跳出 */
- if(++n > dir_entry_num)
- {
- break;
- }
- /* 发现未占用的项,则标记置1 */
- if(current_dir_entry->inode_index == 0)
- {
- new_dir_entry = current_dir_entry;
- is_find = 1;
- break;
- }
- }
- /* 找到或当前范围内未找到空项则跳出外循环 */
- if(is_find || n > dir_entry_num)
- {
- break;
- }
- }
- /* 表示要追加,不用判断文件个数是否超过范围,因为在分配i结点时已判断过 */
- if(new_dir_entry == 0)
- {
- new_dir_entry = current_dir_entry; /* 指向root_dir_sec_num + 1项 */
- root_dir_inode->i_size += DIR_ENTRY_SIZE; /* 根目录文件大小增大 */
- }
- /* 赋上相应的值 */
- new_dir_entry->inode_index = inode_index;
- Str_Cpy(new_dir_entry->file_name,file_name);
- /* 写回硬盘 */
- Write_Sector(root_dir_inode->i_dev,root_dir_inode->i_start_sec + i + 1);
- Syn_I_Node(root_dir_inode); /* 同步根目录的i结点 */
- }
新添加的宏如下:
include/fs.h
- #define MAX_PATH_SIZE 14 /* 路径最大长度 */
- #define DEF_FILE_SEC_NUM 10 /* 每个普通文件占用的固定的扇区数量 */
- #define INODE_MODE_NORMAL 0x8
- /* 打开文件的模式 */
- #define O_CREATE 0x1 /* 创建文件模式 */
- #define O_RDWR 0x2 /* 读写模式 */
那么在进程A中调用Open函数,打印出返回的fd值:
kernel/proc.c
- /*------------------------------------------------------------------------Proc_A
- 进程A的执行体
- */
- void Proc_A()
- {
- int fd = -1;
- fd = Open("/first_file",O_CREATE);
- Printf("FD:%d/n",fd);
- while(1)
- {
- //Milli_Delay(200);
- //Printf("%d ",Get_Ticks());
- Milli_Delay(200);
- }
- }
OK,make,bochs,运行结果如下:
如愿以偿的返回0,但还不知道写入硬盘的值是否正确,现在来查看硬盘:
i结点映射表:
扇区映射表:
i结点数组:
根目录区:
嗯,目前的结果是正确,但是所有的情况并没有测试到,如果有BUG等出错了再说吧。今天到此为止。。