14.6 文件的打开与关闭
14.6.1 文件的打开
//fs.c
/*打开编号为inode_no的inode对应的文件,若成功则返回文件描述符,否则返回-1*/
int32_t file_open(uint32_t inode_no, uint8_t flag){
int fd_idx = get_free_slot_in_global();
if(fd_idx == -1){
printk("exceed max open files\n");
return -1;
}
file_table[fd_idx].fd_inode = inode_open(cur_part,inode_no);
file_table[fd_idx].fd_pos = 0; //每次打开文件,要将fd_pos还原为0,即让文件内的指针指向开头
file_table[fd_idx].fd_flag = flag;
bool* write_deny = &file_table[fd_idx].fd_inode->write_deny;
if(flag & O_WRONLY || flag & O_RDWR){
//只要是关于写文件,判断是否有其他进程正在写此文件,要保持互斥
//若是读文件,不需要考虑write_deny;
/*以下进入临界区前先关闭中断*/
enum intr_status old_status = intr_disable();
if(!(*write_deny)){ //若当前没有其他进程写该文件,将其占用
*write_deny = true; //置位true,避免多个进程同时写这个文件
intr_set_status(old_status);
}else{ //直接返回失败
intr_set_status(old_status);
printk("file can`t be write now, try again later\n");
return -1;
}
} //若是读文件或创建文件,不用例会write_deny,保持默认
return pcb_fd_install(fd_idx);
}
file_open
:函数功能是打开编号为inode_no的inode对应的文件,若成功则返回文件描述符,否则返回-1。流程:1.调用get_free_slot_in_global
先是获取一个空的fd描述符;2.再打开一个inode_no
并把它填充到file_table
;3.关于写文件,判断是否有其他进程正在写此文件,我们要保持互斥,读文件则不需要考虑;4.在创建文件进程或线程的pcb
中安装文件描述符。
同时修改上面之前是sys_open
这样我们的sys_open
函数就可以处理打开文件的命令了。
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);
break;
default:
/* 其余情况均为打开已存在文件:
* O_RDONLY,O_WRONLY,O_RDWR */
fd = file_open(inode_no, flags);
}
/* 此fd是指任务pcb->fd_table数组中的元素下标,
* 并不是指全局file_table中的下标 */
return fd;
14.6.2 文件的关闭
//fs.c
/*关闭文件*/
int32_t file_close(struct file* file){
if(file==NULL){
return -1;
}
file->fd_inode->write_deny=false;
inode_close(file->fd_inode);
file->fd_inode=NULL; //使得文件可用
return 0;
}
......
/*将文件描述符转化为文件表的下标*/
static uint32_t fd_local2global(uint32_t local_fd){
struct task_struct* cur = running_thread();
int32_t global_fd = cur->fd_table[local_fd];
ASSERT(global_fd>=0&&global_fd<MAX_FILE_OPEN);
return (uint32_t)global_fd;
}
/*关闭文件描述符fd指向的文件,成功返回0,失败返回-1*/
int32_t sys_close(int32_t fd){
int32_t ret = -1; //返回值默认为-1,即失败
if(fd>2){
uint32_t _fd = fd_local2global(fd);
ret = file_close(&file_table[_fd]);
running_thread()->fd_table[fd] = -1;//使得文件描述符位可用
}
return ret;
}
file_close
:将文件正在写标志关闭,调用inode_close
移除内存中的inode,并解除文件结构与inode的关系。
fd_local2global
:功能是将文件描述符转化为文件表的下标。这里说明一下:file_table[i]
中存储的是file
结构体里面存储着inode
,而进程的fd_table[j]
中存储的就是file_table[]
中文件标记的i
,这样就可以顺利的摸到inode
。