379 lines
13 KiB
C
379 lines
13 KiB
C
#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;
|
||
}
|
||
|