创建以及打开文件文件“系统调用”

    首先修正一个BUG,在初始化i结点数组的有关TTY的项中,在Make_FS函数中:

    kernel/fs.c

Code:
  1. /* 填充TTY的i结点 */  
  2. for(i = 0;i < TTY_NUM;i++)   
  3. {   
  4.     //i_node++   
  5.     i_node = (I_Node*)(FS_BUF + I_NODE_SIZE * (i + 2));    
  6.     i_node->i_mode = INODE_MODE_SPECIAL;    /* 文件类型为特殊的 */  
  7.     i_node->i_size = 0;                     /* 不占磁盘,当然为0 */  
  8.     i_node->i_start_sec = i;                /* 这里表示TTY的编号 */  
  9.     i_node->i_sect_total = 0;               /* 不占磁盘,当然为0 */  
  10. }  

    在注释中这样是不对的。。因为这样自增把不存放在硬盘只存在于内存中的字段都包括了。。

    好,首先增加一个Open函数,调用它就可以打开一个文件,返回一个fd。

    kernel/fs.c

Code:
  1. /*--------------------------------------------------------------------------Open  
  2.     根据提供的路径和打开模式打开一个文件  
  3.     成功返回一个文件描述符,否则返回-1  
  4. */  
  5. int Open(const char *path,int flag)   
  6. {   
  7.     Message m;   
  8.     m.msg_type = FS_OPEN_FILE;   
  9.     m.p1 = path;   
  10.     m.i1 = flag;   
  11.     m.i2 = Str_Len(path);   
  12.        
  13.     Send_Receive_Shell(BOTH,PROC_FS_PID,&m);    /* 发给文件系统进程 */  
  14.     return m.r1;   
  15. }  

    那么在文件系统进程中要接收处理这个打开消息,在文件系统进程执行体末追加:

Code:
  1. /* 接收消息 */  
  2. while(1)   
  3. {   
  4.     Message m;   
  5.     Send_Receive_Shell(RECEIVE,ANY,&m);   
  6.     switch(m.msg_type)   
  7.     {   
  8.         /* 打开消息,则交给Do_Open_File函数处理 */  
  9.         case FS_OPEN_FILE:   
  10.             m.r1 = Do_Open_File(&m);   
  11.             break;   
  12.                
  13.         default:   
  14.             Panic("UNKNOWN MSG TYPE!/n");   
  15.             break;   
  16.     }   
  17.     Send_Receive_Shell(SEND,m.src_proc_pid,&m);    
  18. }  

    下面来看Do_Open_File函数等函数,详见注释:

   

