c 模拟一个fat16文件系统

模拟一个fat16文件系统,并创建4个文件,生成的映像可挂载。

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/stat.h> //文件权限相关

#include <arpa/inet.h>

#include <sys/socket.h>

#include <stdio.h>

#include <stdlib.h>

#include <stdint.h>

#include <string.h>

#include <capstone/capstone.h>

#include <elf.h>

#include <sys/queue.h>

typedef unsigned char u8;

typedef unsigned int u32;

typedef unsigned short u16;

typedef char s8;

typedef short s16;

typedef int s32;

typedef unsigned longULONG;

int macdbg_dmphex( const char* buff, int len );

unsigned int g_debug_buff[64];

int macdbg_dmphex( const char* buff, int len )

{

int retval = 0;

int x, y, tot, lineoff;

const char* curr;

lineoff = 0;

curr = buff;

tot = 0;

printf( "buff = %p\n", buff );

for( x = 0; len > x+16; ){

printf("0x%08x: ", lineoff);

for( y = 0; y < 16; y++ ){

printf("%02x ", (unsigned char)*(curr + y));

}

printf(" ");

for( y = 0; y < 16; y++ ){

char c;

c = *(curr + y);

if( c > 31 && c < 127 ){

printf("%c", c);

}else{

printf("%c", '.');

}

tot++;

}

curr += 16;

x += 16;

lineoff += 16;

printf("\n");

}

//do last line

if( tot < len ){

curr = (buff + tot);

printf("0x%08x: ", lineoff);

for( y = 0; y < (len - tot); y++ ){

printf("%02x ", (unsigned char)*(curr + y));

}

//padding with spaces

//Ser_Printf("(len - tot) %d.\r\n", (len - tot) );

if( (len - tot) < 16 ){

for( y = 0; y < (32 - ((len - tot)*2)); y++ ){

printf(" ");

}

}

for( y = 0; y < 16-(len - tot); y++ ){

printf(" ");

}

printf(" ");

//Ser_Printf("(len - tot) %d.\r\n", (len - tot) );

for( y = 0; y < (len - tot); y++ ){

char c;

c = *(curr + y);

if( c >31 && c < 127 ){

printf("%c", c);

}else{

printf("%c", '.');

}

}

}

printf("\n");

return retval;

}

//dd if=/dev/zero of=fat.img bs=1k count=64

//mkfs.vfat ./fat.img

//mkdir -p /mnt/fat

//mount -o loop fat.img /mnt/fat

//echo "Hello, FAT!" > /mnt/fat/testfile.txt

//sync

//umount /mnt/fat

// FAT16引导扇区结构

#pragma pack(push, 1)

typedef struct {

uint8_t jump_boot[3];

char oem_name[8];

uint16_t bytes_per_sector;

uint8_t sectors_per_cluster;

uint16_t reserved_sectors;

uint8_t fat_count;

uint16_t root_entries;

uint16_t total_sectors_16;

uint8_t media_type;

uint16_t sectors_per_fat;

uint16_t sectors_per_track;

uint16_t head_count;

uint32_t hidden_sectors;

uint32_t total_sectors_32;

uint8_t drive_number;

uint8_t reserved;

uint8_t boot_signature;

uint32_t volume_serial;

char volume_label[11];

char fs_type[8];

uint8_t boot_code[448];

uint16_t boot_sector_sig;

} BootSector;

#pragma pack(pop)

// FAT目录项结构

#pragma pack(push, 1)

typedef struct {

char name[11];

uint8_t attributes;

uint8_t reserved;

uint8_t creation_time_tenth;

uint16_t creation_time;

uint16_t creation_date;

uint16_t last_access_date;

uint16_t first_cluster_high;

uint16_t write_time;

uint16_t write_date;

uint16_t first_cluster_low;

uint32_t file_size;

} DirEntry;

#pragma pack(pop)

unsigned int g_bs_data_start = 0x00;

// 创建引导扇区

void create_boot_sector(BootSector* bs)

