手写操作系统(五十三)-实现文件的打开与关闭

代码、内容参考来自于包括《操作系统真象还原》、《一个64位操作系统的设计与实现》以及《ORANGE’S:一个操作系统的实现》。

我们已经在根目录下创建了文件file1,接下来就是实现文件打开和关闭了

1.文件打开

打开文件的核心操作是file_open函数完成的。

修改/fs/file.c

添加file_open函数

/* 打开编号为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 接受 2个参数, inode 编号 inode_no 和打开标识 flag,函数功能是打开编号为 inode_no 的 inode对应的文件,若成功则返回文件描述符,否则返回-1。

函数开头调用get_free_slot_in_global从文件表file_table中获取空位的下标。

bool* write_deny = &file_table[fd_idx].fd_inode->write_deny使变量write_deny指向该inode的write_deny位,下面进行判断和处理。if (flag & O_WRONLY || flag & O_RDWR)如果此次以写 文件的方式打开文件,也就是flag中包含O_WRONLY (只写)或O_RDWR (读和写),为了避免多个任务同 时写该文件而引起相互覆盖的混乱,if (!(*write_deny))对指针write_deny取值,判断是否为true,检查是否已有别的任 务正在写该文件,如果为false,将其置为true,表示本任务要对其执行写操作,否则就简单处理,输出提示信息“file can`t be write now, try again later”,也就是目前文件不能写入,然后返回-1。

如果flag是O_RDONLY读文件或O_CREAT创建文件,就不用理会 write_deny的值了,我们允许写文件时对其执行读操作。

最后return pcb_fd_install(fd_idx)将 fd_idx 安装到 fd_table 并返回结果,若成功则返回文件描述符,否则返回-1。

更改/fs/fs.c的sys_open函数

只要修改对flag判断的switch结构,增加其他标识的支持,即O_RDONLY、O_WRONLY和O_RDWR默认都由函数file_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);
}

 

2.文件关闭

接下来就是实现文件关闭的逻辑了

Linux 中文件关闭是 close 函数。

close函数原型是”int close(int fd)”,关闭成功则返回0,否则返回-1。

打开文件的核心操作是file_close函数完成的。

修改/fs/file.c

添加file_close函数

/* 关闭文件 */
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;
}

file_close 接受 1 个参数,文件 file,功能是关闭文件,成功则返回 0,否则返回-1。

file_close唯一失败返回的情况就是file为null。其余的代码就是恢复inode的状态.

修改/fs/fs.c,添加两个函数:

/* 将文件描述符转化为文件表的下标 */
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;
}

fd_local2global接受1个参数,文件描述符local_fd,功能是将文件描述符转化为文件表的下标。 原理就是将local_fd作为下标代入数组fd_table,fd_table[local_fd]的值便是文件表的下标。

函数sys_close接受1个参数,文件描述符fd,功能是关闭文件描述符fd指向的文件,成功返回0,否则返回-1。 通过”fd_local2global(fd)”获取file_table的下标,存入变量_fd,然后用_fd索引文件表中的相应文件结构,在下一行把文件结构的指针作为参数调用file_close关闭文件。 然后把本地文件描述符置为-1,使其为空可分配。

对应file.h

int32_t file_open(uint32_t inode_no, uint8_t flag);
int32_t file_close(struct file* file);

 

接下来就是修改main文件测试一下了

int main(void) {
    put_str("I am kernel\n");
    init_all();
    process_execute(u_prog_a, "u_prog_a");
    process_execute(u_prog_b, "u_prog_b");
    thread_start("k_thread_a", 31, k_thread_a, "I am thread_a");
    thread_start("k_thread_b", 31, k_thread_b, "I am thread_b");

    uint32_t fd = sys_open("/file1", O_RDONLY);
    printf("fd:%d\n", fd);
    sys_close(fd);
    printf("%d closed now\n", fd);
    while(1);
    return 0;
}

 

执行结果如下:

 

3.参考

郑钢著操作系统真象还原

田宇著一个64位操作系统的设计与实现

丁渊著ORANGE’S:一个操作系统的实现

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