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

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

char oem_name8;

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

char fs_type8;

uint8_t boot_code448;

uint16_t boot_sector_sig;

} BootSector;

#pragma pack(pop)

// FAT目录项结构

#pragma pack(push, 1)

typedef struct {

char name11;

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_boot0 = 0xEB;

bs->jump_boot1 = 0x3C;

bs->jump_boot2 = 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;

fat160 = 0xFFF0; // 簇0:介质类型

fat161 = 0xFFFF; // 簇1:保留

fat162 = 0xFFFF; // 簇2:mulu目录

fat163 = 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_dir0;

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

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

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_entriesi.name0 == 0x00 || dir_entriesi.name0 == 0xE5) {

break;

}

}

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

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

free(dir_entries);

return;

}

// 创建文件目录项

DirEntry* entry = &dir_entriesi;

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->namej >= 'a' && entry->namej <= 'z') {

entry->namej = entry->namej - '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 (fat16i == 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_diri.name0 == 0x00) break;

}

if (i == bs->root_entries) {

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

free(root_dir);

free(fat);

return;

}

DirEntry* entry = &root_diri;

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

fat16cluster = cluster + 1; // 链接下一个簇

} else {

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

}

相关推荐
且从容.几秒前
ubuntu安装flink
linux·ubuntu·flink
数字新视界1 小时前
动环监控信创适配在智能机房管理中的应用价值与未来展望
大数据·服务器·数据库·动环监控系统·动力与环境监控系统
爱和冰阔落2 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
程序员沉梦听雨2 小时前
WSL2的安装与使用
linux·wsl
微小的鱼2 小时前
Linux的渲染与显示系统链路
android·java·linux
lisanmengmeng2 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器
Android系统攻城狮3 小时前
Linux FFmpeg深度解析之av_write_frame调用流程与实战(三十三)
linux·运维·服务器·ffmpeg·音视频进阶·ffmpeg音视频
上火的金鱼妹3 小时前
k8s生产实际问题排查(网关,数据库读写等)
运维·服务器
孙克旭_3 小时前
k8s基础组件与创建资源
运维·docker·容器·kubernetes
孙克旭_3 小时前
云原生基础之Containerd容器运行时
运维·云原生