现在我们可以通过IDE磁盘操作来直接读写硬盘扇区,但是这样使用起来非常不方便。我们需要建立一个系统的,有序的文件系统来以“文件”的形式来读写硬盘数据。一个扇区的数据大小为0x200字节,这对于一个文件来说实在是太小了,于是人们采用了一种叫作三级指针的结构来存储文件。首先定义文件的数据结构:
//文件块数据结构 typedef struct fs_s { union { //文件信息块 struct { //模式 u32 mode; //所属者 u32 owner; //所属组 u32 group; //大小 u32 size; //./ u32 dot; //../ u32 dotdot; //root_no u32 root; //is root u32 is_root; //文件名 char name[476]; //文件地址项 u32 address; }; //一级、二级、三级地址项 struct { u32 addr_no[FS_ADDR_COUNT]; }; //文件数据内容 struct { u8 data[FS_DATA_COUNT]; }; }; } s_fs;
一个文件的起始扇区中存放了文件头内容,包括文件名、文件类型、权限等内容,并在最后一个属性中定义了一个u32 address,用于存放一级地址号。这个一级地址号即为一个扇区号,这个扇区中存放了u32 addr_no[FS_ADDR_COUNT]一级地址,也就是一共有0x80个一级地址,每一个一级地址中都存放了一个二级地址号,每一个二级地址号中存放了0x80个三级地址,而每一个三级地址存放了一个真正的数据扇区号。如下图:
其中每个地址都是一个箭头指向另一个地址扇区或数据扇区。可以计算出一个文件的最大占用大小为:0x80 * 0x80 * 0x80 * 0x200 = 0x40000000字节 = 1024MB = 1GB。
下面来实现创建文件的具体代码:
/* * fs_create_fs : 根据父级文件编号创建子文件(夹) * - u32 parent_no : 低级文件块编号 * - char *fs_name : 待创建的文件(夹)名称 * - u32 fs_mode : FS_FOLDER_MODE为文件夹,FS_FILE_MODE为文件 * return : u32 返回新创建的子文件(夹—)编号,0代表创建失败 */ u32 fs_create_fs_path(char *path, char *fs_name, u32 uid, u32 gid, u32 mode) { //根据父级编号读入文件块 s_fs *fs_parent = alloc_mm(sizeof(s_fs)); u32 dev_id = 0; fs_find_path(path, &dev_id, &fs_parent); //root if (uid != 0) { if (fs_parent->owner != uid && fs_parent->group != gid) { if (((fs_parent->mode >> 1) & 0x1) == 0) { free_mm(fs_parent, sizeof(sizeof(s_fs))); return 0; } } else if (fs_parent->owner != uid && fs_parent->group == gid) { if (((fs_parent->mode >> 4) & 0x1) == 0) { free_mm(fs_parent, sizeof(sizeof(s_fs))); return 0; } } else if (fs_parent->owner == uid) { if (((fs_parent->mode >> 7) & 0x1) == 0) { free_mm(fs_parent, sizeof(sizeof(s_fs))); return 0; } } } s_fs *fs = alloc_mm(sizeof(s_fs)); //清空文件块内容 fs_empty_data(fs); fs->owner = uid; fs->group = gid; //文件模式 fs->mode = mode; //申请一块未使用的文件块,给本文件块 fs->dot = alloc_sec(dev_id); if (fs->dot == 0) { free_mm(fs, sizeof(s_fs)); free_mm(fs_parent, sizeof(s_fs)); return 0; } //设定父级文件块编号 fs->dotdot = fs_parent->dot; //root if (fs_parent->is_root) { fs->root = fs_parent->dot; } else { fs->root = fs_parent->root; } //文件大小 fs->size = 0; //设定文件名称 str_copy(fs_name, fs->name); //定入此新的文件块 write_block(dev_id, fs->dot, fs); /* * 以下是将此文件块挂入其父级文件块中 */ //父级子项地址 s_fs *fst_addrs = alloc_mm(sizeof(s_fs)); if (fs_parent->address == 0) { //创建一级磁盘指针 fs_parent->address = alloc_sec(dev_id); fs_empty_data(fst_addrs); //保存地址项 write_block(dev_id, fs_parent->address, fst_addrs); //保存父级文件块 write_block(dev_id, fs_parent->dot, fs_parent); } //一级地址列表 read_block(dev_id, fs_parent->address, fst_addrs); for (int i = 0; i < FS_ADDR_COUNT; ++i) { s_fs *sec_addrs = alloc_mm(sizeof(s_fs)); if (fst_addrs->addr_no[i] == 0) { //创建二级磁盘指针 fst_addrs->addr_no[i] = alloc_sec(dev_id); fs_empty_data(sec_addrs); //保存地址项 write_block(dev_id, fst_addrs->addr_no[i], sec_addrs); //保存父级文件块 write_block(dev_id, fs_parent->address, fst_addrs); } //二级地址列表 read_block(dev_id, fst_addrs->addr_no[i], sec_addrs); for (int j = 0; j < FS_ADDR_COUNT; ++j) { s_fs *thrid_addrs = alloc_mm(sizeof(s_fs)); if (sec_addrs->addr_no[j] == 0) { //创建三级磁盘指针 sec_addrs->addr_no[j] = alloc_sec(dev_id); fs_empty_data(thrid_addrs); //保存地址项 write_block(dev_id, sec_addrs->addr_no[j], thrid_addrs); //保存父级文件块 write_block(dev_id, fst_addrs->addr_no[i], sec_addrs); } //三级地址列表 read_block(dev_id, sec_addrs->addr_no[j], thrid_addrs); for (int k = 0; k < FS_ADDR_COUNT; ++k) { if (thrid_addrs->addr_no[k] == 0) { //挂入文件块 thrid_addrs->addr_no[k] = fs->dot; //保存三级文件块内容 write_block(dev_id, sec_addrs->addr_no[j], thrid_addrs); //返回新的文件块编号 u32 sno = fs->dot; free_mm(thrid_addrs, sizeof(s_fs)); free_mm(sec_addrs, sizeof(s_fs)); free_mm(fst_addrs, sizeof(s_fs)); free_mm(fs, sizeof(s_fs)); free_mm(fs_parent, sizeof(s_fs)); return sno; } } free_mm(thrid_addrs, sizeof(s_fs)); } free_mm(sec_addrs, sizeof(s_fs)); } free_mm(fst_addrs, sizeof(s_fs)); free_mm(fs, sizeof(s_fs)); free_mm(fs_parent, sizeof(s_fs)); //创建失败,返回0 return 0; }
打开一个文件:
/* * f_open : 打开文件 * - char *file_name : 完整路径文件名 * - int fs_mode : FS_MODE_WRITE为写模式,FS_MODE_READ为读模式 * return : s_file*文件结构指针 */ s_file* f_open(char *file_name, int fs_mode, u32 uid, u32 gid) { if (str_len(file_name) == 0) { return NULL; } char dev_path[FS_NAME_LENGTH]; u32 dev_id = find_dev_id_fullpath(file_name, dev_path); //文件名称,临时变量 char *fs_name = alloc_mm(FS_NAME_LENGTH); u32 parent_no = 0; int child_no = 0; for (int i = 0, j = 0; dev_path[i] != '\0'; ++i) { //取得文件目录名称 if (dev_path[i] != '/') { fs_name[j++] = dev_path[i]; } else { //根据目录名称查找子目录 fs_name[j++] = '/'; fs_name[j++] = '\0'; j = 0; child_no = fs_find_sub_fs(dev_id, parent_no, fs_name); if (child_no == 0) { free_mm(fs_name, FS_NAME_LENGTH); return NULL; } parent_no = child_no; } if (dev_path[i + 1] == '\0') { fs_name[j++] = '\0'; //查找文件 child_no = fs_find_sub_fs(dev_id, parent_no, fs_name); //没找到 if (child_no == 0) { free_mm(fs_name, FS_NAME_LENGTH); //返回空 return NULL; } } } //申请文件内存 s_file *fp = alloc_mm(sizeof(s_file)); //读入文件内容 read_block(dev_id, child_no, &fp->fs); //root if (uid != 0) { if (fp->fs.owner != uid && fp->fs.group != gid) { if (fs_mode == FS_MODE_READ && ((fp->fs.mode >> 2) & 0x1) == 0) { free_mm(fs_name, FS_NAME_LENGTH); free_mm(fp, sizeof(s_file)); return NULL; } else if (fs_mode == FS_MODE_WRITE && ((fp->fs.mode >> 1) & 0x1) == 0) { free_mm(fs_name, FS_NAME_LENGTH); free_mm(fp, sizeof(s_file)); return NULL; } } else if (fp->fs.owner != uid && fp->fs.group == gid) { if (fs_mode == FS_MODE_READ && ((fp->fs.mode >> 5) & 0x1) == 0) { free_mm(fs_name, FS_NAME_LENGTH); free_mm(fp, sizeof(s_file)); return NULL; } else if (fs_mode == FS_MODE_WRITE && ((fp->fs.mode >> 4) & 0x1) == 0) { free_mm(fs_name, FS_NAME_LENGTH); free_mm(fp, sizeof(s_file)); return NULL; } } else if (fp->fs.owner == uid) { if (fs_mode == FS_MODE_READ && ((fp->fs.mode >> 8) & 0x1) == 0) { free_mm(fs_name, FS_NAME_LENGTH); free_mm(fp, sizeof(s_file)); return NULL; } else if (fs_mode == FS_MODE_WRITE && ((fp->fs.mode >> 7) & 0x1) == 0) { free_mm(fs_name, FS_NAME_LENGTH); free_mm(fp, sizeof(s_file)); return NULL; } } } fp->dev_id = dev_id; fp->fs_mode = fs_mode; fp->offset = 0; fp->offset_buff = 0; fp->offset_read_buff = FS_READ_BUFF; fp->block_offset = 0; fp->addr_index = 0; fp->first_index = 0; fp->sec_index = 0; fp->third_index = 0; if (fs_mode == FS_MODE_WRITE) { fp->fs.size = 0; fp->buff = alloc_mm(FS_DATA_COUNT); } else if (fs_mode == FS_MODE_READ) { fp->buff = alloc_mm(FS_READ_BUFF); } fs_empty_data(fp->buff); fp->next = NULL; free_mm(fs_name, FS_NAME_LENGTH); //返回文件指针 return fp; }
读取文件内容:
/* * f_read : 读取文件内容 * - s_file *fp : 文件指针 * - int size : 读入字节数 * - char *data : 等待读入的数据地址 * return : int读入字节数 */ int f_read(s_file *fp, int size, char *data) { //文件为空,出错 if (fp == NULL) { return 0; } //文件不是读模式,出错 if (fp->fs_mode != FS_MODE_READ) { return 0; } if (fp->offset + size >= fp->fs.size) { size = fp->fs.size - fp->offset; } int read_size = 0; int offset_read = 0; while (size >= FS_READ_BUFF) { if (fp->offset_read_buff >= FS_READ_BUFF) { f_read_buff(fp); fp->offset_read_buff = 0; } mmcopy_with(fp->buff, data + offset_read, fp->offset_read_buff, FS_READ_BUFF); fp->offset += FS_READ_BUFF; fp->offset_read_buff += FS_READ_BUFF; offset_read += FS_READ_BUFF; size -= FS_READ_BUFF; read_size += FS_READ_BUFF; } if (size > 0 && size < FS_READ_BUFF) { if (fp->offset_read_buff >= FS_READ_BUFF) { f_read_buff(fp); fp->offset_read_buff = 0; } mmcopy_with(fp->buff, data + offset_read, fp->offset_read_buff, size); fp->offset += size; fp->offset_read_buff += size; offset_read += size; read_size += size; size = 0; } return read_size; }
写入文件内容:
/* * f_write : 写入数据到文件 * - s_file *fp : 文件指针 * - int size : 写入字节数 * - char *data : 写入数据 * return : int文件当前偏移 */ int f_write(s_file *fp, int size, char *data) { //文件为空,出错 if (fp == NULL) { return -1; } //读模式不能写入文件 if (fp->fs_mode != FS_MODE_WRITE) { return -1; } //循环写文件 for (int i = 0; i < size; ++i) { //拷贝数据到缓冲区 fp->buff[fp->block_offset] = data[i]; fp->block_offset++; fp->fs.size++; //buff写满0x200之后写入磁盘块 if (fp->block_offset >= FS_DATA_COUNT) { //一次写入0x200字节 f_write_block(fp); fp->block_offset = 0; fp->offset += FS_DATA_COUNT; } } //返回文件当前偏移 return fp->offset; }
关闭文件:
/* * f_close : 关闭文件 * - s_file *fp : 文件指针 * return : -1为失败, 0 为成功 */ int f_close(s_file *fp) { //文件指针为空,出错 if (fp == NULL) { return -1; } //如果是写模式,要将最后一次没写入完成的内容写入文件 if (fp->fs_mode == FS_MODE_WRITE) { //如果有块内偏移 if (fp->block_offset > 0) { //写入剩余内容 for (int i = fp->block_offset; i < FS_DATA_COUNT; ++i) { fp->buff[i] = 0; } f_write_block(fp); } //写入文件,主要更新文件大小属性 write_block(fp->dev_id, fp->fs.dot, &fp->fs); } //释放文件指针内存 if (fp->fs_mode == FS_MODE_WRITE) { free_mm(fp->buff, FS_DATA_COUNT); } else if (fp->fs_mode == FS_MODE_READ) { free_mm(fp->buff, FS_READ_BUFF); } free_mm(fp, sizeof(s_file)); //返回成功 return 0; }
查找文件:
/* * 查找文件,根据文件路径名查找文件,并取得文件内容 */ int fs_find_path(char *path_name, u32 *ret_dev_id, s_fs **fs) { char dev_path[FS_NAME_LENGTH]; u32 dev_id = find_dev_id_fullpath(path_name, dev_path); //临时保存文件夹名称 char folder_name[FS_NAME_LENGTH]; //父级文件块编号 u32 parent_no = 0; for (int i = 0, j = 0; dev_path[i] != '\0'; ++i) { //以'/'为分割符取得文件夹名称 if (dev_path[i] != '/') { folder_name[j++] = dev_path[i]; } else { //取得文件夹名称 folder_name[j++] = '/'; folder_name[j++] = '\0'; j = 0; //根据父级文件块编号查找其下的直属子文件 int child_no = fs_find_sub_fs(dev_id, parent_no, folder_name); //没有找到此文件 if (child_no == 0) { //返回空 fs_empty_data(*fs); return FS_STATUS_NO_FILE_DIR; } //找到子文件块,将其设定为下一级父文件块编号 parent_no = child_no; } } //根据文件块编号读取文件块内容,并写入文件块指针所指向的地址 read_block(dev_id, parent_no, *fs); *ret_dev_id = dev_id; return FS_STATUS_OK; }
Copyright © 2015-2023 问渠网 辽ICP备15013245号