#include #include #include #include #include #define BS_jmpBoot_Offset 0x00 // 跳转指令偏移 #define BS_jmpBoot_Len 3 // 跳转指令长度 #define BS_OEMName_Offset 0x03 // 厂商名称偏移 #define BS_OEMName_Len 8 // 厂商名称长度 #define BPB_BytsPerSec_Offset 0x0B // 每扇区字节数偏移 #define BPB_BytsPerSec_Len 2 // 每扇区字节数长度 #define BPB_SecPerClus_Offset 0x0D // 每簇扇区数偏移 #define BPB_SecPerClus_Len 1 // 每簇扇区数长度 #define BPB_RsvdSecCnt_Offset 0x0E // 保留扇区数 (引导扇区的扇区数)偏移 #define BPB_RsvdSecCnt_Len 2 // 保留扇区数 (引导扇区的扇区数)长度 #define BPB_NumFATs_Offset 0x10 // FAT的份数偏移 #define BPB_NumFATs_Len 1 // FAT的份数长度 #define BPB_RootEntCnt_Offset 0x11 // 根目录可容纳的目录项数偏移 #define BPB_RootEntCnt_Len 2 // 根目录可容纳的目录项数长度 #define BPB_TotSec16_Offset 0x13 // 扇区总数偏移 #define BPB_TotSec16_Len 2 // 扇区总数长度 #define BPB_Media_Offset 0x15 // 介质描述符偏移 #define BPB_Media_Len 1 // 介质描述符长度 #define BPB_FATSz16_Offset 0x16 // 每个FAT表扇区数偏移 #define BPB_FATSz16_Len 2 // 每个FAT表扇区数长度 #define BPB_SecPerTrk_Offset 0x18 // 每磁道扇区数偏移 #define BPB_SecPerTrk_Len 2 // 每磁道扇区数长度 #define BPB_NumHeads_Offset 0x1A // 磁头数偏移 #define BPB_NumHeads_Len 2 // 磁头数长度 #define BPB_HiddSec_Offset 0x1C // 隐藏扇区数偏移 #define BPB_HiddSec_Len 4 // 隐藏扇区数长度 #define BPB_TotSec32_Offset 0x20 // 偏移 如果BPB_TotSec16是0,由这个值记录扇区数 #define BPB_TotSec32_Len 4 // 长度 如果BPB_TotSec16是0,由这个值记录扇区数 #define BS_DrvNum_Offset 0x24 // int 13h的驱动器号偏移 #define BS_DrvNum_Len 1 // int 13h的驱动器号长度 #define BS_Reservedl_Offset 0x25 // 偏移 未使用 #define BS_Reservedl_Len 1 // 长度 未使用 #define BS_BootSig_Offset 0x26 // 扩展引导标记偏移 #define BS_BootSig_Len 1 // 扩展引导标记长度 #define BS_VolID_Offset 0x27 // 卷序列号偏移 #define BS_VolID_Len 4 // 卷序列号长度 #define BS_VolLab_Offset 0x2B // 卷标偏移 #define BS_VolLab_Len 11 // 卷标长度 #define BS_FileSysType_Offset 0x36 // 文件系统类型偏移 #define BS_FileSysType_Len 8 // 文件系统类型长度 #define DBR_BootCode_Offset 0x3E // 引导代码及其他偏移 #define DBR_BootCode_Len 448 // 引导代码及其他长度 #define DBR_EndMark_Offset 0x1FE // 结束标志偏移 #define DBR_EndMark_Len 2 // 结束标志长度 #define DBR_EndMark 0xAA55 // 结束标志 typedef struct { short BytsPerSec; // 每扇区字节数 char SecPerClus; // 每簇扇区数 short RsvdSecCnt; // 保留扇区数 (引导扇区的扇区数) char NumFATs; // FAT的份数 short RootEntCnt; // 根目录可容纳的目录项数 short TotSec16; // 扇区总数 char Media; // 介质描述符 short FATSz16; // 每个FAT表扇区数 short SecPerTrk; // 每磁道扇区数 short NumHeads; // 磁头数 int HiddSec; // 隐藏扇区数 int TotSec32; // 替代扇区数 char DrvNum; // int 13h的驱动器号 char Reservedl; // 未使用 char BootSig; // 扩展引导标记 int VolID; // 卷序列号 int TotalSize; // 总磁盘大小 int current_dir; // 当前目录的首地址 } DISK; DISK init_disk_attr() { DISK disk; disk.BytsPerSec = 0x0200; disk.SecPerClus = 0x01; disk.RsvdSecCnt = 0x0001; disk.NumFATs = 0x01; disk.RootEntCnt = 0x0200; disk.TotSec16 = 0x2000; disk.Media = 0xf8; disk.FATSz16 = 0x0020; disk.SecPerTrk = 0x0020; disk.NumHeads = 0x0040; disk.HiddSec = 0x00000000; disk.TotSec32 = 0x00000000; disk.DrvNum = 0x80; disk.Reservedl = 0x00; disk.BootSig = 0x29; disk.VolID = 0x00000000; disk.TotalSize = 0x400000; disk.current_dir = 0x4200; return disk; } struct tm get_time() { struct timeval tv; struct timezone tz; struct tm *t; gettimeofday(&tv, &tz); t = localtime(&tv.tv_sec); return *t; } void init_file_system(char disk_name[13], DISK disk_attr) { FILE* fp = fopen(disk_name, "wb"); // 跳转指令 fseek(fp, BS_jmpBoot_Offset, 0); char jmpBoot[BS_jmpBoot_Len] = { 0xEB, 0x3C, 0x90 }; fwrite(jmpBoot, 1, BS_jmpBoot_Len, fp); // 厂商名称 fseek(fp, BS_OEMName_Offset, 0); char OEMName[BS_OEMName_Len] = { 'K', 'e', 'J', 'F', ' ', ' ', ' ', ' ' }; fwrite(OEMName, 1, BS_OEMName_Len, fp); // 每扇区字节数 fseek(fp, BPB_BytsPerSec_Offset, 0); fwrite(&disk_attr.BytsPerSec, BPB_BytsPerSec_Len, 1, fp); // 每簇扇区数 fseek(fp, BPB_SecPerClus_Offset, 0); fwrite(&disk_attr.SecPerClus, BPB_SecPerClus_Len, 1, fp); // 保留扇区数 (引导扇区的扇区数) fseek(fp, BPB_RsvdSecCnt_Offset, 0); fwrite(&disk_attr.RsvdSecCnt, BPB_RsvdSecCnt_Len, 1, fp); // FAT的份数 fseek(fp, BPB_NumFATs_Offset, 0); fwrite(&disk_attr.NumFATs, BPB_NumFATs_Len, 1, fp); // 根目录可容纳的目录项数 fseek(fp, BPB_RootEntCnt_Offset, 0); fwrite(&disk_attr.RootEntCnt, BPB_RootEntCnt_Len, 1, fp); // 扇区总数 fseek(fp, BPB_TotSec16_Offset, 0); fwrite(&disk_attr.TotSec16, BPB_TotSec16_Len, 1, fp); // 介质描述符 fseek(fp, BPB_Media_Offset, 0); fwrite(&disk_attr.Media, BPB_Media_Len, 1, fp); // 每个FAT表扇区数 fseek(fp, BPB_FATSz16_Offset, 0); fwrite(&disk_attr.FATSz16, BPB_FATSz16_Len, 1, fp); // 每磁道扇区数 fseek(fp, BPB_SecPerTrk_Offset, 0); fwrite(&disk_attr.SecPerTrk, BPB_SecPerTrk_Len, 1, fp); // 磁头数 fseek(fp, BPB_NumHeads_Offset, 0); fwrite(&disk_attr.NumHeads, BPB_NumHeads_Len, 1, fp); // 隐藏扇区数 fseek(fp, BPB_HiddSec_Offset, 0); fwrite(&disk_attr.HiddSec, BPB_HiddSec_Len, 1, fp); // 替代扇区数 fseek(fp, BPB_TotSec32_Offset, 0); fwrite(&disk_attr.TotSec32, BPB_TotSec32_Len, 1, fp); // int 13h的驱动器号 fseek(fp, BS_DrvNum_Offset, 0); fwrite(&disk_attr.DrvNum, BS_DrvNum_Len, 1, fp); // 未使用 fseek(fp, BS_Reservedl_Offset, 0); fwrite(&disk_attr.Reservedl, BS_Reservedl_Len, 1, fp); // 扩展引导标记 fseek(fp, BS_BootSig_Offset, 0); fwrite(&disk_attr.BootSig, BS_BootSig_Len, 1, fp); // 卷序列号 fseek(fp, BS_VolID_Offset, 0); fwrite(&disk_attr.VolID, BS_VolID_Len, 1, fp); // 卷标 fseek(fp, BS_VolLab_Offset, 0); char VolLab[BS_VolLab_Len] = {'K', 'e', 'J', 'i', 'n', 'g', 'f', 'a', 'n', ' ', ' '}; fwrite(VolLab, 1, BS_VolLab_Len, fp); // 文件系统类型 fseek(fp, BS_FileSysType_Offset, 0); char FileSysType[BS_FileSysType_Len] = {'F', 'A', 'T', '1', '6', ' ', ' ', ' '}; fwrite(FileSysType, 1, BS_FileSysType_Len, fp); // 引导代码等 fseek(fp, DBR_BootCode_Offset, 0); char BootCode[DBR_BootCode_Len] = { 0 }; fwrite(BootCode, 1, DBR_BootCode_Len, fp); // 结束标志 fseek(fp, DBR_EndMark_Offset, 0); short EndMark = DBR_EndMark; fwrite(&EndMark, DBR_EndMark_Len, 1, fp); // FAT分区表 fseek(fp, 0x0200, 0); int FAT_Len = disk_attr.FATSz16 * disk_attr.BytsPerSec * disk_attr.NumFATs; // 每个FAT表扇区数 * 扇区字节数 * FAT的份数 char* FAT_data = (char*)malloc(sizeof(char) * FAT_Len); fwrite(FAT_data, 1, FAT_Len, fp); // DATA段 fseek(fp, 0x0200 + FAT_Len, 0); int DATA_Len = disk_attr.TotalSize - 0x0200 - FAT_Len; char* DATA_data = (char*)malloc(sizeof(char) * DATA_Len); fwrite(DATA_data, 1, DATA_Len, fp); fclose(fp); } unsigned short find_free_blocks(DISK disk_attr, FILE *fp) { unsigned short begin = 0x200; unsigned short end = disk_attr.FATSz16 * disk_attr.BytsPerSec; unsigned short ans = 0x06; while (ans < end) { fseek(fp, begin + ans, 0); char index[5] = { 0 }; fread(index, 1, 4, fp); if (!index[0] && !index[1] && !index[2] && !index[3]) break; ans += 2; } if (ans >= end) return 0xFFFF; return ans / 2; } int mkdir(char dir_name[11], char disk_name[13], DISK disk_attr) { FILE* fp = fopen(disk_name, "rb+"); unsigned short dir_firstBlockNum = find_free_blocks(disk_attr, fp); if (dir_firstBlockNum == 0xFFFF) return -1; fseek(fp, 0x200 + dir_firstBlockNum * 2, 0); short new_index = 0xFFFF; fwrite(&new_index, 2, 1, fp); int start_byte = disk_attr.current_dir; int byte_line_num = 0; while (byte_line_num < disk_attr.BytsPerSec) { fseek(fp, start_byte + byte_line_num, 0); int byte_line[4] = { 0 }; fread(byte_line, 4, 3, fp); if (!byte_line[0] && !byte_line[1] && !byte_line[2]) break; byte_line_num += 0x20; } if (byte_line_num >= disk_attr.BytsPerSec) return -1; fseek(fp, start_byte + byte_line_num, 0); fwrite(dir_name, 1, 11, fp); short dir_attr_byte = 0b00010000; fwrite(&dir_attr_byte, 1, 1, fp); short dir_reserved_byte[6] = { 0 }; fwrite(dir_reserved_byte, 2, 5, fp); struct tm time = get_time(); short dir_time_byte = time.tm_hour * 2048 + time.tm_min * 32 + time.tm_sec / 2; fwrite(&dir_time_byte, 2, 1, fp); short dir_date_byte = (time.tm_year + 1900 - 1980) * 512 + time.tm_mon * 32 + time.tm_mday; fwrite(&dir_date_byte, 2, 1, fp); fwrite(&dir_firstBlockNum, 2, 1, fp); short dir_size = disk_attr.BytsPerSec * disk_attr.SecPerClus; fwrite(&dir_size, 2, 1, fp); int new_block = 0x7800 + disk_attr.BytsPerSec * disk_attr.SecPerClus * dir_firstBlockNum; fseek(fp, new_block, 0); char dot[11] = { '.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }; fwrite(dot, 1, 11, fp); fwrite(&dir_attr_byte, 1, 1, fp); fwrite(dir_reserved_byte, 2, 5, fp); fwrite(&dir_time_byte, 2, 1, fp); fwrite(&dir_date_byte, 2, 1, fp); short dir_oriBlock_byte = 0; fwrite(&dir_oriBlock_byte, 2, 1, fp); unsigned int dir_oriSize = 0; fwrite(&dir_oriSize, 4, 1, fp); fseek(fp, new_block + 0x20, 0); char dotdot[11] = { '.', '.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }; fwrite(dotdot, 1, 11, fp); fwrite(&dir_attr_byte, 1, 1, fp); fwrite(dir_reserved_byte, 2, 5, fp); short dir_oriTime_byte = 0; fwrite(&dir_oriTime_byte, 2, 1, fp); short dir_oriDate_byte = (1970 - 1980 + 1900) * 512 + 1 * 32 + 1; fwrite(&dir_oriDate_byte, 2, 1, fp); fwrite(&dir_oriBlock_byte, 2, 1, fp); fwrite(&dir_oriSize, 4, 1, fp); fclose(fp); return 0; } int touch(char file_name[11], char disk_name[13], DISK disk_attr) { FILE* contentFile = fopen("./data.txt", "r"); char *content = (char*)malloc(2000 * sizeof(char)); fread(content, 1, 2000, contentFile); fclose(contentFile); FILE* fp = fopen(disk_name, "rb+"); int file_blockNum = strlen(content) / (disk_attr.BytsPerSec * disk_attr.SecPerClus) + 1; unsigned short* index = (short*)malloc(sizeof(short) * file_blockNum); for (int i = 0; i < file_blockNum; i++) { index[i] = find_free_blocks(disk_attr, fp); } for (int i = 0; i < file_blockNum - 1; i++) { fseek(fp, 0x200 + index[i] * 2, 0); fwrite(&index[i + 1], 2, 1, fp); } fseek(fp, 0x200 + index[file_blockNum - 1] * 2, 0); short last_index = 0xFFFF; fwrite(&last_index, 2, 1, fp); int start_byte = disk_attr.current_dir; int byte_line_num = 0; while (byte_line_num < disk_attr.BytsPerSec) { fseek(fp, start_byte + byte_line_num, 0); int byte_line[4] = { 0 }; fread(byte_line, 4, 3, fp); if (!byte_line[0] && !byte_line[1] && !byte_line[2]) break; byte_line_num += 0x20; } if (byte_line_num >= disk_attr.BytsPerSec) return -1; fseek(fp, start_byte + byte_line_num, 0); fwrite(file_name, 1, 11, fp); short file_attr_byte = 0b00000000; fwrite(&file_attr_byte, 1, 1, fp); short file_reserved_byte[6] = { 0 }; fwrite(file_reserved_byte, 2, 5, fp); struct tm time = get_time(); short file_time_byte = time.tm_hour * 2048 + time.tm_min * 32 + time.tm_sec / 2; fwrite(&file_time_byte, 2, 1, fp); short file_date_byte = (time.tm_year + 1900 - 1980) * 512 + time.tm_mon * 32 + time.tm_mday; fwrite(&file_date_byte, 2, 1, fp); fwrite(&index[0], 2, 1, fp); unsigned int file_size = strlen(content); fwrite(&file_size, 4, 1, fp); for (int i = 0; i < file_blockNum; i++) { int new_block = 0x7800 + disk_attr.BytsPerSec * disk_attr.SecPerClus * index[i]; fseek(fp, new_block, 0); fwrite(content, file_size > disk_attr.BytsPerSec * disk_attr.SecPerClus ? disk_attr.BytsPerSec * disk_attr.SecPerClus : file_size, 1, fp ); content += disk_attr.BytsPerSec * disk_attr.SecPerClus; file_size -= disk_attr.BytsPerSec * disk_attr.SecPerClus; } fclose(fp); return 0; } int main() { char disk_name[13] = "KJF_disk.img"; DISK disk_attr = init_disk_attr(); init_file_system(disk_name, disk_attr); // char dir_name[11] = "testdir "; // mkdir(dir_name, disk_name, disk_attr); // char file_name[11] = "data txt"; // touch(file_name, disk_name, disk_attr); return 0; }