From c2e80123869a0990aaef2084c36a1613845eaf5b Mon Sep 17 00:00:00 2001 From: HfCloud Date: Thu, 8 Aug 2019 18:55:33 +0800 Subject: [PATCH] v0.11 --- TaurixFS/boot/grub/grub.cfg | 6 - configure.rb | 15 +- image/.gitignore | 2 + image/Taurix.tfs | 13 + image/build_grub_booted.rb | 14 + image/grub.cfg | 7 + include/taurix/utils.h | 7 +- src/arch/i386/extra_flags.rb | 4 +- src/arch/i386/i386_process.c | 3 +- src/fs/fat32.c | 674 +++++++++++++++++++++++++++++++++++ src/fs/fat32.h | 179 ++++++++++ src/fs/gptpart.c | 306 ++++++++++++++++ src/fs/gptpart.h | 141 ++++++++ src/fs/taurix_fs_patch.h | 14 + src/fs/tfstools.h | 208 +++++++++++ src/utils/utils.c | 46 ++- taurix-settings-gui.py | 1 + 17 files changed, 1612 insertions(+), 28 deletions(-) delete mode 100644 TaurixFS/boot/grub/grub.cfg create mode 100644 image/.gitignore create mode 100755 image/Taurix.tfs create mode 100644 image/build_grub_booted.rb create mode 100644 image/grub.cfg create mode 100644 src/fs/fat32.c create mode 100644 src/fs/fat32.h create mode 100644 src/fs/gptpart.c create mode 100644 src/fs/gptpart.h create mode 100644 src/fs/taurix_fs_patch.h create mode 100644 src/fs/tfstools.h diff --git a/TaurixFS/boot/grub/grub.cfg b/TaurixFS/boot/grub/grub.cfg deleted file mode 100644 index 79f0d65..0000000 --- a/TaurixFS/boot/grub/grub.cfg +++ /dev/null @@ -1,6 +0,0 @@ -insmod part_gpt -insmod part_msdos - -menuentry 'Taurix' --class os { - multiboot (hd0,gpt3)/boot/Taurix -} diff --git a/configure.rb b/configure.rb index 9511ab0..bce9d78 100755 --- a/configure.rb +++ b/configure.rb @@ -1,4 +1,5 @@ -#!/usr/bin/ruby +#!/bin/ruby +#encoding: utf-8 # Generate makefile from settings for building taruix # author: hfcloud(sxysxygm@gmail.com) # date: 2019.07.28 @@ -151,19 +152,17 @@ def src_obj_file(file) end #制成由grub引导的硬盘镜像文件的规则 -MAKEFILE.print("Taurix.img: Taurix\n\t") -MAKEFILE.print("cp Taurix ./TaurixFS/boot\n\t") -MAKEFILE.print("grub-mkrescue -o Taurix.img TaurixFS\n") +MAKEFILE.print("image/Taurix.img: Taurix\n\t") +MAKEFILE.print("ruby image/build_grub_booted.rb\n") #别名 Image <-> Taurix.img -MAKEFILE.print("Image:\n\tmake Taurix.img\n") +MAKEFILE.print("Image:\n\tmake image/Taurix.img\n") #清除规则 MAKEFILE.print("clean:\n\t") MAKEFILE.print("#{RM} *.o\n\t") MAKEFILE.print("#{RM} Taurix\n\t") -MAKEFILE.print("#{RM} Taurix.img\n\t") -MAKEFILE.print("#{RM} ./TaurixFS/boot/Taurix\n") +MAKEFILE.print("#{RM} image/Taurix.img\n") MAKEFILE.close @@ -172,7 +171,7 @@ def src_obj_file(file) #!/usr/bin/sh make Image if [ $? -eq 0 ]; then - env LANG=en_US.UTF8 qemu-system-#{$arch} Taurix.img %s + env LANG=en_US.UTF8 qemu-system-#{$arch} image/Taurix.img %s fi AAAA diff --git a/image/.gitignore b/image/.gitignore new file mode 100644 index 0000000..c822824 --- /dev/null +++ b/image/.gitignore @@ -0,0 +1,2 @@ +*.img +ImageBuild.log \ No newline at end of file diff --git a/image/Taurix.tfs b/image/Taurix.tfs new file mode 100755 index 0000000..fb046f2 --- /dev/null +++ b/image/Taurix.tfs @@ -0,0 +1,13 @@ +#!/bin/tfstools +open Taurix.img + +# Select the EFI Partition +select 0 + +#copy grub.cfg and Taruix +enter_part FAT32 +push ../Taurix Taurix +cd GRUB +push grub.cfg grub.cfg +close +exit 0 diff --git a/image/build_grub_booted.rb b/image/build_grub_booted.rb new file mode 100644 index 0000000..8ef30b9 --- /dev/null +++ b/image/build_grub_booted.rb @@ -0,0 +1,14 @@ +#!/bin/ruby +#encoding: utf-8 + +require 'fileutils' +Dir.chdir(File.dirname(__FILE__)) + +FileUtils.cp("template.img", "Taurix.img") +if !system("tfstools Taurix.tfs > ImageBuild.log") + FileUtils.rm("Taurix.img") + puts("Failed to build Taurix.img") + exit 1 +end + + diff --git a/image/grub.cfg b/image/grub.cfg new file mode 100644 index 0000000..989eca4 --- /dev/null +++ b/image/grub.cfg @@ -0,0 +1,7 @@ +insmod part_gpt +insmod elf +insmod video_info + +menuentry 'Taurix' --class os { + multiboot /Taurix +} diff --git a/include/taurix/utils.h b/include/taurix/utils.h index 2046618..6ffd6ed 100644 --- a/include/taurix/utils.h +++ b/include/taurix/utils.h @@ -71,12 +71,16 @@ int ru_sprintf_s(char *buf, size_t max_size, const char *format, ...); //->s //stdlib.h void *ru_memset(void *base, uint8 data, size_t size); //->src/utils/utils.c -void *ru_memcpy(void *dest, void *src, size_t size); +void *ru_memcpy(void *dest, const void *src, size_t size); //string.h char *ru_strcpy(char *dest, const char *src); //->src/utils/utils.c int ru_strlen(const char *str); int ru_strcmp(const char *a, const char *b); +int ru_strncmp(const char *a, const char *b, size_t size); +char *ru_strncpy(char *dest, const char *src, size_t size); +int ru_memcmp(const void *a, const void *b, size_t size); +char *ru_strcat(char *dest, const char *src); //math //整数开根,返回根号x下取整 @@ -109,7 +113,6 @@ int32 ru_detect_available_memory(size_t min_size, _OUT void **baseaddr, _OUT siz int32 ru_text_init(); int32 ru_text_putchar(int ch); //->src/平台/arch_utils(n).c 平台相关的函数 void ru_text_print(const char *text); -int32 ru_text_printf(const char *format, ...); void ru_text_set_color(uint32 color); //设置文本的颜色 void ru_text_set_cursor(int row, int col); int32 ru_text_get_colmns(); //获得文本模式下文字的 列数(宽度) diff --git a/src/arch/i386/extra_flags.rb b/src/arch/i386/extra_flags.rb index d835fb9..64d0f6b 100644 --- a/src/arch/i386/extra_flags.rb +++ b/src/arch/i386/extra_flags.rb @@ -1,5 +1,5 @@ -_CC_FLAGS_COMMON.push("-m32") -_CXX_FLAGS_COMMON.push("-m32") +_CC_FLAGS_COMMON.push("-m32 -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast") +_CXX_FLAGS_COMMON.push("-m32 -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast") _ASM_FLAGS_COMMON.push("-f elf") if RUBY_PLATFORM =~ /darwin/ #fuck OSX CLANG diff --git a/src/arch/i386/i386_process.c b/src/arch/i386/i386_process.c index e3cc3d9..e712c90 100644 --- a/src/arch/i386/i386_process.c +++ b/src/arch/i386/i386_process.c @@ -101,7 +101,7 @@ void clock_int_handler(Context *context) { } //开始进行调度, 使用第一个加入调度器的进程作为第一个进程,duration_per_slice指定了每个时间片的时间(单位:ms) -int32 ps_schedule(ProcessScheduler *ps, uint32 duration_per_slice) { +int32 ps_schedule(ProcessScheduler *ps, uint32 duration_per_slice) { ru_disable_interrupt(); // uint16 freq = 1000 / duration_per_slice; @@ -162,6 +162,7 @@ void ps_do_auto_schedule(ProcessScheduler *ps, Context *context) { //时间片 ru_memcpy(context, &perfer_proc->context, sizeof(Context)); else //同特权级任务切换,不需要恢复堆栈 ru_memcpy(context, &perfer_proc->context, sizeof(Context) - 8); //no esp0, ss0 + } else { //依然没有进程可以调度,挂起 ru_text_set_color(VGA_TEXT_RED); ru_text_print("[ Halt ] No process to switch\n"); diff --git a/src/fs/fat32.c b/src/fs/fat32.c new file mode 100644 index 0000000..005583d --- /dev/null +++ b/src/fs/fat32.c @@ -0,0 +1,674 @@ +#include "fat32.h" + +static inline uint64 cluster2lba(FAT32Tool *fat, uint32 cluster) { + uint64 data_lba = fat->fat_lba + fat->num_fat * fat->sectors_per_fat; + return data_lba + (cluster-2) * fat->sectors_per_cluster; + //(cluster-2)而不是cluster,因为前两个簇被保留了。FAT32只是保留前2个FAT表项,并不保留前两个簇。 + //gtmd被wiki的中文翻译坑了。。。 +} + +//将fat表第fatid项的值设置为newid,如果newid小于0则不改变fatid项上的数值,为0是空闲簇 +//如果oldid不为空指针,会设置通过这个参数返回这个表项上原本的数值 +static int set_fat_next(FAT32Tool *fat, uint32 fatid, uint32 *oldid, int newid) { + uint64 lba = fat->fat_lba + fatid / 128; + if(lba < fat->fat_lba || lba >= fat->fat_lba + fat->sectors_per_fat) + return ERROR_TFS_INVALID_ARGUMENT; + fat->fs.io.read_lba(lba, lba, fat->sector_buffer); + uint32* fats = (uint32*)fat->sector_buffer; + if(oldid) + *oldid = fats[fatid % 128]; + if(newid >= 0) { + fats[fatid % 128] = newid; + for(int i = 0; i < fat->num_fat; i++) { //写回修改后的fat表项 + fat->fs.io.write_lba(lba + fat->sectors_per_fat * i, lba + fat->sectors_per_fat * i, fat->sector_buffer); + } + } + return STATUS_SUCCESS; +} + +static uint32 __find_next_free_item(FAT32Tool *fat) { + + static uint32 fatid = 0; //查找的起点 + int wrapped = 0; //回头从前面找过的标记 + + while(1) { + int flag = 0; + uint64 lba = fat->fat_lba + fatid / 128; + fat->fs.io.read_lba(lba, lba, fat->sector_buffer); + uint32 *fats = (uint32*)fat->sector_buffer; + int offset = 0; + for(int i = fatid % 128; i < 128; i++) { + if(!fats[i]) { + flag = 1; + offset = i; + break; + } else fatid++; + + } + if(flag) { //已找到 + return fatid; //返回fat表项的id,也即空闲簇的簇号 + } else { + lba++; + if(lba == fat->fat_lba + fat->sectors_per_fat) { + if(!wrapped) { + fatid = 0; + wrapped = 1; + continue; + } else { + break; //确实没有空闲表项了 + } + } + } + } + return 0; +} + +//找到一个空闲表项(空闲簇),分配掉,返回编号,如果返回0表示fat表被分配完 +static uint32 alloc_fat_item(FAT32Tool *fat) { + const uint32 cluster = fat->fsinfo.next_free_cluster; + if(cluster) { + const uint64 lba = fat->fat_lba + cluster / 128; //因为一个扇区有128个FAT表项 + fat->fs.io.read_lba(lba, lba, fat->sector_buffer); + uint32 *fats = (uint32*)fat->sector_buffer; + fats[cluster % 128] = FAT32_FILE_END; + fat->fs.io.write_lba(lba, lba, fat->sector_buffer); //写回 + fat->fsinfo.next_free_cluster = __find_next_free_item(fat); + fat->fsinfo.free_clusters--; + } + return cluster; +} + +int fat32_fstool_initialize(FAT32Tool *fat, FSIO io, uint64 start_lba, uint64 end_lba) { + fat->fs.io = io; + if(start_lba > end_lba) + return ERROR_TFS_INVALID_ARGUMENT; + fat->fs.start_lba = start_lba; + fat->fs.end_lba = end_lba; + fat->fs.create_file = fat32_create_file; + fat->fs.delete_file = fat32_delete_file; + fat->fs.makefs = fat32_makefs; + fat->fs.enum_dir = fat32_enum_dir; + fat->fs.query_file_info = fat32_query_file_info; + fat->fs.create_file = fat32_create_file; + fat->fs.delete_file = fat32_delete_file; + fat->fs.fread = fat32_fread; + fat->fs.fwrite = fat32_fwrite; + fat->fs.fseek = fat32_fseek; + fat->fs.sync_information = fat32_sync_information; + + FAT32Header header; + fat->fs.io.read_lba(start_lba, start_lba, &header); + fat->is_valid_fat32 = memcmp("FAT32", header.fat32, 5) == 0; + + fat->fat_lba = fat->fs.start_lba + header.num_reserved; + fat->num_fat = header.num_fat; + fat->sectors_per_fat = header.sectors_per_fat32; + fat->sectors_per_cluster = header.sectors_per_clust; + fat->root_dir_cluster = header.root_dir_start; + //fat->root_dir_cluster = 0; + //fsinfo + if(header.fsinfo) { + fat->fs.io.read_lba(start_lba + header.fsinfo, start_lba + header.fsinfo, &fat->fsinfo ); + } + if(fat->sectors_per_cluster > 8) { //大于8不支持鸭 + return ERROR_TFS_UNSUPPORTED_FEATURE; + } + if(((uint64)fat->sectors_per_fat) * 512 / 4 > 0xfffffef) { + return ERROR_TFS_NO_SPACE; //fat表表项太多 + } + return STATUS_SUCCESS; +} + +int fat32_makefs(struct tagFSTool *fs) { + FAT32Tool *fat = ((FAT32Tool*)fs); + if(fs->end_lba - fs->start_lba + 1 < 4000) + return ERROR_TFS_NO_SPACE; + if(fs->end_lba - fs->start_lba + 1 > 0xffffffffu) //太大 + return ERROR_TFS_NO_SPACE; + { + FAT32Header header; + memset(&header, 0, sizeof(header)); + memcpy(header.jmp, "\xeb\x58\x90", 3); + memcpy(header.OEM, "tfstool", 8); + header.bytes_per_sector = 512; + //header.sectors_per_clust = 8; //4kb + header.sectors_per_clust = 1; + header.num_reserved = 32; + header.num_fat = 2; //两个fat表 + header.material = 0xf8; + header.num_sectors = fs->end_lba - fs->start_lba + 1; + //s <- end_lba - start_lba + 1 - num_reserved + //t <- sectors_per_clust + //num_fat = 2 + //x <- sectors_per_fat32 + //sectors_per_clust + //s - 2 * x = x * (512/4) * t + // x = s / (128*t + 2) + header.sectors_per_fat32 = (uint32)(fs->end_lba - fs->start_lba + 1 - header.num_reserved) / (128*header.sectors_per_clust+2) - 1; + if(header.sectors_per_fat32 < header.num_fat + 1) + return ERROR_TFS_NO_SPACE; + header.root_dir_start = 2; // + header.fsinfo = 1; + header.backup = 2; + header.device_code = 0x80; + memcpy(header.fat32, "FAT32", 5); + header.aa55 = 0xaa55; + fs->io.write_lba(fs->start_lba, fs->start_lba, &header); + fs->io.write_lba(fs->start_lba+2, fs->start_lba+2, &header); //备份引导扇区 + + //fsinfo: + fat->fsinfo.aa55 = 0xaa55; + fat->fsinfo.x41615252 = 0x41615252; + fat->fsinfo.x61417272 = 0x61417272; + fat->fsinfo.free_clusters = (uint32)((fs->end_lba - fs->start_lba + 1) - header.sectors_per_fat32 * header.num_fat) / header.sectors_per_clust; + //fat->fsinfo.next_free_cluster = header.root_dir_start + 1; + fat->fsinfo.next_free_cluster = 5; + fs->io.write_lba(fs->start_lba+1, fs->start_lba+1, &fat->fsinfo); + } + + //在这之前fat结构体内的成员大都是不可用的 + int e = fat32_fstool_initialize(fat, fs->io, fs->start_lba, fs->end_lba); //偷个懒,直接调用它... + if(e) return e; + { + unsigned char init_fat[512] = {0}; + //0号项 + init_fat[0] = 0xf8; + init_fat[1] = 0xff; + init_fat[2] = 0xff; + init_fat[3] = 0x0f; + //1号项 + init_fat[4] = 0xf8; + init_fat[5] = 0xff; + init_fat[6] = 0xff; + init_fat[7] = 0x0f; + //根目录项 + init_fat[8] = 0xff; + init_fat[9] = 0xff; + init_fat[10] = 0xff; + init_fat[11] = 0x0f; + fs->io.write_lba(fat->fat_lba, fat->fat_lba, init_fat); //FAT1 + fs->io.write_lba(fat->fat_lba + fat->sectors_per_fat, fat->fat_lba + fat->sectors_per_fat, init_fat); //FAT2 + } + return e; +} //创建无文件的文件系统 + +#define CHECK_FS if(!fat->is_valid_fat32) {return ERROR_TFS_INVALID_FS; } + +#define HANDLE_CLUSTER(h) ((h) & 0x00000000ffffffffull) +#define HANDLE_OFFSET(h) (((h) & 0xffffffff00000000ull) >> 32) +#define MAKE_CLUSTER_OFFSET_HANDLE(cl, of) (((FileHandle)of << 32) | cl) + +//FileItem可被占用 +#define ITEM_AVAILABLE(x) (x.attribute == 0 || x.dosname[0] == 0xe5) + +//将FileInfo指示的信息转变为Fat文件系统的文件信息,返回错误信息 +static inline int FileInfoToFat(FileInfo *info, FAT32FileItem *item, uint32 first_cluster) { + int name_len = strlen(info->name_char); + int i; + for(i = name_len - 1; ~i; i--) { + if(info->name_char[i] == '.') { //找最后一个 . + if(i <= 7) { + if(name_len - i - 1 > 3) { + return ERROR_TFS_INVALID_FILENAME; //扩展名太长 + } else { + break; + } + } else { + return ERROR_TFS_INVALID_FILENAME; //文件名太长 + } + } + } + + if(i < 0) { //没有扩展名 + if(name_len > 8) return ERROR_TFS_INVALID_FILENAME; //太长 + strcpy((char*)item->dosname, info->name_char); + for(i = name_len; i < 8; i++) { //空格补齐 + item->dosname[i] = ' '; + } + memset(item->dosname_ext, ' ', sizeof(item->dosname_ext)); + } else { + if(i > 8) + return ERROR_TFS_INVALID_FILENAME; //太长 + strncpy((char*)item->dosname, info->name_char, i); + for(int j = i; j < 8; j++) + item->dosname[j] = ' '; + int ext_len = name_len - i - 1; + strncpy((char*)item->dosname_ext, info->name_char+i+1, ext_len); + for(int j = ext_len; j < 3; j++) + item->dosname_ext[j] = ' '; //补空格 + } + + item->attribute = 0; + if(info->attributes & FILE_ATTRIBUTE_READONLY) + item->attribute |= 0x01; + if(info->attributes & FILE_ATTRIBUTE_HIDDEN) + item->attribute |= 0x02; + if(info->attributes & FILE_ATTRIBUTE_SYSTEM) + item->attribute |= 0x04; + if(info->is_directory) { + item->attribute |= 0x10; + } else { + item->attribute |= 0x20; + } + if(info->attributes & FILE_ATTRIBUTE_DEVICE) + item->attribute |= 0x40; + + item->create_time_ymd = (((info->created_year - 1980) & 0x7f) << 9) | (info->created_month << 5) | (info->created_day); + item->create_time_hmsdiv2 = (info->created_hour << 11) | (info->created_minute << 5) | (info->created_second / 2); + item->create_time_in2s = (info->created_second & 1) * 100; + + item->access_time_ymd = (((info->access_year - 1980) & 0x7f) << 9) | (info->access_month << 5) | (info->access_day); + item->modify_time_ymd = (((info->modify_year - 1980) & 0x7f) << 9) | (info->modify_month << 5) | (info->modify_day); + item->modify_time_hmsdiv2 = (info->modify_hour << 11) | (info->modify_minute << 5) | (info->modify_second / 2); + if(info->file_size_in_bytes > 0xffffffffu) + return ERROR_TFS_NO_SPACE; //文件太大。。。 + item->file_size_in_byte = info->file_size_in_bytes; + item->first_cluster_low = first_cluster & 0x0000ffff; + item->first_cluster_hight = (first_cluster & 0xffff0000u) >> 16; + return STATUS_SUCCESS; +} + +//Fat32目录项 -> 标准FileInfo,无需返回值 +void FileItemToFileInfo(FAT32Tool *fat, FAT32FileItem *item, FileInfo *info) { + //size + info->file_size_in_bytes = item->file_size_in_byte; + int size_per_cluster = (512 * fat->sectors_per_cluster); + info->file_occupies_in_bytes = item->file_size_in_byte % size_per_cluster ? (item->file_size_in_byte / size_per_cluster + 1) * size_per_cluster : item->file_size_in_byte; + + //attribute + if(item->attribute & 0x10) { + info->is_directory = 1; + } else info->is_directory = 0; + if(item->attribute & 0x40) + info->attributes |= FILE_ATTRIBUTE_DEVICE; + if(item->attribute & 0x01) + info->attributes |= FILE_ATTRIBUTE_READONLY; + if(item->attribute & 0x02) + info->attributes |= FILE_ATTRIBUTE_HIDDEN; + if(item->attribute & 0x04) + info->attributes |= FILE_ATTRIBUTE_SYSTEM; + + //name + int name_len = 8; + for(name_len--; name_len >= 0 && item->dosname[name_len] == ' '; name_len--); + name_len++; + + memcpy(info->name_char, (const void*)item->dosname, name_len); + info->name_char[name_len] = 0; + + int ext_len = 3; + for(ext_len--; ext_len>=0 && item->dosname_ext[ext_len] == ' '; ext_len--); + ext_len++; + if(ext_len) { + strcat(info->name_char, "."); + memcpy(info->name_char + name_len + 1, item->dosname_ext, ext_len); + info->name_char[name_len + 1 + ext_len] = 0; + } + //TODO: 日期信息,太智障了不想做了。。。恶心死了 + info->access_ymdhms = 0; + info->modify_ymdhms = 0; + info->created_ymdhms = 0; + + //return; +} + +static inline uint64 __u64min(uint64 x, uint64 y) { + return x < y ? x : y; +} + + +int fat32_create_file(struct tagFSTool *fs, FSHandle dir, FileInfo *info, FSHandle *handle) { + FAT32Tool *fat = ((FAT32Tool*)fs); + CHECK_FS + + int num = fat->sectors_per_cluster * 0x200 / 0x20; //单个簇内目录项个数 + + uint64 current_cluster; + if(dir != FSTOOL_INVALID_HANDLE) { + current_cluster = HANDLE_CLUSTER(dir); + fs->io.read_lba(cluster2lba(fat, current_cluster), cluster2lba(fat, current_cluster) + fat->sectors_per_cluster - 1, + fat->cluster_buffer); + uint64 idx = HANDLE_OFFSET(dir); + FAT32FileItem *items = (FAT32FileItem*) fat->cluster_buffer; + if(idx >= num || idx < 0) return ERROR_TFS_INVALID_HANDLE; + if(!(items[idx].attribute & 0x10)) { //不是目录项 + return ERROR_TFS_INVALID_HANDLE; + } + current_cluster = items[idx].first_cluster_low | (items[idx].first_cluster_hight << 16); + } else { + current_cluster = fat->root_dir_cluster; + } + + { + fs->io.read_lba(cluster2lba(fat, current_cluster), cluster2lba(fat, current_cluster) + fat->sectors_per_cluster - 1, fat->cluster_buffer); + FAT32FileItem *items = (FAT32FileItem *)fat->cluster_buffer; + while(1) { + int flag = 0; + + int i; + for(i = 0; i < num; i++) { + if(ITEM_AVAILABLE(items[i])) { + flag = 1; + break; + } + } + if(flag) { //找到空目录项 + uint32 free_cluster = alloc_fat_item(fat); //为新文件分配一个簇 + if(!free_cluster) + return ERROR_TFS_NO_SPACE; + int err = FileInfoToFat(info, items+i, free_cluster); + if(err) return err; + fs->io.write_lba(cluster2lba(fat, current_cluster), cluster2lba(fat, current_cluster) + fat->sectors_per_cluster - 1, fat->cluster_buffer); + if(handle) { + *handle = MAKE_CLUSTER_OFFSET_HANDLE(current_cluster, i); //文件记录占用当前簇的第i个表项 + } + if(info->is_directory) { //创建的是子目录,在所创建的目录中创建'.'和'..'的文件记录 + memset(fat->sector_buffer, 0, sizeof(fat->sector_buffer)); + items = (FAT32FileItem *)fat->sector_buffer; + memset(items, 0x20, sizeof(FAT32FileItem)); + memset(items+1, 0x20, sizeof(FAT32FileItem)); + items[0].dosname[0] = 0x2e; + items[1].dosname[0] = 0x2e; + items[1].dosname[1] = 0x2e; + items[0].attribute = 0x10; + items[1].attribute = 0x10; + fs->io.write_lba(cluster2lba(fat, free_cluster), cluster2lba(fat, free_cluster), fat->sector_buffer); + } + return STATUS_SUCCESS; + } else { + uint32 next_cluster; + set_fat_next(fat, current_cluster, &next_cluster, -1); + if(FAT32_IS_END_CLUSTAR(next_cluster)) { + uint32 free_cluster = alloc_fat_item(fat); //新开一个簇储存目录内的信息,那么下一次一定可以找得到。。。 + if(!free_cluster) return ERROR_TFS_NO_SPACE; + set_fat_next(fat, current_cluster, NULL, free_cluster); + current_cluster = free_cluster; + } else { + current_cluster = next_cluster; + } + } + } + } + + return STATUS_SUCCESS; +} //创建文件 + +int fat32_delete_file(struct tagFSTool *fs, FSHandle target) { + FAT32Tool *fat = ((FAT32Tool*)fs); + CHECK_FS + + int num = fat->sectors_per_cluster * 0x200 / 0x20; //单个簇内目录项个数 + + if(target == FSTOOL_INVALID_HANDLE) { + return ERROR_TFS_INVALID_HANDLE; + } + + uint64 current_cluster = HANDLE_CLUSTER(target); + + //进入目录所在簇,得到对应目录项 + { + fs->io.read_lba(cluster2lba(fat, current_cluster), cluster2lba(fat, current_cluster) + fat->sectors_per_cluster - 1, + fat->cluster_buffer); + uint64 idx = HANDLE_OFFSET(target); + FAT32FileItem *items = (FAT32FileItem*) fat->cluster_buffer; + if(idx >= num || idx < 0) return ERROR_TFS_INVALID_HANDLE; + items[idx].dosname[0] = 0xe5; //标记删除 + fs->io.write_lba(cluster2lba(fat, current_cluster), cluster2lba(fat, current_cluster) + fat->sectors_per_cluster - 1, + fat->cluster_buffer); + } + + return STATUS_SUCCESS; +} //删除文件 + +int fat32_query_file_info(struct tagFSTool *fs, FSHandle file, FileInfo *info) { + FAT32Tool *fat = ((FAT32Tool*)fs); + CHECK_FS + + int num = fat->sectors_per_cluster * 0x200 / 0x20; //单个簇内目录项个数 + + if(file == FSTOOL_INVALID_HANDLE) { + return ERROR_TFS_INVALID_HANDLE; + } + + uint64 current_cluster = HANDLE_CLUSTER(file); + + { + fs->io.read_lba(cluster2lba(fat, current_cluster), cluster2lba(fat, current_cluster) + fat->sectors_per_cluster - 1, + fat->cluster_buffer); + uint64 idx = HANDLE_OFFSET(file); + FAT32FileItem *items = (FAT32FileItem*) fat->cluster_buffer; + if(idx >= num || idx < 0) return ERROR_TFS_INVALID_HANDLE; + FileItemToFileInfo(fat, &items[idx], info); + } + + return STATUS_SUCCESS; +} + +FSHandle fat32_enum_dir(struct tagFSTool *fs, FSHandle dir, FSHandle last, FileInfo *info){ + FAT32Tool *fat = ((FAT32Tool*)fs); + if(!fat->is_valid_fat32) + return 0; + + int num = fat->sectors_per_cluster * 0x200 / 0x20; //单个簇内目录项个数 + uint32 cluster; + uint32 offset; + + if(FSTOOL_INVALID_HANDLE == last) { //第一次 + if(dir != FSTOOL_INVALID_HANDLE) { + uint64 current_cluster = dir ? HANDLE_CLUSTER(dir) : fat->root_dir_cluster; + fs->io.read_lba(cluster2lba(fat, current_cluster), cluster2lba(fat, current_cluster) + fat->sectors_per_cluster - 1, + fat->cluster_buffer); + uint64 idx = HANDLE_OFFSET(dir); + FAT32FileItem *items = (FAT32FileItem*) fat->cluster_buffer; + if(idx >= num || idx < 0) return ERROR_TFS_INVALID_HANDLE; + if(!(items[idx].attribute & 0x10)) //不是目录项 + return FSTOOL_INVALID_HANDLE; + + current_cluster = items[idx].first_cluster_low | (items[idx].first_cluster_hight << 16); + cluster = current_cluster; + offset = 0; + } else { + cluster = fat->root_dir_cluster; + offset = 0; + } + } else { //不是第一次,接着上次的Handle(last)往后 + cluster = HANDLE_CLUSTER(last); + offset = HANDLE_OFFSET(last) + 1; + + if(offset == num) { //跳到指向的下一块cluster + uint32 next_cluster; + set_fat_next(fat, cluster, &next_cluster, -1); + cluster = next_cluster; + if(FAT32_IS_END_CLUSTAR(cluster)) { //到目录项最后一个簇了 + return FSTOOL_INVALID_HANDLE; + } + offset = 0; + } + } + if(offset < 0 || offset >= num) + return FSTOOL_INVALID_HANDLE; + + //判断是否到末尾 + fs->io.read_lba(cluster2lba(fat, cluster), cluster2lba(fat, cluster) + fat->sectors_per_cluster - 1, + fat->cluster_buffer); + FAT32FileItem *items = (FAT32FileItem *)fat->cluster_buffer; + if(items[offset].dosname[0] != 0xe5 && items[offset].attribute) { //有效 + //返回指向它的句柄 + if(info) { + FileItemToFileInfo(fat, items + offset, info); + } + return MAKE_CLUSTER_OFFSET_HANDLE(cluster, offset); //返回指向下一个文件的句柄 + } else { //无效 + return FSTOOL_INVALID_HANDLE; + } +} //列举目录dir内文件(包括子目录),第一次last为NULL + +uint64 fat32_fread(struct tagFSTool *fs, FSHandle file, const void *buffer, uint64 buffer_size, FSHandle *offset_handle) { + FAT32Tool *fat = ((FAT32Tool*)fs); + if(!fat->is_valid_fat32) + return 0; + + if(file == FSTOOL_INVALID_HANDLE) + return 0; + //复制粘贴过来的呀 + uint64 file_size; + uint32 cluster, foffset; + { + const int num = fat->sectors_per_cluster * 0x200 / 0x20; //单个簇内目录项个数 + cluster = HANDLE_CLUSTER(file); + fs->io.read_lba(cluster2lba(fat, cluster), cluster2lba(fat, cluster) + fat->sectors_per_cluster - 1, + fat->cluster_buffer); + uint64 idx = HANDLE_OFFSET(file); + FAT32FileItem *items = (FAT32FileItem*) fat->cluster_buffer; + if(idx >= num || idx < 0) return ERROR_TFS_INVALID_HANDLE; + + file_size = items[idx].file_size_in_byte; + cluster = items[idx].first_cluster_low | (items[idx].first_cluster_hight << 16); + foffset = 0; + } + + const uint32 cluster_size = fat->sectors_per_cluster * 0x200; + if(*offset_handle) { //从偏移位置继续 + cluster = HANDLE_CLUSTER(*offset_handle); + foffset = HANDLE_OFFSET(*offset_handle); + } + + uint32 offset = foffset % cluster_size; //这个offset是簇内偏移量 + uint64 buffer_offset = 0; //buffer_offset同时也等于已读取的字节数 + int is_new = 0; //当前簇是整块的簇的标记 + while(buffer_offset < buffer_size && foffset < file_size) { + + uint64 read_size = 0; //本次读取的大小 + + if(!is_new) { + read_size = __u64min(buffer_size - buffer_offset, cluster_size - offset); //min(剩余数据量, 簇剩余空间) + read_size = __u64min(read_size, file_size - foffset); //再与文件剩余字节数比较 + } else { //整块的簇,直接从头开始读 + read_size = __u64min(cluster_size, buffer_size - buffer_offset); + read_size = __u64min(read_size, file_size - foffset); + } + + fs->io.read_lba(cluster2lba(fat, cluster), cluster2lba(fat, cluster) + fat->sectors_per_cluster - 1, + fat->cluster_buffer); + memcpy((char*)buffer + buffer_offset, &fat->cluster_buffer[offset], read_size); + offset = (uint32)(offset + read_size) % cluster_size; + buffer_offset += read_size; + + if(buffer_offset >= buffer_size || foffset >= file_size) + break; + if(!offset) { //找下一块簇 + uint32 next_cluster; + set_fat_next(fat, cluster, &next_cluster, -1); + if(FAT32_IS_END_CLUSTAR(next_cluster)) { //往后没有了 + break; + } else { + cluster = next_cluster; + } + } + } + *offset_handle = MAKE_CLUSTER_OFFSET_HANDLE(cluster, foffset + buffer_offset); + return buffer_offset; +} + +//offset_handle组成: +//簇号和相对于文件第0个字节的偏移量。 +uint64 fat32_fwrite(struct tagFSTool *fs, FSHandle file, const void *data, uint64 data_size, FSHandle *offset_handle) { + FAT32Tool *fat = ((FAT32Tool*)fs); + if(!fat->is_valid_fat32) + return 0; + if(file == FSTOOL_INVALID_HANDLE) + return 0; + + //复制粘贴过来的呀 + uint64 file_size; + uint32 cluster, foffset; + { + const int num = fat->sectors_per_cluster * 0x200 / 0x20; //单个簇内目录项个数 + cluster = HANDLE_CLUSTER(file); + fs->io.read_lba(cluster2lba(fat, cluster), cluster2lba(fat, cluster) + fat->sectors_per_cluster - 1, + fat->cluster_buffer); + uint64 idx = HANDLE_OFFSET(file); + FAT32FileItem *items = (FAT32FileItem*) fat->cluster_buffer; + if(idx >= num || idx < 0) return ERROR_TFS_INVALID_HANDLE; + + file_size = items[idx].file_size_in_byte; + cluster = items[idx].first_cluster_low | (items[idx].first_cluster_hight << 16); + foffset = 0; + } + + const uint32 cluster_size = fat->sectors_per_cluster * 0x200; + if(*offset_handle) { //从偏移位置继续 + cluster = HANDLE_CLUSTER(*offset_handle); + foffset = HANDLE_OFFSET(*offset_handle); + } + + uint32 offset = foffset % cluster_size; //这个offset是簇内偏移量 + uint64 buffer_offset = 0; //buffer_offset同时也等于已写入的字节数 + int is_new = 0; //当前簇是新开的簇的标记 + while(buffer_offset < data_size) { + + //int is_last = data_size - buffer_offset <= cluster_size; //当前簇是要写入的最后一块的标记 + uint64 write_size = 0; //本次写入的大小 + + if(!is_new) { //先尽量把这个簇写满 + fs->io.read_lba(cluster2lba(fat, cluster), cluster2lba(fat ,cluster) + fat->sectors_per_cluster - 1, + fat->cluster_buffer); + write_size = __u64min(data_size - buffer_offset, cluster_size - offset); //min(剩余数据量, 簇剩余空间) + memcpy(&fat->cluster_buffer[offset], (char*)data + buffer_offset, write_size); + } else { //新的簇,直接从头开始写 + write_size = __u64min(cluster_size, data_size - buffer_offset); + memcpy(fat->cluster_buffer, (char*)data + buffer_offset, write_size); + } + + offset = (uint32)(offset + write_size) % cluster_size; + fs->io.write_lba(cluster2lba(fat, cluster), cluster2lba(fat, cluster) + fat->sectors_per_cluster - 1, + fat->cluster_buffer); + buffer_offset += write_size; + + if(buffer_offset >= data_size) + break; + + if(!offset && foffset >= file_size) { //新开块 + uint32 new_cluster = alloc_fat_item(fat); + if(!new_cluster) + break; + set_fat_next(fat, cluster, NULL, new_cluster); + cluster = new_cluster; + is_new = 1; + } + } + //重算文件大小 + uint32 add_bytes = data_size - (file_size - foffset); + file_size += add_bytes; + { + uint32 tmp = HANDLE_CLUSTER(file), idx = HANDLE_OFFSET(file); + fs->io.read_lba(cluster2lba(fat, tmp), cluster2lba(fat, tmp) + fat->sectors_per_cluster - 1, + fat->cluster_buffer); + FAT32FileItem *items = (FAT32FileItem*)fat->cluster_buffer; + items[idx].file_size_in_byte = file_size; + fs->io.write_lba(cluster2lba(fat, tmp), cluster2lba(fat, tmp) + fat->sectors_per_cluster - 1, + fat->cluster_buffer); + } + + *offset_handle = MAKE_CLUSTER_OFFSET_HANDLE(cluster, foffset + buffer_offset); + return buffer_offset; +} + +int fat32_fseek(struct tagFSTool *fs, FSHandle file, uint64 offset, FSHandle *offset_handle) { + FAT32Tool *fat = ((FAT32Tool*)fs); + CHECK_FS + + + + return ERROR_TFS_NO_IMPLEMENT; +} + + +//主要是同步fsinfo +int fat32_sync_information(struct tagFSTool *fs) { + FAT32Tool *fat = ((FAT32Tool*)fs); + fat->fs.io.read_lba(fs->start_lba, fs->start_lba, fat->sector_buffer); + FAT32Header *header = (FAT32Header *)fat->sector_buffer; + fat->fs.io.write_lba(fs->start_lba + header->fsinfo, fs->start_lba + header->fsinfo, &fat->fsinfo); + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/src/fs/fat32.h b/src/fs/fat32.h new file mode 100644 index 0000000..a5711f8 --- /dev/null +++ b/src/fs/fat32.h @@ -0,0 +1,179 @@ +// 注意,暂时不支持长文件名 + + +#ifndef FAT32_H +#define FAT32_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "tfstools.h" + +#ifdef _MSC_VER +#pragma pack(push, 1) +struct tagFAT32Header { +#else +struct __attribute__((packed)) tagFAT32Header { +#endif + uint8 jmp[3]; //0x00 - 0x02 跳转指令 + uint8 OEM[8]; //0x03 - 0x0a OEM,工具创建Fat32文件系统时会写入"tfstool\0" + uint16 bytes_per_sector; //0x0b - 0x0c 每个lba(sector)字节数,通常都是512,即便一些设备的单个扇区大小实际上不是512,也会向软件层兼容512 + uint8 sectors_per_clust; //0x0d 每个簇的的扇区数 + uint16 num_reserved; //0x0e - 0x0f 第一个FAT表前面的保留扇区的数目 + uint8 num_fat; //0x10 FAT个数(一般来说FAT32是2个) + uint16 num_root_entries; //0x11 - 0x12 根目录条目个数最大值,FAT32不使用,为0 + uint16 num_sectors16; //0x13 - 0x14 总扇区数(如果是0使用num_sectors, tfstools总会使用num_sectors + uint8 material; //0x15 介质描述,由于使用lba寻址这里实际上没什么用,固定0xF8 + uint16 sectors_per_fat16; //0x16 - 0x17 每个FAT的扇区数(for FAT16.FAT32不使用) + uint32 zeros0; //0x18 - 0x1b C/H/S模式使用的信息,无用 + uint32 sectors_hidden; //0x1c - 0x1f 隐藏扇区 + uint32 num_sectors; //0x20 - 0x23 总扇区数 + uint32 sectors_per_fat32; //0x24 - 0x27 每个FAT扇区数(for FAT32) + uint16 flags; //0x28 - 0x29 flags + uint16 version; //0x2a - 0x2b 版本号 + uint32 root_dir_start; //0x2c - 0x2f 根目录起始簇号,一般为2 + uint16 fsinfo; //0x30 - 0x31 fsinfo扇区 + uint16 backup; //0x32 - 0x33 引导扇区备份 + uint8 reserved[12]; //0x34 - 0x3f FAT32保留 + uint8 device_code; //0x40 设备代号,tfstools将使用0x80(主硬盘) + uint8 zeros4; //0x41 未使用 + uint8 signature; //0x42 标记? + uint32 partition_index; //0x43 - 0x46 卷序号 + uint8 partition_label[11]; //0x47 - 0x51 卷标 + uint8 fat32[8]; //0x52 - 0x59 "FAT32" + uint8 code[420]; //0x5a -0x1fd 引导代码 + uint16 aa55; //0x1fe-0x1ff 0xaa55 +}; +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +typedef struct tagFAT32Header FAT32Header; + +typedef char __tfstools_check_fat32header_512_bytes[sizeof(FAT32Header) == 512 ? 1:-1]; + +//FAT32的FSInfo信息 +#ifdef _MSC_VER +#pragma pack(push, 1) +struct tagFAT32Info { +#else +struct __attribute__((packed)) tagFAT32Info { +#endif + unsigned int x41615252; //固定的0x41615252 + char unused[480]; //未使用 + unsigned int x61417272; //固定的0x61417272 + unsigned int free_clusters; //空闲簇的数量 + unsigned int next_free_cluster; //下一个空闲簇的簇号 + char unused2[14]; //未使用 + unsigned short aa55; //结束标志,固定的0xaa55; +}; +#ifdef _MSC_VER +#pragma pack(pop) +#endif +typedef char __tfstools_check_fat32info_512bytes[sizeof(struct tagFAT32Info) == 512 ? 1 : -1]; +typedef struct tagFAT32Info FAT32Info; + +typedef struct tagFAT32Tool { + FSTool fs; + //fat相关: + uint64 fat_lba; //主FAT表的位置 + uint32 num_fat; //个数 + uint32 sectors_per_fat; //每个fat表占的lba数 + uint32 sectors_per_cluster; //每个簇占用的lba数 + uint32 root_dir_cluster; + int is_valid_fat32; + + //注意!!!如果在一个函数里修改了buffer的内容,调用其它可能会修改buffer内容的函数时要特别注意!!! + char cluster_buffer[8 * 512]; //临时使用的簇缓冲区,不支持大于8kb的簇 + char sector_buffer[512]; + FAT32Info fsinfo; +}FAT32Tool; + +int fat32_fstool_initialize(FAT32Tool *fat, FSIO io, uint64 start_lba, uint64 end_lba); +int fat32_makefs(struct tagFSTool *fs); //创建无文件的文件系统 +int fat32_create_file(struct tagFSTool *fs, FSHandle dir, FileInfo *info, FSHandle *handle); //创建文件 +int fat32_delete_file(struct tagFSTool *fs, FSHandle target); //删除文件 +FSHandle fat32_enum_dir(struct tagFSTool *fs, FSHandle dir, FSHandle last, FileInfo *info); //列举目录dir内文件(包括子目录),第一次last为NULL + +int fat32_query_file_info(struct tagFSTool *fs, FSHandle file, FileInfo *info); //查询文件信息 + +uint64 fat32_fread(struct tagFSTool *fs, FSHandle file, const void *buffer, uint64 buffer_size, FSHandle *offset_handle); +uint64 fat32_fwrite(struct tagFSTool *fs, FSHandle file, const void *data, uint64 data_size, FSHandle *offset_handle); + +int fat32_fseek(struct tagFSTool *fs, FSHandle file, uint64 offset, FSHandle *offset_handle); + +int fat32_sync_information(struct tagFSTool *fs); + +#define FAT32_FREE_CLUSTER 0 +#define FAT32_RESERVED_CLUSTER 1 +#define FAT32_RESERVED_CLUSTER_ID_START 0x0ffffff0 +#define FAT32_RESERVED_CLUSTER_ID_END 0x0ffffff6 +#define FAT32_BAD_CLUSTER 0x0ffffff7 +#define FAT32_FILE_END 0x0fffffff +#define FAT32_IS_END_CLUSTAR(c) (c >= 0x0ffffff8 && c <= 0x0fffffff) + +//FAT32目录表表项结构 +#ifdef _MSC_VER +#pragma pack(push, 1) +struct tagFAT32FileItem { +#else +struct __attribute__((packed)) tagFAT32FileItem { +#endif + //0x00-0x07 dos文件名 + //dosname第一个字节的特殊值: + //0x00 这个条目有用并且后面没有被占用的条目(wiki上是这么说的。。。) + //0x05 转义为字符"\xe5",与下面的0xe5不同 + //0x2e . 或者.. (指向本目录自己或上一级目录) + //0xe5 已被删除。将这个标记替换掉可能能够恢复文件 + unsigned char dosname[8]; + + char dosname_ext[3]; //0x08-0x0a dos文件名扩展名部分 + + // 0x0b 属性: + // mask 含义 + // (1<<0) 只读 + // (1<<1) 隐藏 + // (1<<2) 系统 + // (1<<3) 卷标 + // (1<<4) 子目录项 + // (1<<5) 文件 + // (1<<6) 设备 + // (1<<7) 未使用 + //如果attribute值为0x0f表示是长文件条目 + unsigned char attribute; + unsigned char reserved_for_NT; //0x0c NT保留? + unsigned char create_time_in2s; //0x0d 创建时间的2s部分,单位为10ms,有意义的数值从0-199。这个设计真的很智障 + + //0x0e - 0x0f 创建时间的时分秒,秒数*2+偏移0x0d处算出的秒数才是实际的时间 + // bits 15-11 小时 + // bits 10-5 分钟 + // bits 4-0 秒/2 + unsigned short create_time_hmsdiv2; + + //0x10 - 0x11 创建时间的年月日 + // bits 15-9 年,最大值为127,这里的数值加上1980为实际的年份 + // bits 8-5 月,这里的数值就是月份 + // bits 4-0 日 (1-31) + unsigned short create_time_ymd; + + + unsigned short access_time_ymd; //0x12 - 0x13 最近访问日期,格式同create_time_ymd + unsigned short first_cluster_hight; //0x14 - 0x15 文件内容的第一个簇的编号的高两字节 + unsigned short modify_time_hmsdiv2; //0x16 - 0x17 最后修改的时间(时分秒),格式同create_time_hmsdiv2 + unsigned short modify_time_ymd; //0x18 - 0x19 最后修改时间的年月日 + unsigned short first_cluster_low; //0x1a - 0x1b 文件内容的第一个簇的编号的低两字节 + unsigned int file_size_in_byte; //0x1c - 0x1f 文件大小,字节数 +}; +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +typedef struct tagFAT32FileItem FAT32FileItem; + + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/fs/gptpart.c b/src/fs/gptpart.c new file mode 100644 index 0000000..3fab2b9 --- /dev/null +++ b/src/fs/gptpart.c @@ -0,0 +1,306 @@ +#include "gptpart.h" + +unsigned int crc32(const void *pdata, unsigned int size) +{ + const unsigned char *data = (const unsigned char *)pdata; + unsigned int crc = 0xffffffffu; + for (unsigned int i = 0; i < size; i++) + { + crc = crc ^ data[i]; + for (int j = 8; j > 0; j--) + { + crc = (crc >> 1) ^ (0xEDB88320U & ((crc & 1) ? 0xFFFFFFFF : 0)); + } + } + return ~crc; +} + +int gpt_is_parted(GPTItem *item) { + return item->start_lba <= item->end_lba && memcmp(item->type_guid, GUID_EMPTY, sizeof(GPTGUID)); +} + +static uint32 _SEED_ = 32; //随机数种子 +void RandomGUID(GPTGUID *guid) { + uint32 magic = ((uint64)guid); //选取一个magic,指针先转换成uint64再赋给magic避免某些编译器报错 + uint32 offset = 0x12345; + for(int i = 0; i < 16; i++) { + (*guid)[i] = (_SEED_ = (_SEED_ * magic + offset) % 255); + }; +} + +int gpt_part_tool_initialize(GPTPartTool *pt, FSIO io) { + pt->pt.io = io; + + pt->pt.create_part = gpt_create_part; + pt->pt.delete_part = gpt_delete_part; + pt->pt.enum_part = gpt_enum_part; + pt->pt.get_part_count = gpt_get_part_count; + pt->pt.query_part_info = gpt_query_part_info; + pt->pt.sync_with_disk = gpt_sync_with_disk; + pt->pt.make_part_table = gpt_make_part_table; + memset(&pt->header, 0, sizeof(GPTHeader)); + memset(pt->items, 0, sizeof(pt->items)); + pt->pt.io.read_lba(1, 1, &pt->header); + if(memcmp(pt->header.signature, "EFI PART", 8)) { + pt->is_valid_gpt_disk = 0; + } else pt->is_valid_gpt_disk = 1; + + if(!pt->header.gpt_item_first_lba) //for some buggy gpt header... + pt->header.gpt_item_first_lba = 2; + + pt->num_items = pt->header.gpt_part_count > 128 ? 128 : pt->header.gpt_part_count; + size_t read_size = (pt->num_items * sizeof(GPTItem)); + size_t read_count = read_size % 512 ? (read_size / 512 + 1) : read_size / 512; + + pt->pt.io.read_lba(pt->header.gpt_item_first_lba, pt->header.gpt_item_first_lba + read_count - 1, pt->items); + + if(pt->header.backup_lba) { //有备份表 + pt->pt.io.read_lba(pt->header.backup_lba, pt->header.backup_lba, &pt->header_backup); + } else { + memset(&pt->header_backup, 0, sizeof(GPTHeader)); + } + + return STATUS_SUCCESS; +} + +#define CHECK_GPT_VALID if(!gpt->is_valid_gpt_disk) {return ERROR_TFS_INVALID_DISK;} + +//内部使用,重做分区表crc32校验 +void gpt_remake_crc32(GPTPartTool *gpt) { + gpt->header.gpt_part_crc32 = crc32(gpt->items, sizeof(gpt->items)); + gpt->header.header_crc32 = 0; + unsigned int crc = crc32(&gpt->header, 92); + gpt->header.header_crc32 = crc; + + if(gpt->header.backup_lba) { //备份表 + memcpy(&gpt->header_backup, &gpt->header, sizeof(GPTHeader)); + gpt->header_backup.header_lba = gpt->header.backup_lba; + gpt->header_backup.backup_lba = gpt->header.header_lba; + gpt->header_backup.header_crc32 = 0; + crc = crc32(&gpt->header_backup, 92); + gpt->header_backup.header_crc32 = crc; + } +} + +int gpt_make_part_table(struct tagPartTool *pt, uint64 disk_size_in_byte) { + GPTPartTool *gpt = (GPTPartTool *)pt; + // + uint64 size_in_byte = disk_size_in_byte; + uint64 last_lba = size_in_byte / 512 - 2; + + uint64 cur_lba = 0; + { //mbr + char mbr[512]; + memset(mbr, 0, sizeof(mbr)); + + mbr[0x1c0] = 0x01; //fixed + mbr[0x1c1] = 0x00; + mbr[0x1c2] = 0xee; //GPT signature + mbr[0x1c3] = 0xfe; //-| + mbr[0x1c4] = 0xff; // fixed + mbr[0x1c5] = 0xff; // + mbr[0x1c6] = 0x01; //-| + mbr[0x1c7] = mbr[0x1c8] = mbr[0x1c9] = 0; + unsigned long long selectors = (size_in_byte / 512 - 1) > 0xffffffffu ? 0xffffffffu : (size_in_byte / 512 - 1); + *((unsigned int*)&mbr[0x1ca]) = (unsigned int)selectors; + + mbr[0x1fe] = 0x55; + mbr[0x1ff] = 0xaa; + gpt->pt.io.write_lba(cur_lba, cur_lba, mbr); + cur_lba++; + } + + { //gpt tables + GPTHeader gh; + GPTItem items[128]; + memset(&gh, 0, sizeof(gh)); + memset(items, 0, sizeof(items)); + memcpy(gh.signature, "EFI PART", 8); + gh.version = 0x00010000; + gh.sizeof_header = 92; + gh.header_crc32 = 0; + gh.reserved = 0; + gh.header_lba = 1; + gh.backup_lba = last_lba + 1; + //gh.backup_lba = (size_in_byte / 512 - 1); + gh.first_partable_lba = 2048; + gh.last_partable_lba = last_lba; + RandomGUID(&gh.disk_guid); + gh.gpt_item_first_lba = 2; + gh.gpt_part_count = 128; + gh.gpt_item_size = 128; + + //see also -->gpt_remake_crc32 + gh.gpt_part_crc32 = crc32(items, sizeof(items)); + unsigned int header_crc32 = crc32(&gh, 92); + gh.header_crc32 = header_crc32; + gpt->pt.io.write_lba(cur_lba, cur_lba, &gh); + cur_lba++; + + char zeros[512] = {0}; + for(int i = 2; i < 34; i++) { //空表项 + gpt->pt.io.write_lba(cur_lba, cur_lba, zeros); + cur_lba++; + } + + for(int i = 34; i <= last_lba; i++) { //数据区填0 + gpt->pt.io.write_lba(cur_lba, cur_lba, zeros); + cur_lba++; + } + + //写入备份表 + gh.header_lba = gh.backup_lba; + gh.backup_lba = 1; + gh.header_crc32 = 0; + header_crc32 = crc32(&gh, 92); + gh.header_crc32 = header_crc32; + gpt->pt.io.write_lba(cur_lba, cur_lba, &gh); + cur_lba++; + } + gpt->is_valid_gpt_disk = 1; //设为合法的gpt磁盘 + return STATUS_SUCCESS; +} + +unsigned int gpt_get_part_count(PartTool *pt) { + GPTPartTool *gpt = (GPTPartTool *)pt; + CHECK_GPT_VALID + return (gpt)->num_items; +} + +int gpt_create_part(PartTool *pt, PartInfo *info,FSHandle *target) { + GPTPartTool *gpt = (GPTPartTool *)pt; + CHECK_GPT_VALID + if(info->start_lba > info->end_lba) + return ERROR_TFS_INVALID_ARGUMENT; + + if(info->start_lba < gpt->header.first_partable_lba || info->end_lba > gpt->header.last_partable_lba) + return ERROR_TFS_NO_SPACE; + + GPTItem *item = NULL; + for(int i = 0; i < 128; i++) { + if(gpt_is_parted(&gpt->items[i])) { //与已有的分区冲突 + GPTItem *p = &gpt->items[i]; + if(!(info->start_lba > p->end_lba || info->end_lba < p->start_lba)) { + return ERROR_TFS_CONFLICT; + } + } else { + if(!item) { + item = &gpt->items[i]; + } + } + } + if(item) { + /* + if(info->type >= PART_UNKNOWN) + return ERROR_TFS_INVALID_ARGUMENT; + */ + + item->attributes = info->attribute; + memcpy(item->type_guid, info->type_guid, sizeof(GPTGUID)); + memcpy(item->guid, info->guid, sizeof(GPTGUID)); + //int is_le = check_is_LE(); //GPT分区表label是规定的小端序的 + for(int i = 0; i < 36; i++) { + item->label[i*2] = info->label[i]; + } + item->label[71] = 0; + + item->start_lba = info->start_lba; + item->end_lba = info->end_lba; + + gpt_remake_crc32(gpt); + if(target) { + *target = (FSHandle)item; + } + return STATUS_SUCCESS; + }else { + return ERROR_TFS_NO_SPACE; + } + + return STATUS_SUCCESS; +} +int gpt_delete_part(PartTool *pt, FSHandle target) { + GPTPartTool *gpt = (GPTPartTool *)pt; + CHECK_GPT_VALID + GPTItem *item = (GPTItem *)target; + + //不是从管理工具中得到的句柄 + if(item < gpt->items || item >= (gpt->items + gpt->num_items)) + return ERROR_TFS_INVALID_HANDLE; + + memset(item, 0, sizeof(GPTItem)); + gpt_remake_crc32(gpt); + + return STATUS_SUCCESS; +} + +FSHandle gpt_enum_part(PartTool *pt, FSHandle last) { + GPTPartTool *gpt = (GPTPartTool *)pt; +// CHECK_GPT_VALID + + if(!gpt->is_valid_gpt_disk) + return 0; + + GPTItem *last_item = (GPTItem *)last; + + for(GPTItem *p = last_item ? (last_item + 1) : gpt->items; p < (gpt->items + gpt->num_items); p++) { + if(gpt_is_parted(p)) { + return (FSHandle)p; + } + } + + return 0; +} + +int gpt_query_part_info(PartTool *pt, FSHandle target, PartInfo *info) { + GPTPartTool *gpt = (GPTPartTool *)pt; + CHECK_GPT_VALID + + if(target) { + GPTItem *item = (GPTItem *)target; + info->start_lba = item->start_lba; + info->end_lba = item->end_lba; + memcpy(info->guid, item->guid, sizeof(GPTGUID)); + memcpy(info->type_guid, item->type_guid, sizeof(GPTGUID)); + for(int i = 0; i < 36; i++) { + info->label[i] = item->label[i*2]; + } + info->label[35] = 0; + for(int i = 0; i < PART_UNKNOWN; i++) { + if(!memcmp(PART_TYPE_GUID(i), item->type_guid, sizeof(GPTGUID))) { + info->type = PART_EMPTY + i; + return STATUS_SUCCESS; + } + } + info->type = PART_UNKNOWN; + return STATUS_SUCCESS; + } else { + return STATUS_FAILED; + } + + return STATUS_SUCCESS; +} + + + +int gpt_sync_with_disk(struct tagPartTool *pt) { + GPTPartTool *gpt = ((GPTPartTool *)pt); + CHECK_GPT_VALID + + gpt_remake_crc32(gpt); + + //主表表头 + gpt->pt.io.write_lba(1, 1, &gpt->header); + //主表表项 + gpt->num_items = gpt->header.gpt_part_count > 128 ? 128 : gpt->header.gpt_part_count; + size_t read_size = (gpt->num_items * sizeof(GPTItem)); + size_t read_count = read_size % 512 ? (read_size / 512 + 1) : read_size / 512; + gpt->pt.io.write_lba(gpt->header.gpt_item_first_lba, gpt->header.gpt_item_first_lba + read_count - 1, gpt->items); + + //备份表 + if(gpt->header.backup_lba) { + gpt->pt.io.write_lba(gpt->header.backup_lba, gpt->header.backup_lba, &gpt->header_backup); + } + return STATUS_SUCCESS; +} + +#undef CHECK_GPT_VALID diff --git a/src/fs/gptpart.h b/src/fs/gptpart.h new file mode 100644 index 0000000..2c152f0 --- /dev/null +++ b/src/fs/gptpart.h @@ -0,0 +1,141 @@ +#ifndef GPT_PART_H +#define GPT_PART_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "tfstools.h" + +typedef unsigned char GPTGUID[16]; + +typedef struct tagGPTHeader { + char signature[8]; // "EFI PART" + unsigned int version; + unsigned int sizeof_header; + unsigned int header_crc32; //表头的crc32校验 (暂时不用) + unsigned int reserved; + unsigned long long header_lba; //主gpt分区表表头lba + unsigned long long backup_lba; //备份gpt分区表表头lba + unsigned long long first_partable_lba; //第一个可以用分区的lba + unsigned long long last_partable_lba; //最后一个可用于分区的lba(备份表lba-1) + GPTGUID disk_guid; + unsigned long long gpt_item_first_lba; //分区表项第一项的lba(通常是2) + unsigned int gpt_part_count; //分区数量 + unsigned int gpt_item_size; //一个分区表项的大小 + unsigned int gpt_part_crc32; //分区表项的crc32校验(暂时不用) + unsigned char zeros[420]; //zeros +}GPTHeader; + +typedef char __check_gpt_header_512_bytes[sizeof(GPTHeader) == 512 ? 1 : -1]; + +typedef struct tagGPTItem { + GPTGUID type_guid; //分区类型guid + GPTGUID guid; //分区guid + unsigned long long start_lba; //起始lba + unsigned long long end_lba; //末尾lba + unsigned long long attributes; //属性 + union { + char label[72]; //分区名 + short label_wchar[36]; //宽字节版 + }; +}GPTItem; + +typedef char __check_gpt_item_128_bytes[sizeof(GPTItem) == 128 ? 1 : -1]; + +static const GPTGUID GUID_EMPTY = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; +static const GPTGUID GUID_EFISYSTEM = {0x28, 0x73, 0x2a, 0xc1, 0x1f, 0xf8, 0xd2, 0x11, 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b}; +static const GPTGUID GUID_MSRESERVE = {0x16, 0xe3, 0xc9, 0xe3, 0x5c, 0x0b, 0xb8, 0x4d, 0x81, 0x7d, 0xf9, 0x2d, 0xf0, 0x02, 0x15, 0xae}; +static const GPTGUID GUID_MSBASICDATA = {0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44, 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7}; +//可能一些linux爱好者看到了会生气,可微软数据分区guid和linux数据分区guid真的是一样的呢 +#define GUID_LINUXDATA GUID_MSBASICDATA +static const GPTGUID GUID_LINUXSWAP = {0x6d, 0xfd, 0x57, 0x06, 0xab, 0xa4, 0xc4, 0x43, 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f}; +static const GPTGUID GUID_MBR = {0x41, 0xee, 0x4d, 0x02, 0xe7, 0x33, 0xd3, 0x11, 0x9d, 0x69, 0x00, 0x08, 0xc7, 0x81, 0xf3, 0x9f}; +static const GPTGUID GUID_BIOSBOOT = {0x48, 0x61, 0x68, 0x21, 0x49, 0x64, 0x6f, 0x6e, 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49}; +static const GPTGUID GUID_WINDOWS_RECOVERY = {0xa4, 0xbb, 0x94, 0xde, 0xd1, 0x06, 0x40, 0x4d, 0xa1, 0x6a, 0xbf, 0xd5, 0x01, 0x79, 0xd6, 0xac}; +static const GPTGUID GUID_APPLE_HFS = {0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11, 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac}; +static const GPTGUID GUID_APPLE_UFS = {0x00, 0x53, 0x46, 0x55, 0x00, 0x00, 0xaa, 0x11, 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac}; + +//系统分区 +#define PART_ATTRIBUTE_SYSTEM (1<<0) + +//EFI分区 +#define PART_ATTRIBUTE_EFI_HIDE (1<<1) + +//传统BIOS可引导分区 +#define PART_ATTRIBUTE_BIOSBOOT (1<<2) + +//只读 +#define PART_ATTRIBUTE_READONLY (1ull<<60) + +//隐藏 +#define PART_ATTRIBUTE_HIDE (1ull<<62) + +//不自动挂载 +#define PART_ATTRIBUTE_NO_AUTO_MOUNT (1ull<<63) + +#define PART_EMPTY 0 +#define PART_EFISYSTEM 1 +#define PART_MSRESERVE 2 +#define PART_MSBASICDATA 3 +#define PART_LINUXDATA PART_MSBASICDATA +#define PART_LINUX_SWAP 4 +#define PART_MBR 5 +#define PART_BIOSBOOT 6 +#define PART_WINDOWS_RECOVERY 7 +#define PART_APPLE_HFS 8 +#define PART_APPLE_UFS 9 +#define PART_UNKNOWN 10 +static const char *PART_DESCRIPTION[] = { + "Empty", + "EFI System", + "Reserved by Mircosoft", + "Data", + "Linux Swapfile", + "MBR Partition Table", + "BIOS Boot", + "Windows Recovery Environment", + "Apple HFS/HFS+", + "Apple UFS", + "Unknown", +}; +static const GPTGUID *PART_TYPE_GUID_[] = { + &GUID_EMPTY, + &GUID_EFISYSTEM, + &GUID_MSRESERVE, + &GUID_MSBASICDATA, + &GUID_LINUXSWAP, + &GUID_MBR, + &GUID_BIOSBOOT, + &GUID_WINDOWS_RECOVERY, + &GUID_APPLE_HFS, + &GUID_APPLE_UFS, +}; +#define PART_TYPE_GUID(__i) (*(PART_TYPE_GUID_[__i])) + +typedef struct tagGPTPartTool { + PartTool pt; + GPTHeader header; + GPTHeader header_backup; //备份表 + GPTItem items[128]; + int is_valid_gpt_disk; //是否为合法的gpt磁盘的标记 + unsigned int num_items; //header中也有分区数,这里记录的是min(128, header中记录的数量) +}GPTPartTool; + +int gpt_part_tool_initialize(GPTPartTool *pt, FSIO io); +int gpt_make_part_table(struct tagPartTool *pt, uint64 disk_size_in_byte); +unsigned int gpt_get_part_count(PartTool *pt); +int gpt_create_part(PartTool *pt, PartInfo *info, FSHandle *target); +int gpt_delete_part(PartTool *pt, FSHandle target); +//int gpt_rename_part(PartTool *pt, FSHandle target, const char *new_name); +FSHandle gpt_enum_part(PartTool *pt, FSHandle last); +int gpt_query_part_info(PartTool *pt, FSHandle target, PartInfo *info); +int gpt_sync_with_disk(struct tagPartTool *pt); + +void RandomGUID(GPTGUID *guid); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/fs/taurix_fs_patch.h b/src/fs/taurix_fs_patch.h new file mode 100644 index 0000000..062787b --- /dev/null +++ b/src/fs/taurix_fs_patch.h @@ -0,0 +1,14 @@ +#ifndef TAURIX_FS_PATCH_H +#define TAURIX_FS_PATCH_H + +#include +#define memset ru_memset +#define memcpy ru_memcpy +#define strcpy ru_strcpy +#define strncmp ru_strncmp +#define strncpy ru_strncpy +#define memcmp ru_memcmp +#define strlen ru_strlen +#define strcat ru_strcat + +#endif \ No newline at end of file diff --git a/src/fs/tfstools.h b/src/fs/tfstools.h new file mode 100644 index 0000000..6a13e65 --- /dev/null +++ b/src/fs/tfstools.h @@ -0,0 +1,208 @@ +#ifndef TFSTOOLS_H +#define TFSTOOLS_H + +#ifdef __cplusplus +extern "C" { +#endif + +//Taurix 补丁: +#include "taurix_fs_patch.h" +//#define STATUS_SUCCESS 0 +//#define STATUS_FAILED 1 + +#define ERROR_TFS_START 1000 +//不合法的磁盘镜像 +#define ERROR_TFS_INVALID_DISK (ERROR_TFS_START+1) +//没有足够空间 +#define ERROR_TFS_NO_SPACE (ERROR_TFS_START+2) +//位置冲突 +#define ERROR_TFS_CONFLICT (ERROR_TFS_START+3) +//非法参数 +#define ERROR_TFS_INVALID_ARGUMENT (ERROR_TFS_START+4) +//分区/文件/目录 不存在 <大多针对删除操作> +#define ERROR_TFS_NOT_EXIST (ERROR_TFS_START+5) +//分区/文件/目录 已存在 <大多针对创建操作> +#define ERROR_TFS_ALREADY_EXIST (ERROR_TFS_START+6) +//功能未实现 +#define ERROR_TFS_NO_IMPLEMENT (ERROR_TFS_START+7) +//非法句柄 +#define ERROR_TFS_INVALID_HANDLE (ERROR_TFS_START+8) +//非法文件系统 +#define ERROR_TFS_INVALID_FS (ERROR_TFS_START+9) +//非法文件名 +#define ERROR_TFS_INVALID_FILENAME (ERROR_TFS_START+10) +//不支持的特性 +#define ERROR_TFS_UNSUPPORTED_FEATURE (ERROR_TFS_START+16) + +static const char *ERROR_TFS_STRING[] = {0, "Invalid disk", + "No enough space", + "Conflict", + "Invalid argument", + "Not exist", + "Already exist", + "Not implemented", + "Invalid handle", + "Invalid filesystem", + "Invalid filename", + "Unsupported feature"}; + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef unsigned long long uint64; + +typedef uint64 FSHandle; +typedef FSHandle FileHandle; +typedef FSHandle OffsetHandle; + +typedef struct tagFSIO { + uint64 (*read_lba)(uint64 start, uint64 end, void *buf); + uint64 (*write_lba)(uint64 start, uint64 end, void *buf); +}FSIO; + +//分区根据以0作为无效句柄的标识 +//分区工具接口 +//暂时钦点GPT分区表了所以。。 +typedef struct tagPartInfo { + char label[36]; /* 标签 */ + int type; //分区类型,GPT分区表可以根据分区guid得到 + + unsigned long long attribute; + uint64 start_lba, end_lba; + + unsigned char guid[16]; //guid + unsigned char type_guid[16]; +}PartInfo; + +typedef struct tagPartTool { + FSIO io; + int (*make_part_table)(struct tagPartTool *pt, uint64 disk_size_in_byte); //将磁盘镜像前size_in_bytes做成GPT磁盘 + unsigned int (*get_part_count)(struct tagPartTool *pt); //获得分区数(对于比如gpt分区表是固定的128),实际上没有意义的分区类型guid为空 + int (*create_part)(struct tagPartTool *pt, PartInfo *info, FSHandle *target); //(创建分区) + int (*delete_part)(struct tagPartTool *pt, FSHandle target); //删除分区 + FSHandle (*enum_part) (struct tagPartTool *pt, FSHandle last); //枚举所有分区,第一次last为NULL + int (*query_part_info)(struct tagPartTool *pt, FSHandle target, PartInfo *info); //查询分区信息 + int (*sync_with_disk) (struct tagPartTool *pt); //将分区表写入磁盘 +}PartTool; + +//文件系统接口 +typedef struct tagFileInfo { + union { //文件全名(包括扩展名等) + char name_char[512]; + short name_wchar[256]; + }; + uint64 attributes; //属性 + int is_directory; //是否为目录的标记 + + //创建时间的年月日时分秒。 + union { + struct { + short created_year; //16bits + uint8 created_month; //8bits + uint8 created_day; //8bits + uint8 created_hour; //8bits + uint8 created_minute; //8bits + uint8 created_second; //8bits + }; + uint64 created_ymdhms; + }; + + //访问时间的年月日时分秒。 + union { + struct { + short access_year; //16bits + uint8 access_month; //8bits + uint8 access_day; //8bits + uint8 access_hour; //8bits + uint8 access_minute; //8bits + uint8 access_second; //8bits + }; + uint64 access_ymdhms; + }; + + //修改时间的年月日时分秒。 + union { + struct { + short modify_year; //16bits + uint8 modify_month; //8bits + uint8 modify_day; //8bits + uint8 modify_hour; //8bits + uint8 modify_minute; //8bits + uint8 modify_second; //8bits + }; + uint64 modify_ymdhms; + }; + + uint64 file_size_in_bytes; //文件大小(bytes) + uint64 file_occupies_in_bytes; //占用储存介质的字节数 +}FileInfo; + +//普通文件 +#define FILE_ATTRIBUTE_NORMAL 0 +//只读 +#define FILE_ATTRIBUTE_READONLY (1<<0) +//隐藏 +#define FILE_ATTRIBUTE_HIDDEN (1<<1) +//设备文件 +#define FILE_ATTRIBUTE_DEVICE (1<<2) +//符号链接(软链接) +#define FILE_ATTRIBUTE_SYMBOL_LINK (1<<3) +//系统文件 +#define FILE_ATTRIBUTE_SYSTEM (1<<4) + +//小端序 +#define YMDHMS(_Y,_M,_D,_H,_MI,_S) ((_Y) | ((_M) << 16) | ((_D) << 24) | ((_H) << 32) | ((_MI) << 40) | ((_S) << 48)) + +//文件系统以-1(0xffffffffffffffffull) 作为无效句柄 +#define FSTOOL_INVALID_HANDLE 0xffffffffffffffffull +typedef struct tagFSTool { + FSIO io; + uint64 start_lba, end_lba; //起始和终止lba,可以从分区工具得到 + int (*makefs)(struct tagFSTool *fs); //创建无文件的文件系统 + + //新建/打开文件,取决于mode + //dir为目录文件句柄,如果为FSTOOL_INVALID_HANDLE则使用根目录 + //handle为传出参数,用于接收文件句柄。可以为空指针(不接收) + //返回值为错误代码(0为成功) + int (*create_file)(struct tagFSTool *fs, FileHandle dir, FileInfo *info, FileHandle *handle); + + int (*delete_file)(struct tagFSTool *fs, FileHandle target); //删除文件 + + //列举目录dir内文件(包括子目录),dir参数为FSTOOL_INVALID_HANDLE使用根目录,第一次last为FSTOOL_INVALID_HANDLE,从目录中第一个文件开始 + //如果info参数不为空指针,将会同时通过info参数返回函数所返回的文件句柄指向的文件的信息,这样做将遍历目录与查询目录下文件信息一起做了。 + //目的是为了尽量减少磁盘IO次数。 + FileHandle (*enum_dir)(struct tagFSTool *fs, FileHandle dir, FileHandle last, FileInfo *info); + + //查询单个文件的信息,file为文件句柄,*info为接收信息的结构体 + int (*query_file_info)(struct tagFSTool *fs, FileHandle file, FileInfo *info); + + //对非目录文件的读/写,模式相当于C语言的二进制模式 + //file为文件句柄,不可以是非法句柄(file传入FSTOOL_INVALID_HANDLE不表示根目录,是非法参数,不允许直接对目录文件本身读写) + //offset_handle既是传入参数又是传出参数,不可以为空指针,当文件不能一次读/写完的时候,offset_handle用于记录文件指针的偏移量。 + //*offset_handle为0时,被认为是读/写的偏移地址是文件开头,读/写后会改变*offset_handle + //返回值为实际读/写的字节数 + uint64 (*fread)(struct tagFSTool *fs, FSHandle file, const void *buffer, uint64 buffer_size, FSHandle *offset_handle); + uint64 (*fwrite)(struct tagFSTool *fs, FSHandle file, const void *data, uint64 data_size, FSHandle *offset_handle); + + //得到offset对应的offset_handle + //注意,不保证offset == *offset_handle,*offset_handle是跟具体文件系统实现有关的数值,而非实现无关的偏移量 + int (*fseek)(struct tagFSTool *fs, FSHandle file, uint64 offset, FSHandle *offset_handle); + + //同步文件系统的附加维护信息(如果有,没有的话请赋值一个空的函数) + int (*sync_information)(struct tagFSTool *fs); +}FSTool; + +#define CREATEFILE_MODE_NEW 0 +#define CREATEFILE_MODE_OPEN 1 + +inline int check_is_LE() { + union {int x; char y; }u; + u.x = 1; + return u.y == 1; +} + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/utils/utils.c b/src/utils/utils.c index 1902d7d..2f96288 100644 --- a/src/utils/utils.c +++ b/src/utils/utils.c @@ -11,12 +11,7 @@ */ void ru_dummy() {} -/* ru_sprintf - */ -int ru_sprintf(char *buf, const char *format, ...) { - //TODO: - return 0; -} +//string.h /* ru_memset */ @@ -28,18 +23,18 @@ void *ru_memset(void *base, uint8 data, size_t size) { /* ru_memcpy */ -void *ru_memcpy(void *dest, void *src, size_t size) { +void *ru_memcpy(void *dest, const void *src, size_t size) { uint8 *pdest = (uint8 *)dest, *psrc = (uint8*)src; while(size--) *pdest++ = *psrc++; return dest; } -//string.h char *ru_strcpy(char *dest, const char *src) { + char *ori_dest = dest; while(*src) *dest++ = *src++; *dest = 0; - return dest; + return ori_dest; } int ru_strlen(const char *str) { @@ -54,6 +49,39 @@ int ru_strcmp(const char *a, const char *b) { return *a - *b; } +int ru_strncmp(const char *a, const char *b, size_t size) { + while(size-- && (*a && *b) && *a == *b) + a++, b++; + return *a - *b; +} +char* ru_strncpy(char *dest, const char *src, size_t size) { + char *ori_dest = dest; + while(size-- && *src) { + *dest++ = *src++; + } + *dest = 0; + return ori_dest; +} +int ru_memcmp(const void *a, const void *b, size_t size) { + const char *pa = (const char *)a; + const char *pb = (const char *)b; + while(size--) { + char diff = *pa - *pb; + if(diff) return diff; + *pa++, *pb++; + } + return 0; +} +char *ru_strcat(char *dest, const char *src) { + char *ori_dest = dest; + + int len = ru_strlen(dest); + for(dest += len; *src; ) + *dest++ = *src++; + *dest = 0; + return ori_dest; +} + /* ru_isqrt */ uint32 ru_isqrt(uint32 x) { diff --git a/taurix-settings-gui.py b/taurix-settings-gui.py index 8472184..309fc79 100755 --- a/taurix-settings-gui.py +++ b/taurix-settings-gui.py @@ -1,4 +1,5 @@ #! python3 +# -*- coding: utf-8 -*- try: from PyQt5.QtCore import *