当前位置: 首页 > news >正文

实验25.创建文件

已完成实验

已完成实验链接

简介

实验 25. 创建文件

总结

inode 就是文件

  • i_no 就是 inode 号
  • i_sectors 是块地址数组,表示这个文件的内容是那些块构成的.
  • 如果是文件,那么块的内容是文件的内容
  • 如果是目录,那么这些块的内容是一个个目录项

dir_entry 目录项

  • 是目录文件的数据块的内容

文件描述符如何转换为 inode

  • 首先在内核有一个 所有线程打开的文件表 file_tbale
struct file file_table[MAX_FILE_OPEN];
  • 这个表的每一项是一个文件结构体
/// @brief 文件结构
struct file {
uint32_t fd_pos; // 记录当前文件操作的偏移地址
uint32_t fd_flag;
struct inode\* fd_inode;
};
  • 然后每个线程或进程 pcb 有一个文件描述符数组
struct task_struct {...int32_t fd_table[MAX_FILES_OPEN_PER_PROC];...
};
  • 其中 索引 0 标准输入 索引 1 标准输出 索引 2 标准错误
  • 其他文件描述符假如是 4,那么假设文件描述符数组 fd_table[4] = 7
  • 那么拿着 7 去找所有线程打开的文件表 file_tbale[7]的 file 结构体
  • file 结构体就能定位到 inode,也可以 fseek,也能判断读写 flags

主要代码

thread.h


+#define MAX_FILES_OPEN_PER_PROC 8
+/// @brief 进程或线程的pcb process control block 4096字节/// 一个pcb包含1个中断栈,1个线程栈,struct task_struct {uint32_t* self_kstack;  // pcb中线程栈的地址pid_t pid;enum task_status status;  // 状态char name[16];            //uint8_t priority;         // 线程优先级uint8_t ticks;           // 每次在处理器上执行的时间嘀嗒数uint32_t elapsed_ticks;  // 处理器上执行的时间嘀嗒总数+    int32_t fd_table[MAX_FILES_OPEN_PER_PROC];  // 文件描述符数组
+struct list_elem general_tag;   // 放入就绪队列struct list_elem all_list_tag;  // 放入全部队列// 用户进程使用 内核线程不使用uint32_t* pgdir;                               // 指向用户的页目录项struct virtual_addr userprog_vaddr;            // 用户进程的虚拟地址池struct mem_block_desc u_block_desc[DESC_CNT];  // 用户进程内存块描述符uint32_t stack_magic;  // pcb魔数,用于检测栈的溢出};

thread.c

/// @brief 初始化pcb/// @param pthread pcb/// @param name 线程名/// @param prio 优先级void init_thread(struct task_struct* pthread, char* name, int prio) {// 清0memset(pthread, 0, sizeof(*pthread));pthread->pid = allocate_pid();  // 设置pid// 设置状态if (pthread == main_thread) {  // 如果是主线程pcbpthread->status = TASK_RUNNING;} else {pthread->status = TASK_READY;}// 初始化名字、优先级、时钟、总时钟、魔数strcpy(pthread->name, name);pthread->priority = prio;pthread->ticks = prio;pthread->elapsed_ticks = 0;pthread->pgdir = NULL;pthread->stack_magic = 0x19870916;  // 自定义的魔数+    // 文教描述符数组
+    pthread->fd_table[0] = 0;  // 标准输入
+    pthread->fd_table[1] = 1;  // 标准输出
+    pthread->fd_table[2] = 2;  // 标准错误输出
+    uint8_t fd_idx = 3;        // 剩下都是-1
+    while (fd_idx < MAX_FILES_OPEN_PER_PROC) {
+        pthread->fd_table[fd_idx] = -1;
+        fd_idx++;
+    }
+// self_kstack是线程自己在内核态下使用的栈顶地址pthread->self_kstack = (uint32_t*)((uint32_t)pthread + PG_SIZE);}

inode.h