{

memset(bs, 0, sizeof(BootSector));

bs->jump_boot[0] = 0xEB;

bs->jump_boot[1] = 0x3C;

bs->jump_boot[2] = 0x90;

memcpy(bs->oem_name, "MSDOS5.0", 8);

bs->bytes_per_sector = 512;

bs->sectors_per_cluster = 1;

bs->reserved_sectors = 1;

bs->fat_count = 2;

bs->root_entries = 224;

bs->total_sectors_16 = 2880;

bs->media_type = 0xF0;

bs->sectors_per_fat = 9;

bs->sectors_per_track = 18;

bs->head_count = 2;

bs->hidden_sectors = 0;

bs->total_sectors_32 = 0;

bs->drive_number = 0x80;

bs->boot_signature = 0x29;

bs->volume_serial = 0x12345678;

memcpy(bs->volume_label, "MYDISK ", 11);

memcpy(bs->fs_type, "FAT16 ", 8);

bs->boot_sector_sig = 0xAA55;

}

// 创建FAT表

void create_fat_table(uint8_t* fat, int sectors_per_fat, int bytes_per_sector) {

memset(fat, 0, sectors_per_fat * bytes_per_sector);

uint16_t* fat16 = (uint16_t*)fat;

fat16[0] = 0xFFF0; // 簇0:介质类型

fat16[1] = 0xFFFF; // 簇1:保留

//fat16[2] = 0xFFFF; // 簇2:TEST目录

//fat16[3] = 0xFFFF; // 簇3:TEST1.TXT

}

// 创建根目录

void create_root_dir(DirEntry* root_dir, int root_entries) {

memset(root_dir, 0, root_entries * sizeof(DirEntry));

DirEntry* entry = &root_dir[0];

memcpy(entry->name, "mulu", 5); // 目录名

entry->attributes = 0x10; // 目录属性

entry->creation_time_tenth = 0;

entry->creation_time = 0x8000;

entry->creation_date = 0x4A21;

entry->last_access_date = 0x4A21;

entry->first_cluster_high = 0;

entry->write_time = 0x8000;

entry->write_date = 0x4A21;

entry->first_cluster_low = 2; // 起始簇2

entry->file_size = 0; // 目录大小为0

}

// 创建目录数据区

void create_directory_data(FILE* fp, BootSector* bs, int cluster_num, int parent_cluster) {

unsigned int data_start = g_bs_data_start + (cluster_num - 2) * bs->bytes_per_sector;

DirEntry* dir_entries = (DirEntry*)calloc(bs->bytes_per_sector, 1);

// 创建 "." 目录项

DirEntry* dot_entry = &dir_entries[0];

memcpy(dot_entry->name, ". ", 11);

dot_entry->attributes = 0x10;

dot_entry->first_cluster_low = cluster_num;

// 创建 ".." 目录项

DirEntry* dotdot_entry = &dir_entries[1];

memcpy(dotdot_entry->name, ".. ", 11);

dotdot_entry->attributes = 0x10;

dotdot_entry->first_cluster_low = parent_cluster;

fseek(fp, data_start, SEEK_SET);

fwrite(dir_entries, bs->bytes_per_sector, 1, fp);

free(dir_entries);

}

// 创建文件

void create_file(FILE* fp, BootSector* bs, const char* filename, const char* content, int cluster_num) {

DirEntry* root_dir = (DirEntry*)malloc(bs->root_entries * sizeof(DirEntry));

unsigned int root_dir_start = bs->reserved_sectors * bs->bytes_per_sector +

(bs->fat_count * bs->sectors_per_fat * bs->bytes_per_sector);

fseek(fp, root_dir_start, SEEK_SET);

fread(root_dir, sizeof(DirEntry), bs->root_entries, fp);

for (int i = 0; i < bs->root_entries; i++) {

if (root_dir[i].name[0] == 0x00) {

memcpy(root_dir[i].name, filename, 11);

root_dir[i].attributes = 0x20; // 文件属性

root_dir[i].first_cluster_low = cluster_num;

root_dir[i].file_size = strlen(content);

fseek(fp, root_dir_start + i * sizeof(DirEntry), SEEK_SET);

fwrite(&root_dir[i], sizeof(DirEntry), 1, fp);

break;

}

}

free(root_dir);

// 写入文件数据

unsigned int data_start = g_bs_data_start + (cluster_num - 2) * bs->bytes_per_sector;

uint8_t* file_data = (uint8_t*)malloc(bs->bytes_per_sector);

memcpy(file_data, content, strlen(content));

fseek(fp, data_start, SEEK_SET);

fwrite(file_data, bs->bytes_per_sector, 1, fp);

free(file_data);

}

