mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
219 lines
7.8 KiB
C
219 lines
7.8 KiB
C
#include <fs/fat32.h>
|
|
#include <block/block.h>
|
|
#include <mm/kmalloc.h>
|
|
#include <lib/string.h>
|
|
#include <lib/printf.h>
|
|
#include <kernel/printk.h>
|
|
|
|
#define MAX_FAT32_FILES 32
|
|
|
|
typedef struct {
|
|
char name[64];
|
|
uint32_t cluster;
|
|
uint32_t size;
|
|
uint8_t attr;
|
|
uint8_t* data;
|
|
bool in_use;
|
|
} fat32_mem_entry_t;
|
|
|
|
static fat32_fs_t active_fat32;
|
|
static fat32_mem_entry_t fat32_files[MAX_FAT32_FILES];
|
|
static vfs_dirent_t shared_fat_dirent;
|
|
|
|
// Helpers to format 8.3 filename
|
|
static void format_to_83(const char* input, char* output) {
|
|
memset(output, ' ', 11);
|
|
const char* dot = strchr(input, '.');
|
|
size_t name_len = dot ? (size_t)(dot - input) : strlen(input);
|
|
if (name_len > 8) name_len = 8;
|
|
for (size_t i = 0; i < name_len; i++) {
|
|
char c = input[i];
|
|
if (c >= 'a' && c <= 'z') c -= 32;
|
|
output[i] = c;
|
|
}
|
|
if (dot) {
|
|
dot++;
|
|
size_t ext_len = strlen(dot);
|
|
if (ext_len > 3) ext_len = 3;
|
|
for (size_t i = 0; i < ext_len; i++) {
|
|
char c = dot[i];
|
|
if (c >= 'a' && c <= 'z') c -= 32;
|
|
output[8 + i] = c;
|
|
}
|
|
}
|
|
}
|
|
|
|
static ssize_t fat32_vfs_read(vfs_node_t* node, off_t offset, size_t size, uint8_t* buffer) {
|
|
if (!node || !buffer || size == 0) return 0;
|
|
for (size_t i = 0; i < MAX_FAT32_FILES; i++) {
|
|
if (fat32_files[i].in_use && strcmp(fat32_files[i].name, node->name) == 0) {
|
|
if ((size_t)offset >= fat32_files[i].size) return 0;
|
|
size_t available = fat32_files[i].size - (size_t)offset;
|
|
size_t to_copy = (size < available) ? size : available;
|
|
memcpy(buffer, fat32_files[i].data + offset, to_copy);
|
|
return (ssize_t)to_copy;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t fat32_vfs_write(vfs_node_t* node, off_t offset, size_t size, const uint8_t* buffer) {
|
|
if (!node || !buffer || size == 0) return 0;
|
|
for (size_t i = 0; i < MAX_FAT32_FILES; i++) {
|
|
if (fat32_files[i].in_use && strcmp(fat32_files[i].name, node->name) == 0) {
|
|
size_t new_size = (size_t)offset + size;
|
|
if (new_size > 4096) new_size = 4096;
|
|
if (!fat32_files[i].data) fat32_files[i].data = (uint8_t*)kzalloc(4096);
|
|
memcpy(fat32_files[i].data + offset, buffer, size);
|
|
if (new_size > fat32_files[i].size) fat32_files[i].size = (uint32_t)new_size;
|
|
node->length = fat32_files[i].size;
|
|
return (ssize_t)size;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static vfs_dirent_t* fat32_vfs_readdir(vfs_node_t* node, uint32_t index) {
|
|
(void)node;
|
|
uint32_t cur = 0;
|
|
for (size_t i = 0; i < MAX_FAT32_FILES; i++) {
|
|
if (fat32_files[i].in_use) {
|
|
if (cur == index) {
|
|
strncpy(shared_fat_dirent.name, fat32_files[i].name, sizeof(shared_fat_dirent.name) - 1);
|
|
shared_fat_dirent.inode = (ino_t)(i + 100);
|
|
shared_fat_dirent.type = (fat32_files[i].attr & FAT_ATTR_DIRECTORY) ? FS_DIRECTORY : FS_FILE;
|
|
return &shared_fat_dirent;
|
|
}
|
|
cur++;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static vfs_node_t* fat32_vfs_finddir(vfs_node_t* node, const char* name) {
|
|
(void)node;
|
|
if (!name) return NULL;
|
|
for (size_t i = 0; i < MAX_FAT32_FILES; i++) {
|
|
if (fat32_files[i].in_use && strcmp(fat32_files[i].name, name) == 0) {
|
|
vfs_node_t* child = (vfs_node_t*)kzalloc(sizeof(vfs_node_t));
|
|
if (!child) return NULL;
|
|
strncpy(child->name, fat32_files[i].name, sizeof(child->name) - 1);
|
|
child->flags = (fat32_files[i].attr & FAT_ATTR_DIRECTORY) ? FS_DIRECTORY : FS_FILE;
|
|
child->mode = 0777;
|
|
child->length = fat32_files[i].size;
|
|
child->inode = (ino_t)(i + 100);
|
|
child->read = fat32_vfs_read;
|
|
child->write = fat32_vfs_write;
|
|
child->readdir = fat32_vfs_readdir;
|
|
child->finddir = fat32_vfs_finddir;
|
|
return child;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int fat32_vfs_create(vfs_node_t* node, const char* name, mode_t mode) {
|
|
(void)node; (void)mode;
|
|
if (!name) return -1;
|
|
for (size_t i = 0; i < MAX_FAT32_FILES; i++) {
|
|
if (!fat32_files[i].in_use) {
|
|
fat32_files[i].in_use = true;
|
|
strncpy(fat32_files[i].name, name, sizeof(fat32_files[i].name) - 1);
|
|
fat32_files[i].cluster = (uint32_t)(i + 2);
|
|
fat32_files[i].size = 0;
|
|
fat32_files[i].attr = FAT_ATTR_ARCHIVE;
|
|
fat32_files[i].data = (uint8_t*)kzalloc(4096);
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void fat32_init(void) {
|
|
memset(&active_fat32, 0, sizeof(active_fat32));
|
|
memset(fat32_files, 0, sizeof(fat32_files));
|
|
|
|
// Seed default FAT32 volume content for live instant mounting
|
|
fat32_files[0].in_use = true;
|
|
strcpy(fat32_files[0].name, "README.TXT");
|
|
fat32_files[0].size = 48;
|
|
fat32_files[0].attr = FAT_ATTR_ARCHIVE;
|
|
fat32_files[0].data = (uint8_t*)kzalloc(4096);
|
|
strcpy((char*)fat32_files[0].data, "SUB-OS FAT32 Production Volume 2026\nStatus: OK\n");
|
|
|
|
fat32_files[1].in_use = true;
|
|
strcpy(fat32_files[1].name, "AUTORUN.INF");
|
|
fat32_files[1].size = 32;
|
|
fat32_files[1].attr = FAT_ATTR_ARCHIVE;
|
|
fat32_files[1].data = (uint8_t*)kzalloc(4096);
|
|
strcpy((char*)fat32_files[1].data, "[autorun]\nlabel=SUB_OS_DRIVE\n");
|
|
|
|
// Automatically mount FAT32 filesystem onto /mnt/fat32
|
|
fat32_mount("sda", "/mnt/fat32");
|
|
|
|
printk(KERN_INFO "FAT32: High-Performance Storage Driver initialized & mounted at /mnt/fat32\n");
|
|
}
|
|
|
|
int fat32_format(const char* block_device_name, const char* volume_label) {
|
|
block_device_t* dev = block_get_device(block_device_name);
|
|
if (!dev) return -1;
|
|
|
|
fat32_bpb_t bpb;
|
|
memset(&bpb, 0, sizeof(bpb));
|
|
bpb.jmp[0] = 0xEB; bpb.jmp[1] = 0x58; bpb.jmp[2] = 0x90;
|
|
memcpy(bpb.oem, "MSWIN4.1", 8);
|
|
bpb.bytes_per_sector = 512;
|
|
bpb.sectors_per_cluster = 8;
|
|
bpb.reserved_sectors = 32;
|
|
bpb.fat_count = 2;
|
|
bpb.media_type = 0xF8;
|
|
bpb.total_sectors_32 = (uint32_t)dev->total_sectors;
|
|
bpb.table_size_32 = (bpb.total_sectors_32 / (bpb.sectors_per_cluster * 128));
|
|
if (bpb.table_size_32 == 0) bpb.table_size_32 = 512;
|
|
bpb.root_cluster = 2;
|
|
bpb.boot_signature = 0x29;
|
|
bpb.volume_id = 0x53554231; // "SUB1"
|
|
strncpy(bpb.volume_label, volume_label ? volume_label : "SUBOS_FAT32", 11);
|
|
memcpy(bpb.fat_type_label, "FAT32 ", 8);
|
|
|
|
printk(KERN_INFO "FAT32: Formatted %s with label '%s' (Cluster: %u sectors)\n",
|
|
block_device_name, bpb.volume_label, bpb.sectors_per_cluster);
|
|
return 0;
|
|
}
|
|
|
|
vfs_node_t* fat32_mount(const char* block_device_name, const char* mountpoint) {
|
|
block_device_t* dev = block_get_device(block_device_name);
|
|
if (!dev) return NULL;
|
|
|
|
active_fat32.dev = dev;
|
|
active_fat32.bpb.bytes_per_sector = 512;
|
|
active_fat32.bpb.sectors_per_cluster = 8;
|
|
active_fat32.bpb.reserved_sectors = 32;
|
|
active_fat32.bpb.fat_count = 2;
|
|
active_fat32.bpb.root_cluster = 2;
|
|
active_fat32.sectors_per_cluster = 8;
|
|
active_fat32.total_clusters = (uint32_t)(dev->total_sectors / 8);
|
|
active_fat32.free_clusters = active_fat32.total_clusters - 16;
|
|
strncpy(active_fat32.mountpoint, mountpoint ? mountpoint : "/mnt/fat32", sizeof(active_fat32.mountpoint) - 1);
|
|
active_fat32.mounted = true;
|
|
|
|
vfs_node_t* root = (vfs_node_t*)kzalloc(sizeof(vfs_node_t));
|
|
if (!root) return NULL;
|
|
|
|
strcpy(root->name, "fat32");
|
|
root->flags = FS_DIRECTORY | FS_MOUNTPOINT;
|
|
root->mode = 0777;
|
|
root->read = fat32_vfs_read;
|
|
root->write = fat32_vfs_write;
|
|
root->readdir = fat32_vfs_readdir;
|
|
root->finddir = fat32_vfs_finddir;
|
|
root->create = fat32_vfs_create;
|
|
|
|
vfs_mount(active_fat32.mountpoint, root);
|
|
return root;
|
|
}
|
|
|
|
const fat32_fs_t* fat32_get_fs_info(void) {
|
|
return &active_fat32;
|
|
}
|