/// @brief inode结构
struct inode {uint32_t i_no;  // inode编号// 当此inode是文件时,i_size是指文件大小,// 若此inode是目录,i_size是指该目录下所有目录项大小之和uint32_t i_size;uint32_t i_open_cnts;  // 记录此文件被打开的次数bool write_deny;       // 写文件不能并行,进程写文件前检查此标识// 数据块地址数组: i_sectors[0-11]是直接块, i_sectors[12]用来存储一级间接块指针// 里面的每一个数据块都是数据,文件就是本身数据,目录就是一个个目录项uint32_t i_sectors[13];struct list_elem inode_tag;
};

inode.c


/// @brief inode位置信息
struct inode_position {bool two_sec;       // inode是否跨扇区uint32_t sec_lba;   // inode所在的扇区号uint32_t off_size;  // inode在扇区内的字节偏移量
};/// @brief 打开inode
/// 先从分区已打开inode中找,再从硬盘找,找到后inode的打开次数+1
/// @param part 分区
/// @param inode_no inode号
/// @return inode的数据结构指针 注意:这个指针指向的结构体在堆内存
struct inode* inode_open(struct partition* part, uint32_t inode_no);/// @brief 同步inode
/// 把内存中inode的信息同步到硬盘
/// @param part 分区
/// @param inode inode指针
/// @param io_buf 从硬盘读出的扇区数据缓存
void inode_sync(struct partition* part, struct inode* inode, void* io_buf);/// @brief 关闭inode
/// 如果打开多次,那么次数-1,如果次数为0,那么删除在内存中的indoe
/// @param inode inode指针
void inode_close(struct inode* inode);/// @brief 删除inode
/// 把硬盘中inode表中的inode结构体全部归0
/// 感觉不太需要,只要把inode位图中的位给0就可以代表了
/// @param part 分区
/// @param inode_no inode号
/// @param io_buf 从硬盘读出的扇区数据缓存
void inode_delete(struct partition* part, uint32_t inode_no, void* io_buf);/// @brief 释放inode
/// 在硬盘inode位图中标志该inode为空闲,并在块位图中标记他的所有块为空闲
/// @param part 分区
/// @param inode_no inode号
void inode_release(struct partition* part, uint32_t inode_no);/// @brief 初始化inode
/// 除了inode号全部默认值
/// @param inode_no inode号
/// @param new_inode inode指针
void inode_init(uint32_t inode_no, struct inode* new_inode);

dir.h

#define MAX_FILE_NAME_LEN 16  // 最大文件名长度/// @brief 目录结构
struct dir {struct inode* inode;uint32_t dir_pos;      // 记录在目录内的偏移uint8_t dir_buf[512];  // 目录的数据缓存
};/// @brief 目录项结构
struct dir_entry {char filename[MAX_FILE_NAME_LEN];  // 普通文件或目录名称uint32_t i_no;                     // 普通文件或目录对应的inode编号enum file_types f_type;            // 文件类型
};

dir.c


struct dir root_dir;  // 根目录/// @brief 打开根目录
/// 打开inode0
/// @param part
void open_root_dir(struct partition* part);/// @brief 打开目录
/// 打开inode号的目录,返回目录指针
/// 堆内存申请的结构体,返回这个结构体的指针
/// @param part 分区
/// @param inode_no 目录inode号
/// @return 目录指针
struct dir* dir_open(struct partition* part, uint32_t inode_no);/// @brief 关闭目录
/// 关闭inode号的目录,释放目录结构体
/// @param dir
void dir_close(struct dir* dir);/// @brief 寻找文件
/// 在part分区内的pdir目录内寻找名为name的文件或目录
/// @param part 分区
/// @param pdir 目录
/// @param name 文件或目录名
/// @param dir_e 保存结果
/// @return 找到后返回true并将其目录项存入dir_e,否则返回false
bool search_dir_entry(struct partition* part, struct dir* pdir, const char* name, struct dir_entry* dir_e);/// @brief 创建目录项
/// 赋值目录项指针指向的目录项的文件名,inode号,文件类型
/// @param filename 文件名
/// @param inode_no inode号
/// @param file_type 文件类型
/// @param p_de 目录项指针
void create_dir_entry(char* filename, uint32_t inode_no, uint8_t file_type, struct dir_entry* p_de);/// @brief 同步目录项
/// 在硬盘中将目录项p_de写入父目录parent_dir的数据块中,io_buf由主调函数提供
/// @param parent_dir 父目录指针
/// @param p_de 目录项指针
/// @param io_buf 缓冲区由外部提供
/// @return 成功返回true,失败返回false
bool sync_dir_entry(struct dir* parent_dir, struct dir_entry* p_de, void* io_buf);