Code:
  1. /*------------------------------------------------------------------Do_Open_File  
  2.     打开(必要时创建一个文件并打开)一个文件  
  3. */  
  4. static int Do_Open_File(Message *m)   
  5. {   
  6.     int fd = -1;   
  7.     int flags = m->i1;  /* 取出打开模式 */  
  8.     PCB *p_caller = &PCB_Table[m->src_proc_pid];    /* 得到调用此进程的PCB */  
  9.        
  10.     /* 把路径复制到栈中 */  
  11.     char path[MAX_PATH_SIZE];   
  12.     Str_Cpy(path,m->p1);   
  13.        
  14.     /* 根据路径取得文件名 */  
  15.     char file_name[MAX_FILENAME_SIZE];   
  16.     if(Parse_Path(path,file_name) == 0)   
  17.     {   
  18.         return -1;   
  19.     }   
  20.        
  21.     /* 在进程的PCB的文件描述符指针数组中寻找一个空的项 */  
  22.     int i;   
  23.     for(i = 0;i < MAX_FILE_PER_PROC;i++)   
  24.     {   
  25.         if(p_caller->fd_ptr_table[i] == 0)   
  26.         {   
  27.             fd = i;     /* fd就是待返回的文件描述符 */  
  28.             break;   
  29.         }   
  30.     }   
  31.     /* 检验要返回的fd的正确性 */  
  32.     if(fd < 0 || fd >= MAX_FILE_PER_PROC)   
  33.     {   
  34.         Panic("fd_prt_table[] is full (PID:%d)/n",m->src_proc_pid);   
  35.     }   
  36.        
  37.     /* 寻找一个未使用的文件描述符表的项 */  
  38.     for(i = 0;i < MAX_FILE;i++)   
  39.     {   
  40.         if(FD_Table[i].fd_inode == 0)   
  41.         {   
  42.             break;   
  43.         }   
  44.     }   
  45.     /* 检测是否超过表的大小,i就是在FD_Table中选中的项的索引 */  
  46.     if(i >= MAX_FILE)   
  47.     {   
  48.         Panic("FD_Table[] is full (PID:%d)/n",m->src_proc_pid);   
  49.     }   
  50.     /* 寻找文件,返回文件对应的i结点的索引,返回0表示文件不存在 */  
  51.     int file_inode_offset = Search_File(path);     
  52.     I_Node *p_inode = 0;    /* 准备指向找到的文件在i结点缓冲表的i结点 */  
  53.        
  54.     /* 如果Open时表示找不到就创建一个文件 */  
  55.     if(flags & O_CREATE)   
  56.     {   
  57.         /* 文件已存在,返回-1 */  
  58.         if(file_inode_offset != 0)   
  59.         {   
  60.             Printf("FILE EXISTS!/n");   
  61.             return -1;   
  62.         }   
  63.         /* 否则创建一个文件,返回对应的结点指针,指向i结点缓冲表的某项 */  
  64.         else  
  65.         {   
  66.             p_inode = Create_File(file_name);   
  67.         }   
  68.     }   
  69.     /* 表示读写 */  
  70.     else if(flags & O_RDWR)   
  71.     {   
  72.         char file_name[MAX_FILENAME_SIZE];   
  73.         if(Parse_Path(path,file_name) == 0)   
  74.         {   
  75.             return -1;   
  76.         }   
  77.         /* 取出对应的结点指针,指向i结点缓冲表的某项 */  
  78.         p_inode = Get_I_Node(FS_DEV,file_inode_offset);   
  79.     }   
  80.     /* 成功的话则把进程的fd_ptr_table,FD_Table和i结点缓冲表连接在一起 */  
  81.     if(p_inode != 0)   
  82.     {   
  83.         p_caller->fd_ptr_table[fd] = &FD_Table[i];   
  84.         FD_Table[i].fd_access_mode = flags;   
  85.         FD_Table[i].fd_pos = 0;   
  86.         FD_Table[i].fd_inode = p_inode;   
  87.     }   
  88.     /* 失败则返回-1 */  
  89.     else  
  90.     {   
  91.         return -1;   
  92.     }   
  93.     return fd;   
  94. }   
  95.   
  96. /*-------------------------------------------------------------------Create_File   
  97.     创建一个文件,逻辑很简单,就是函数调用  
  98. */     
  99. static I_Node *Create_File(const char *file_name)   
  100. {   
  101.     u32 inode_index = Alloc_I_Node_Map_Bit(root_dir_inode->i_dev);   
  102.     u32 sec_index = Alloc_Sec_Map_Bit(root_dir_inode->i_dev);   
  103.     I_Node *new_inode = New_I_Node(root_dir_inode->i_dev,inode_index,sec_index);   
  104.     New_Dir_Entry(root_dir_inode,new_inode->inode_array_index,file_name);   
  105.     return new_inode;   
  106. }   
  107.   
  108. /*----------------------------------------------------------Alloc_I_Node_Map_Bit  
  109.     寻找device分区的i结点映射表的一个空闲的位,把此位置1表示占用  
  110.     返回此位的在i结点映射表的索引  
  111. */  
  112. static u32 Alloc_I_Node_Map_Bit(u32 device)   
  113. {   
  114.     u32 read_sec_begin = 1 + 1;     /* i结点映射表的扇区偏移 */  
  115.     Super_Block *sb = Get_Super_Block(device);  /* 获得device的超级块 */  
  116.     int i,j,k;   
  117.     u32 inode_index = 0;    /* 待返回的i结点在表中的索引 */  
  118.     u8 *buf = (u8*)FS_BUF;   
  119.        
  120.     /* 遍历i结点映射表的每一个扇区,其实只有1个扇区 */  
  121.     for(i = 0;i < sb->imap_sec_total;i++)   
  122.     {   
  123.         Read_Sector(device,read_sec_begin + i); /* 读到缓冲区 */  
  124.         /* 遍历当前的扇区的每一个字节 */  
  125.         for(j = 0;j < SECTOR_SIZE;j++)   
  126.         {   
  127.             /* 当前的字节都被占用,则继续下一次运行 */  
  128.             if(buf[j] == 0xff)   
  129.             {   
  130.                 continue;   
  131.             }   
  132.             /* 到这里则表示这个字节有空位 */  
  133.             for(k = 0;((*buf >> k) & 1) != 0;k++);  /* 将k定位到空闲的位上 */  
  134.             inode_index = (i * SECTOR_SIZE + j) * 8 + k;    /* 求得待返回的值 */  
  135.             *buf |= (1 << k);   /* 将该空闲位置1,表示已占用 */  
  136.             Write_Sector(device,read_sec_begin + i);        /* 写回硬盘 */  
  137.             return inode_index;    
  138.         }   
  139.     }   
  140.     return 0;   
  141. }   
  142.   
  143. /*-------------------------------------------------------------Alloc_Sec_Map_Bit  
  144.     寻找数据区连续DEF_FILE_SEC_NUM个空闲扇区  
  145.     寻找到占用后返回第一个扇区的相对于整个分区的索引  
  146.     反之返回0  
  147. */  
  148. static u32 Alloc_Sec_Map_Bit(u32 device)   
  149. {   
  150.     Super_Block *sb = Get_Super_Block(device);  /* 取得超级块 */  
  151.     int i,j,k;   
  152.     int sec_to_alloc = DEF_FILE_SEC_NUM;    /* 默认给一个文件的扇区大小,固定 */  
  153.     int is_find = 0;   
  154.     u32 read_sec_begin = 1 + 1 + sb->imap_sec_total;    /* 扇区映射表的起始扇区 */  
  155.     u32 first_sector = 0;   /* 待返回值 */  
  156.     u8 *buf = (u8*)FS_BUF;   
  157.        
  158.     /* 遍历扇区映射表的每一个扇区 */  
  159.     for(i = 0;i < sb->smap_sec_total;i++)   
  160.     {   
  161.         Read_Sector(device,read_sec_begin + i); /* 读入缓冲区 */  
  162.         /* 遍历当前扇区的每一个字节 */  
  163.         for(j = 0;j < SECTOR_SIZE;j++)   
  164.         {   
  165.             /* 如果当前字节都被占用,继续下一次循环 */  
  166.             if(buf[j] == 0xff)   
  167.             {   
  168.                 continue;   
  169.             }   
  170.             /* 来到这里则表示有空位 */  
  171.             for(k = 0;((buf[j] << k & 1)) != 0;k++);    /* 把k定位到空闲的位上 */  
  172.             /* 待返回的值赋值 */  
  173.             first_sector = (i * SECTOR_SIZE + j) * 8 + k + sb->first_data_sec;   
  174.             /* 把当前字节的在k之后的空位置1,表示占用 */  
  175.             for(;k < 8;k++)   
  176.             {   
  177.                 buf[j] |= (1 << k);   
  178.                 sec_to_alloc--;     /* 置1的次数自减1 */  
  179.             }   
  180.             is_find = 1;    /* 表示找到连续的空间 */  
  181.             break;   
  182.         }   
  183.         /* 找到则跳出外循环 */  
  184.         if(is_find)   
  185.         {   
  186.             break;   
  187.         }   
  188.     }   
  189.     /* 表示找遍整张表都没找到空间,返回0表示失败 */  
  190.     if(is_find == 0)   
  191.     {   
  192.         return 0;   
  193.     }   
  194.        
  195.     int is_finish = 0;  /* 置1(表示被占用)完成的标记 */  
  196.     /* 还有位要置1则继续 */  
  197.     while(sec_to_alloc > 0)   
  198.     {   
  199.         j++;    /* 跳到下一个字节 */  
  200.         /* 如果超过本扇区的界限,则考虑下一个扇区*/  
  201.         if(j >= SECTOR_SIZE)   
  202.         {   
  203.             Write_Sector(device,read_sec_begin + i); /* 写回当前扇区到硬盘 */  
  204.             i++;   
  205.             Read_Sector(device,read_sec_begin + i); /* 读下一个扇区 */  
  206.             j = 0;  /* 读扇区开头开始分析 */  
  207.         }   
  208.         /* 继续把当前字节置1 */  
  209.         for(k = 0;k < 8;k++)   
  210.         {   
  211.             buf[j] |= (1 << k);   
  212.             sec_to_alloc--;   
  213.             /* 工作结束,标志置1 */  
  214.             if(sec_to_alloc == 0)   
  215.             {   
  216.                 is_finish = 1;   
  217.                 break;   
  218.             }   
  219.         }   
  220.         /* 还有未置1的位,则继续 */  
  221.         if(sec_to_alloc != 0)   
  222.         {   
  223.             continue;   
  224.         }    
  225.         /* 完成的话则把当前扇区写回硬盘 */  
  226.         if(is_finish)   
  227.         {   
  228.             Write_Sector(device,read_sec_begin + i);   
  229.             break;   
  230.         }   
  231.     }   
  232.        
  233.     return first_sector;    /* 返回空闲扇区的首扇区总偏移 */  
  234. }   
  235.   
  236. /*--------------------------------------------------------------------New_I_Node  
  237.     把inode_index表示的i结点存入i结点缓冲表,并初始化表中的i结点  
  238.     并把改动后的值写回到硬盘中的i结点数组中  
  239.     并返回在i结点缓冲表的该结点的指针  
  240. */  
  241. static I_Node * New_I_Node(u32 device,u32 inode_index,u32 sec_index)   
  242. {   
  243.     /* 详见Get_I_Node函数说明 */  
  244.     I_Node *new_inode = Get_I_Node(device,inode_index);    
  245.     /* 初始化 */  
  246.     new_inode->i_mode = INODE_MODE_NORMAL;      /* 文件模式 */  
  247.     new_inode->i_size = 0;                      /* 还未写入任何值,设为0 */  
  248.     new_inode->i_start_sec = sec_index;         /* 文件起始扇区偏移 */  
  249.     new_inode->i_sect_total = DEF_FILE_SEC_NUM; /* 设为固定的文件大小扇区数 */  
  250.        
  251.     new_inode->i_dev = device;      /* 设备号 */  
  252.     new_inode->shared_count = 1;    /* 新创建的文件的i结点,肯定设为1 */  
  253.     new_inode->inode_array_index = inode_index; /* 在硬盘中的i结点表的索引 */  
  254.        
  255.     Syn_I_Node(new_inode);  /* 写回硬盘 */  
  256.     return new_inode;       /*  返回*/  
  257. }   
  258.   
  259. /*-----------------------------------------------------------------New_Dir_Entry  
  260.     在根目录区中添加一项,对应刚创建的文件  
  261. */  
  262. static void New_Dir_Entry(I_Node *root_dir_inode,u32 inode_index,const char *file_name)   
  263. {   
  264.     /* 此时根目录中实际的字节数,中间有空洞的也算 */  
  265.     u32 dir_entry_num = root_dir_inode->i_size / DIR_ENTRY_SIZE;   
  266.     /* 求得根目录现有数据占几个扇区 */  
  267.     u32 root_dir_sec_num = root_dir_inode->i_size / SECTOR_SIZE;   
  268.     if((root_dir_inode->i_size % SECTOR_SIZE) != 0)   
  269.     {   
  270.         root_dir_sec_num++;   
  271.     }   
  272.     Dir_Entry *current_dir_entry = (Dir_Entry*)FS_BUF;   
  273.     Dir_Entry *new_dir_entry = 0;   
  274.     int i,j,n,is_find;   
  275.     is_find = n = 0;   
  276.     /* 遍历根目录的占有的每个扇区 */  
  277.     for(i = 0;i < root_dir_sec_num;i++)   
  278.     {   
  279.         /* 读入缓冲区 */  
  280.         Read_Sector(root_dir_inode->i_dev,root_dir_inode->i_start_sec + i + 1);   
  281.         /* 遍历当前扇区的每一项 */  
  282.         for(j = 0;j < SECTOR_SIZE / DIR_ENTRY_SIZE;j++,current_dir_entry++)   
  283.         {   
  284.             /* 如果检测的项数超过总项数,则跳出 */  
  285.             if(++n > dir_entry_num)   
  286.             {   
  287.                 break;   
  288.             }   
  289.             /* 发现未占用的项,则标记置1 */  
  290.             if(current_dir_entry->inode_index == 0)   
  291.             {   
  292.                 new_dir_entry = current_dir_entry;   
  293.                 is_find = 1;   
  294.                 break;   
  295.             }   
  296.         }   
  297.         /* 找到或当前范围内未找到空项则跳出外循环 */  
  298.         if(is_find || n > dir_entry_num)   
  299.         {   
  300.             break;   
  301.         }   
  302.     }   
  303.     /* 表示要追加,不用判断文件个数是否超过范围,因为在分配i结点时已判断过 */  
  304.     if(new_dir_entry == 0)   
  305.     {   
  306.         new_dir_entry = current_dir_entry;          /* 指向root_dir_sec_num + 1项 */  
  307.         root_dir_inode->i_size += DIR_ENTRY_SIZE;   /* 根目录文件大小增大 */  
  308.     }   
  309.     /* 赋上相应的值 */  
  310.     new_dir_entry->inode_index = inode_index;   
  311.     Str_Cpy(new_dir_entry->file_name,file_name);   
  312.     /* 写回硬盘 */  
  313.     Write_Sector(root_dir_inode->i_dev,root_dir_inode->i_start_sec + i + 1);   
  314.     Syn_I_Node(root_dir_inode);     /* 同步根目录的i结点 */  
  315. }  

    新添加的宏如下:

    include/fs.h