// 修正后的 find_free_cluster 函数

int find_free_cluster(FILE* fp, BootSector* bs) {

int fat_size = bs->sectors_per_fat * bs->bytes_per_sector;

uint8_t* fat = (uint8_t*)malloc(fat_size);

fseek(fp, bs->reserved_sectors * bs->bytes_per_sector, SEEK_SET);

fread(fat, 1, fat_size, fp);

uint16_t* fat16 = (uint16_t*)fat;

int total_clusters = fat_size / 2;

for (int i = 2; i < total_clusters; i++) {

if (fat16[i] == 0x0000) { // 空闲簇

free(fat);

return i;

}

}

free(fat);

return -1;

}

int count_chars_before_dot(const char* s) {

const char* dot = strchr(s, '.');

if (dot == NULL) {

return strlen(s); // 无.返回总长度

}

return dot - s; // 返回.前字符数

}

void write_file( FILE* fp, BootSector* bs, const char* filename, const char* content )

{

unsigned int root_dir_start;

int n;

DirEntry* root_dir = (DirEntry*)malloc(bs->root_entries * sizeof(DirEntry));

uint8_t* fat = (uint8_t*)malloc(1 * bs->sectors_per_fat * bs->bytes_per_sector);

int fat_size = bs->sectors_per_fat * bs->bytes_per_sector;

fseek(fp, bs->reserved_sectors * bs->bytes_per_sector, SEEK_SET);

fread(fat, 1, fat_size, fp);

//1.读取根目录

root_dir_start = bs->reserved_sectors * bs->bytes_per_sector +

(bs->fat_count * bs->sectors_per_fat * bs->bytes_per_sector);

fseek(fp, root_dir_start, SEEK_SET);

fread(root_dir, sizeof(DirEntry), bs->root_entries, fp);

// 2. 查找空闲簇

int cluster = find_free_cluster(fp, bs);

if (cluster == -1) {

printf("磁盘空间不足\n");

free(root_dir);

free(fat);

return;

}

printf("cluster = %d\n", cluster);

// 3. 创建目录项

int i;

for (i = 0; i < bs->root_entries; i++) {

if (root_dir[i].name[0] == 0x00) break;

}

if (i == bs->root_entries) {

printf("根目录已满\n");

free(root_dir);

free(fat);

return;

}

DirEntry* entry = &root_dir[i];

memset(entry->name, ' ', 11); // 初始化为空格

n = count_chars_before_dot(filename);

printf("n = %d\n", n);

memcpy(entry->name, filename, n > 8 ? 8 : n ); //限制8字节

memcpy(entry->name + 8, filename+n+1, strlen(filename)-n-1 );

entry->attributes = 0x20; // 普通文件

entry->first_cluster_low = cluster;

entry->file_size = strlen(content);

// 4. 写入根目录

fseek(fp, root_dir_start + i * sizeof(DirEntry), SEEK_SET);

fwrite(entry, sizeof(DirEntry), 1, fp);

// 5. 写入文件数据

unsigned int data_start = g_bs_data_start + (cluster - 2) * bs->bytes_per_sector;

int content_len = strlen(content);

int sectors = (content_len + bs->bytes_per_sector - 1) / bs->bytes_per_sector;

uint8_t* file_data = (uint8_t*)malloc(bs->bytes_per_sector);

printf("sectors = %d\n", sectors);

//return;

for (int j = 0; j < sectors; j++) {

int write_len = (j == sectors - 1) ? content_len % bs->bytes_per_sector : bs->bytes_per_sector;

printf("write_len = %d\n", write_len);

memcpy(file_data, content + j * bs->bytes_per_sector, write_len);

printf("data_start = %x\n", data_start);

fseek(fp, data_start + j * bs->bytes_per_sector, SEEK_SET);

fwrite(file_data, write_len, 1, fp);

// 更新FAT表

uint16_t* fat16 = (uint16_t*)fat;

if (j < sectors - 1) {

fat16[cluster] = cluster + 1; // 链接下一个簇

} else {

fat16[cluster] = 0xFFFF; // 文件结束

}

cluster++;

}

printf("bs->reserved_sectors * bs->bytes_per_sector = %x\n", bs->reserved_sectors * bs->bytes_per_sector);

// 6. 写回FAT表

fseek(fp, bs->reserved_sectors * bs->bytes_per_sector, SEEK_SET);

fwrite(fat, 1, 1 * bs->sectors_per_fat * bs->bytes_per_sector, fp);

fseek(fp, bs->reserved_sectors * bs->bytes_per_sector +

1 * bs->sectors_per_fat * bs->bytes_per_sector, SEEK_SET);

fwrite(fat, 1, 1 * bs->sectors_per_fat * bs->bytes_per_sector, fp);

// 7. 释放资源

free(root_dir);

free(fat);

free(file_data);

}