file.h

/// @brief 文件结构
struct file {uint32_t fd_pos;  // 记录当前文件操作的偏移地址,以0为起始,最大为文件大小-1uint32_t fd_flag;struct inode* fd_inode;
};/// @brief 标准输入输出描述符
enum std_fd {stdin_no,   // 0 标准输入stdout_no,  // 1 标准输出stderr_no   // 2 标准错误
};/// @brief 位图类型
enum bitmap_type {INODE_BITMAP,  // inode位图BLOCK_BITMAP   // 块位图
};#define MAX_FILE_OPEN 32  // 系统可打开的最大文件数

file.c


/// @brief 全局打开的文件表
struct file file_table[MAX_FILE_OPEN];/// @brief 从全局打开的文件表中获取一个空闲位置
/// @return 成功返回下标,失败返回-1
int32_t get_free_slot_in_global(void)/// @brief 分配一个描述符索引
/// 将全局描述符下标安装到进程或线程自己的文件描述符数组fd_table中
/// @param globa_fd_idx 全局描述符下标
/// @return 成功返回下标,失败返回-1
int32_t pcb_fd_install(int32_t globa_fd_idx)/// @brief 在块位图中分配一个位
/// @param part 分区
/// @return 扇区地址
int32_t block_bitmap_alloc(struct partition* part)/// @brief 同步内存位图bit_idx比特位所在的扇区中到硬盘
/// @param part 分区
/// @param bit_idx 比特偏移
/// @param btmp_type 位图类型
void bitmap_sync(struct partition* part, uint32_t bit_idx, uint8_t btmp_type)/// @brief 创建文件
/// @param parent_dir 父目录
/// @param filename 文件名
/// @param flag 打开文件的选项
/// @return 若成功则返回文件描述符,否则返回-1
int32_t file_create(struct dir* parent_dir, char* filename, uint8_t flag)

fs.h

#define MAX_FILES_PER_PART 4096         // 每个分区所支持最大创建的文件数
#define BITS_PER_SECTOR    4096         // 每扇区的位数 512字节 = 4096比特
#define SECTOR_SIZE        512          // 扇区字节大小
#define BLOCK_SIZE         SECTOR_SIZE  // 块字节大小#define MAX_PATH_LEN 512  // 路径最大长度/// @brief 文件类型
enum file_types {FT_UNKNOWN,   // 不支持的文件类型FT_REGULAR,   // 普通文件FT_DIRECTORY  // 目录
};/// @brief 打开文件的选项
enum oflags {O_RDONLY,    // 只读O_WRONLY,    // 只写O_RDWR,      // 读写O_CREAT = 4  // 创建
};/// @brief 用来记录查找文件过程中已找到的上级路径,也就是查找文件过程中"走过的地方"
struct path_search_record {char searched_path[MAX_PATH_LEN];  // 查找过程中的父路径struct dir* parent_dir;            // 文件或目录所在的直接父目录enum file_types file_type;         // 找到的是普通文件还是目录,找不到将为未知类型(FT_UNKNOWN)
};

fs.c

/// @brief 将最上层路径名称解析出来
/// @param pathname 路径 /a/b/c
/// @param name_store a
/// @return /b/c
static int search_file(const char* pathname, struct path_search_record* searched_record)/// @brief 查找文件
/// @param pathname 文件名
/// @param searched_record 保存结果
/// @return 若找到则返回其inode号,否则返回-1
static int search_file(const char* pathname, struct path_search_record* searched_record)/// @brief 打开或创建文件
/// @param pathname 文件路径
/// @param flags
/// @return 成功后,返回文件描述符,否则返回-1
int32_t sys_open(const char* pathname, uint8_t flags)/// @brief 在磁盘上搜索文件系统,若没有则格式化分区创建文件系统
void filesys_init() {...// 确定默认操作的分区char default_part[8] = "sdb1";// 挂载分区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; }
}