Code:
  1. #define MAX_PATH_SIZE       14          /* 路径最大长度 */   
  2. #define DEF_FILE_SEC_NUM    10          /* 每个普通文件占用的固定的扇区数量 */   
  3. #define INODE_MODE_NORMAL   0x8    
  4. /* 打开文件的模式 */  
  5. #define O_CREATE            0x1         /* 创建文件模式 */   
  6. #define O_RDWR              0x2         /* 读写模式 */  

    那么在进程A中调用Open函数,打印出返回的fd值:

    kernel/proc.c

Code:
  1. /*------------------------------------------------------------------------Proc_A  
  2.     进程A的执行体   
  3. */  
  4. void Proc_A()   
  5. {              
  6.     int fd = -1;   
  7.     fd = Open("/first_file",O_CREATE);   
  8.     Printf("FD:%d/n",fd);   
  9.     while(1)   
  10.     {      
  11.            
  12.         //Milli_Delay(200);   
  13.         //Printf("%d ",Get_Ticks());   
  14.         Milli_Delay(200);   
  15.     }   
  16. }  

    OK,make,bochs,运行结果如下:

    如愿以偿的返回0,但还不知道写入硬盘的值是否正确,现在来查看硬盘:

    i结点映射表:

    扇区映射表:

    i结点数组:

 

    根目录区:

    嗯,目前的结果是正确,但是所有的情况并没有测试到,如果有BUG等出错了再说吧。今天到此为止。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值