int main( void )

{

FILE* fp = fopen("fat.img", "wb+");

if (!fp) {

printf("can not to creat disk image.\n");

return 1;

}

unsigned int root_dir_start;

BootSector bs;

create_boot_sector(&bs);

fwrite(&bs, sizeof(BootSector), 1, fp);

printf( "sizeof(BootSector) = %d\n", sizeof(BootSector) );

printf( "bs.sectors_per_fat = %d\n", bs.sectors_per_fat );

printf( "bs.bytes_per_sector = %d\n", bs.bytes_per_sector );

int fat_size = bs.sectors_per_fat * bs.bytes_per_sector;

uint8_t* fat = (uint8_t*)calloc(fat_size, 1);

create_fat_table(fat, bs.sectors_per_fat, bs.bytes_per_sector);

//macdbg_dmphex( (const char *) fat, fat_size);

fwrite(fat, fat_size, 1, fp);

fwrite(fat, fat_size, 1, fp);

root_dir_start = bs.reserved_sectors * bs.bytes_per_sector +

(bs.fat_count * bs.sectors_per_fat * bs.bytes_per_sector);

g_bs_data_start = root_dir_start +

(bs.root_entries * sizeof(DirEntry));

printf( "bs.reserved_sectors = %d\n", bs.reserved_sectors );

printf( "bs.fat_count = %d\n", bs.fat_count );

printf( "bs.root_entries = %d\n", bs.root_entries );

printf( "sizeof(DirEntry) = %d\n", sizeof(DirEntry) );

printf( "root_dir_start = %#x\n", root_dir_start );

printf( "g_bs_data_start = %#x\n", g_bs_data_start );

//DirEntry* root_dir = (DirEntry*)calloc(bs.root_entries, sizeof(DirEntry));

//create_root_dir(root_dir, bs.root_entries);

//fwrite(root_dir, bs.root_entries * sizeof(DirEntry), 1, fp);

//uint8_t* file_data = (uint8_t*)calloc(bs.bytes_per_sector, 1);

// create_file_data(file_data, bs.bytes_per_sector);

//fwrite(file_data, bs.bytes_per_sector, 1, fp);

// 填充剩余空间

long current_pos = ftell(fp);

long total_size = 2880 * 512;

if (current_pos < total_size) {

uint8_t* padding = (uint8_t*)calloc(total_size - current_pos, 1);

fwrite(padding, total_size - current_pos, 1, fp);

free(padding);

}

fclose(fp);

free(fat);

//free(root_dir);

//free(file_data);

// 写入新文件

fp = fopen("fat.img", "r+b");

if (!fp) {

printf("无法打开磁盘镜像\n");

return 1;

}

//write_file(fp, &bs, "file1 txt", "file1 neirong888899999.\n");

write_file(fp, &bs, "file1.txt", "123\n");

write_file(fp, &bs, "file2.txt", "456\n");

write_file(fp, &bs, "file3.txt", "333\n");

write_file(fp, &bs, "file4.txt", "444\n");

fclose(fp);

printf("FAT16镜像已创建并写入新文件\n");

return 0;

}

