2024-09-05 13:31:02 +08:00

379 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#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;
}