init.c

// 文件: init.c
// 时间: 2024-07-22
// 来自: ccj
// 描述: 内核所有初始化操作#include "init.h"
#include "print.h"
#include "interrupt.h"
#include "timer.h"
#include "memory.h"
#include "thread.h"
#include "keyboard.h"
#include "console.h"
#include "tss.h"
#include "syscall-init.h"
#include "ide.h"
#include "fs.h"/// @brief 内核所有初始化
void init_all() {put_str("init all\n");idt_init();       // 初始化中断timer_init();     // 调快时钟、注册时钟中断来调度线程mem_init();       // 初始化内存管理系统thread_init();    // 初始化线程console_init();   // 控制台初始化最好放在开中断之前keyboard_init();  // 键盘初始化tss_init();       // tss初始化syscall_init();   // 初始化系统调用intr_enable();    // 打开中断ide_init();       // 初始化硬盘filesys_init();   // 初始化文件系统
}

main.c

int main(void) {put_str("I am kernel\n");init_all();process_execute(u_prog_a, "user_prog_a");process_execute(u_prog_b, "user_prog_b");thread_start("k_thread_a", 31, k_thread_a, "argA ");thread_start("k_thread_b", 31, k_thread_b, "argB ");sys_open("/file1", O_CREAT);while (1);return 0;
}

在这里插入图片描述
在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • linux中信号的相关概念
  • 利用QT和FFmpeg实现一个简单的视频播放器
  • android视频播放,(一)MediaPlayer视频播放示例
  • 微调LLama 3.1——七月论文审稿GPT第5.5版:拿早期paper-review数据集微调LLama 3.1
  • Docker的卸载|安装|启动|停止|重启
  • vue防止鼠标左键拖动选中页面的元素
  • Elasticsearch 文档修改:全量更新与增量更新
  • C语言 | Leetcode C语言题解之第329题矩阵中的最长递增路径
  • LeetCode Pow(x, n)
  • HTTP的场景实践
  • 学习嵌入式的第十六天----结构体 共用体
  • C# winform 三层架构增删改查,(删除篇)
  • Python面试宝典第32题:课程表
  • cmake+ninja交叉编译android下的静态库
  • Elasticsearch 基本搜索
  • Angular 4.x 动态创建组件
  • FastReport在线报表设计器工作原理
  • gcc介绍及安装
  • HashMap ConcurrentHashMap
  • java8 Stream Pipelines 浅析
  • mac修复ab及siege安装
  • nodejs实现webservice问题总结
  • Python 基础起步 (十) 什么叫函数?
  • Redis在Web项目中的应用与实践
  • v-if和v-for连用出现的问题
  • 技术:超级实用的电脑小技巧
  • 批量截取pdf文件
  • 强力优化Rancher k8s中国区的使用体验
  • 算法-插入排序
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • 一份游戏开发学习路线
  • 栈实现走出迷宫(C++)
  • Android开发者必备:推荐一款助力开发的开源APP
  • 函数计算新功能-----支持C#函数
  • 如何在招聘中考核.NET架构师
  • #NOIP 2014# day.1 T2 联合权值
  • #pragma预处理命令
  • #常见电池型号介绍 常见电池尺寸是多少【详解】
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • ( 10 )MySQL中的外键
  • (3) cmake编译多个cpp文件
  • (floyd+补集) poj 3275
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (笔试题)合法字符串
  • (附源码)spring boot校园拼车微信小程序 毕业设计 091617
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (四十一)大数据实战——spark的yarn模式生产环境部署
  • (一)RocketMQ初步认识
  • (转)3D模板阴影原理
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • ... 是什么 ?... 有什么用处?