// 主函数

int mainxxx(void) {

BootSector bs;

create_boot_sector(&bs);

FILE* fp = fopen("fat.img", "wb");

if (!fp) {

printf("无法创建磁盘镜像\n");

return 1;

}

// 写入引导扇区

fwrite(&bs, sizeof(BootSector), 1, fp);

// 写入两个FAT表

uint8_t* fat = (uint8_t*)malloc(bs.sectors_per_fat * bs.bytes_per_sector);

create_fat_table(fat, bs.sectors_per_fat, bs.bytes_per_sector);

fwrite(fat, bs.sectors_per_fat * bs.bytes_per_sector, 1, fp);

fwrite(fat, bs.sectors_per_fat * bs.bytes_per_sector, 1, fp);

free(fat);

// 创建根目录

DirEntry* root_dir = (DirEntry*)calloc(bs.root_entries, sizeof(DirEntry));

create_root_dir(root_dir, bs.root_entries);

fwrite(root_dir, bs.root_entries * sizeof(DirEntry), 1, fp);

free(root_dir);

// 创建TEST目录数据区(簇2)

create_directory_data(fp, &bs, 2, 0);

// 创建TEST1.TXT文件(簇3)

create_file(fp, &bs, "file", "Hello,FAT16!\n", 3);

// 填充剩余空间

unsigned int total_size = bs.total_sectors_16 * bs.bytes_per_sector;

unsigned int current_size = ftell(fp);

if (current_size < total_size) {

uint8_t* padding = (uint8_t*)calloc(total_size - current_size, 1);

fwrite(padding, 1, total_size - current_size, fp);

free(padding);

}

fclose(fp);

printf("FAT16镜像创建完成:fat16.img\n");

return 0;

}

mount -o loop fat.img /mnt/fat

root@ubuntu:/mnt/fat# ls -alh

总用量 13K

drwxr-xr-x 2 root root 7.0K Dec 31 1969 .

drwxr-xr-x 4 root root 4.0K Dec 25 02:20 ..

-rwxr-xr-x 1 root root 4 Dec 31 1979 file1.txt

-rwxr-xr-x 1 root root 4 Dec 31 1979 file2.txt

-rwxr-xr-x 1 root root 4 Dec 31 1979 file3.txt

-rwxr-xr-x 1 root root 4 Dec 31 1979 file4.txt

相关推荐
行走的bug...2 小时前
利用计算机辅助数学运算
人工智能·算法·机器学习
挖矿大亨2 小时前
C++中左移运算符重载
开发语言·c++
CoderCodingNo2 小时前
【GESP】C++五级真题(数论-素数、贪心思想考点) luogu-B4050 [GESP202409 五级] 挑战怪物
开发语言·c++·算法
小O的算法实验室2 小时前
2026年AEI SCI1区TOP,基于多策略集成粒子群算法+无人机平滑覆盖路径规划,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
~光~~2 小时前
【记录——内核模块加载到内核】基于鲁班猫4 rk3588s
c++·学习·rk3588s
小刘爱玩单片机2 小时前
【stm32简单外设篇】- 三色LED
c语言·stm32·单片机·嵌入式硬件
老王熬夜敲代码2 小时前
C++模版元编程2
开发语言·c++
hope_wisdom2 小时前
C/C++数据结构之队列基础
c语言·数据结构·c++·队列·queue
图形学爱好者_Wu2 小时前
C++ 数据结构 | 数组的底层原理
c++