c 模拟一个fat16文件系统1

建立一个mulu的目录,然后在此目录下创建一个文本文件

前面那个只能创建普通文本文件。

root@ubuntu:/mnt/fat# ls

mulu

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

总用量 8.0K

drwxr-xr-x 2 root root 512 Jan 1 2017 .

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

-rwxr-xr-x 1 root root 6 Jan 1 2017 FILE1.TXT

root@ubuntu:/mnt/fat#

#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;

}

// 修正后的 create_fat_table

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:mulu目录

fat16[3] = 0xFFFF; // 簇3:file1.txt文件

}

//创建根目录

void create_root_dir(DirEntry* root_dir, int root_entries) {

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

// 创建mulu目录项

DirEntry* entry = &root_dir[0];

memset(entry->name, ' ', 11);

memcpy(entry->name, "mulu", 4); // 目录名(大写)

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);

if (dir_entries == NULL) {

printf("内存分配失败\n");

return;

}

// 创建 "." 目录项

DirEntry* dot_entry = &dir_entries[0];

memset(dot_entry->name, ' ', 11);

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

dot_entry->attributes = 0x10;

dot_entry->first_cluster_low = cluster_num;

dot_entry->file_size = 0;

// 创建 ".." 目录项

DirEntry* dotdot_entry = &dir_entries[1];

memset(dotdot_entry->name, ' ', 11);

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

dotdot_entry->attributes = 0x10;

dotdot_entry->first_cluster_low = parent_cluster; // 根目录的父目录为0

dotdot_entry->file_size = 0;

fseek(fp, data_start, SEEK_SET);

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

free(dir_entries);

}

// 在指定目录中创建文件

void create_file_in_directory(FILE* fp, BootSector* bs, int dir_cluster,

const char* filename, const char* content, int file_cluster) {

// 读取目录数据区

unsigned int dir_start = g_bs_data_start + (dir_cluster - 2) * bs->bytes_per_sector;

DirEntry* dir_entries = (DirEntry*)malloc(bs->bytes_per_sector);

if (dir_entries == NULL) {

printf("内存分配失败\n");

return;

}

fseek(fp, dir_start, SEEK_SET);

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

// 查找空闲目录项(从第2个开始,因为前两个是.和..)

int i;

for (i = 2; i < bs->bytes_per_sector / sizeof(DirEntry); i++) {

if (dir_entries[i].name[0] == 0x00 || dir_entries[i].name[0] == 0xE5) {

break;

}

}

if (i >= bs->bytes_per_sector / sizeof(DirEntry)) {

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

free(dir_entries);

return;

}

// 创建文件目录项

DirEntry* entry = &dir_entries[i];

memset(entry->name, ' ', 11);

// 处理文件名(8.3格式)

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

if (dot) {

// 有扩展名

int name_len = dot - filename;

int ext_len = strlen(dot + 1);

// 文件名部分(最多8个字符)

memcpy(entry->name, filename, name_len > 8 ? 8 : name_len);

// 扩展名部分(最多3个字符)

if (ext_len > 0) {

memcpy(entry->name + 8, dot + 1, ext_len > 3 ? 3 : ext_len);

}

} else {

// 无扩展名

memcpy(entry->name, filename, strlen(filename) > 8 ? 8 : strlen(filename));

}

// 转换为大写(FAT标准要求)

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

if (entry->name[j] >= 'a' && entry->name[j] <= 'z') {

entry->name[j] = entry->name[j] - 'a' + 'A';

}

}

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

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 = file_cluster;

entry->file_size = strlen(content);

// 写回目录数据区

fseek(fp, dir_start, SEEK_SET);

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

free(dir_entries);

// 写入文件数据

unsigned int file_start = g_bs_data_start + (file_cluster - 2) * bs->bytes_per_sector;

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

if (file_data == NULL) {

printf("内存分配失败\n");

return;

}

memset(file_data, 0, bs->bytes_per_sector);

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

fseek(fp, file_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 );

// 4. 创建根目录

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);

// 5. 创建mulu目录的数据区(簇2)

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

// 6. 在mulu目录中创建file1.txt文件(簇3)

create_file_in_directory(fp, &bs, 2, "file1.txt", "88888\n", 3);

// 填充剩余空间

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");

fclose(fp);

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

return 0;

}

相关推荐
lengjingzju2 小时前
一网打尽Linux IPC(四):POSIX IPC
linux·服务器·c语言
取加若则_2 小时前
Linux进程状态解析:僵尸与孤儿进程揭秘
linux
活蹦乱跳酸菜鱼2 小时前
Linux开发板使用AI-通义千问
linux·运维·服务器
Xの哲學2 小时前
Linux IPC机制深度剖析:从设计哲学到内核实现
linux·服务器·网络·算法·边缘计算
lihui_cbdd2 小时前
[故障排查] NFS 存储集群卡顿的完整排查记录:谁在深夜疯狂读写?
linux·运维
掘根2 小时前
【消息队列项目】客户端搭建与测试
运维·服务器·中间件
ONE_SIX_MIX2 小时前
debian 13 安装 nvidia-driver 后,登录后黑屏,只能看到左上角光标 或 一个鼠标 的问题解决
运维·debian
虹科数字化与AR2 小时前
安宝特方案丨AR电力·变电篇:筑牢变电站安全运维
运维·安全·ar
代码游侠2 小时前
应用——Linux Socket编程
运维·服务器·开发语言·笔记·网络协议·学习