os3/libfat/libfat.c
2022-09-24 22:30:25 -04:00

272 lines
No EOL
8 KiB
C

#include "libfat.h"
os_u32 loaded_fat_segment[512];
#define DIRECTORY_BUFFER_SIZE 32
FatDirectoryEntry directory_buffer[DIRECTORY_BUFFER_SIZE];
os_bool libfat_read_header_12(FileHandle handle, FatHeader_12* result) {
handle.seek(0, LIBFAT_SEEK_END, handle.user_data);
os_u32 size = handle.tell(handle.user_data);
if (size < sizeof(FatHeader_12)) {
return OS_FALSE;
}
handle.seek(0, LIBFAT_SEEK_ORIGIN, handle.user_data);
handle.read(sizeof(FatHeader_12), (void*)result, handle.user_data);
return OS_TRUE;
}
os_bool libfat_read_header_32(FileHandle handle, FatHeader_32* result) {
handle.seek(0, LIBFAT_SEEK_END, handle.user_data);
os_u32 size = handle.tell(handle.user_data);
if (size < sizeof(FatHeader_32)) {
return OS_FALSE;
}
handle.seek(0, LIBFAT_SEEK_ORIGIN, handle.user_data);
handle.read(sizeof(FatHeader_32), (void*)result, handle.user_data);
return OS_TRUE;
}
os_bool libfat_img_write_mbr(FileHandle image_file, FileHandle mbr_file) {
return OS_TRUE;
}
os_u32 libfat_img_copy_file(FileHandle image_file, FileHandle file, os_s8* name) {
return 0;
}
os_bool libfat_load_fat_cluster(FatControlBlock* fat, os_u32 target_cluster, os_bool force) {
if (fat->first_loaded_cluster > target_cluster ||
fat->first_loaded_cluster + fat->loaded_fat_cluster_amount <= target_cluster ||
force != OS_FALSE) {
os_u32 fat_size = fat->header.sectors_per_fat_32 * fat->header.base.bytes_per_sector;
os_u32 fat_offset = (fat->header.base.bytes_per_sector * fat->header.base.reserved_sectors) + fat_size;
fat->handle.seek(fat_offset, LIBFAT_SEEK_ORIGIN, fat->handle.user_data);
os_u32 fat_clusters = fat_size / sizeof(os_u32);
if (target_cluster >= fat_clusters) {
return OS_FALSE;
}
os_u32 base_cluster = target_cluster - (target_cluster % fat->loaded_fat_cluster_amount);
os_u32 final_offset = fat_offset + (base_cluster * sizeof(os_u32));
fat->handle.read(fat->loaded_fat_cluster_amount * sizeof(os_u32), (void*)fat->loaded_fat_segment, fat->handle.user_data);
return OS_TRUE;
}
return OS_TRUE;
}
os_u32 libfat_read_cluster(FatControlBlock* fat, os_u32 cluster) {
if(libfat_load_fat_cluster(fat, cluster, OS_FALSE) == OS_FALSE) {
return 0;
}
return fat->loaded_fat_segment[cluster - fat->first_loaded_cluster];
}
os_u32 libfat_load_cluster(FatControlBlock* fat, os_u32 cluster, void* buffer, os_u32 buffer_size, os_u32 offset_in_cluster) {
os_u32 cluster_size = fat->header.base.bytes_per_sector * fat->header.base.sectors_per_cluster;
os_u32 data_offset = (fat->header.base.reserved_sectors + (fat->header.sectors_per_fat_32 * fat->header.base.number_of_fats)) * fat->header.base.bytes_per_sector;
if (offset_in_cluster >= cluster_size) {
return 0;
}
os_u32 cluster_offset = data_offset + ((cluster - 2) * cluster_size) + offset_in_cluster;
os_u32 amount_to_read = cluster_size - offset_in_cluster > buffer_size ? buffer_size : cluster_size - offset_in_cluster;
if(!fat->handle.seek(cluster_offset, LIBFAT_SEEK_ORIGIN, fat->handle.user_data)) {
return 0;
}
os_u32 read = fat->handle.read(amount_to_read, buffer, fat->handle.user_data);
return read;
}
os_bool libfat_open_read(FatControlBlock* fat, FatDirectoryEntry* entry, LibFatFile* result) {
if(result == 0 || fat == 0 || entry == 0) {
return OS_FALSE;
}
if ((entry->attribute & FAT_SYSTEM_BIT) != 0 ||
(entry->attribute & FAT_VOLUME_BIT) != 0) {
return OS_FALSE;
}
result->fat = fat;
result->file_entry = *entry;
result->fat_cluster_size = fat->header.base.sectors_per_cluster * fat->header.base.bytes_per_sector;
result->fat_data_offset = (fat->header.base.reserved_sectors + (fat->header.sectors_per_fat_32 * fat->header.base.number_of_fats)) * fat->header.base.bytes_per_sector;
result->position = 0;
result->current_cluster = (((os_u32)entry->start_cluster_high) << 16) + entry->start_cluster;
result->in_cluster_position = 0;
return OS_TRUE;
}
os_bool libfat_open_directory(FatControlBlock* fat, FatDirectoryEntry* entry, LibFatDirectory* result) {
if (fat == 0 || result == 0) {
return OS_FALSE;
}
if (entry != 0 && (entry->attribute & FAT_SUBDIRECTORY_BIT) == 0) {
return OS_FALSE;
}
result->fat = fat;
result->fat_cluster_size = fat->header.base.sectors_per_cluster * fat->header.base.bytes_per_sector;
result->current_cluster = entry == 0 ? fat->header.first_root_cluster : (((os_u32)entry->start_cluster_high) << 16) + entry->start_cluster;
result->base_cluster = result->current_cluster;
result->position_in_cluster = 0;
result->done = 0;
return OS_TRUE;
}
os_bool libfat_read_directory(LibFatDirectory* dir, FatDirectoryEntry* entry) {
if (dir == 0 || entry == 0) {
return OS_FALSE;
}
if (dir->done == OS_TRUE) {
return OS_FALSE;
}
FatDirectoryEntry my_entry;
os_u32 read = libfat_load_cluster(dir->fat, dir->current_cluster, &my_entry, sizeof(FatDirectoryEntry), dir->position_in_cluster);
dir->position_in_cluster += read;
if (dir->position_in_cluster == dir->fat_cluster_size) {
os_u32 next_cluster = libfat_read_cluster(dir->fat, dir->current_cluster);
if (next_cluster >= FAT_LAST_CLUSTER_32) {
dir->done = OS_TRUE;
}
}
if (my_entry.file_name[0] == '\0') {
dir->done = OS_TRUE;
return OS_FALSE;
}
*entry = my_entry;
return OS_TRUE;
}
os_u32 libfat_read(LibFatFile* file, void* buffer, os_u32 buffer_size) {
os_u32 read = 0;
os_bool eof = file->position >= file->file_entry.file_size ? OS_TRUE : OS_FALSE;
while(read < buffer_size && eof != OS_TRUE) {
os_u32 amount_left = file->file_entry.file_size - file->position;
os_u32 amount_to_read = (buffer_size - read) > amount_left ? amount_left : buffer_size - read;
os_u32 local_read;
if (file->in_cluster_position + amount_to_read >= file->fat_cluster_size) {
local_read = file->fat_cluster_size - file->in_cluster_position;
} else {
local_read = amount_to_read;
}
os_u32 r = libfat_load_cluster(file->fat, file->current_cluster, buffer, local_read, file->in_cluster_position);
read += r;
buffer += r;
file->position += r;
file->in_cluster_position += r;
if (file->in_cluster_position == file->fat_cluster_size) {
file->current_cluster = libfat_read_cluster(file->fat, file->current_cluster);
file->in_cluster_position = 0;
}
if (file->position == file->file_entry.file_size) {
eof = OS_TRUE;
}
}
return read;
}
os_u32 libfat_tell(LibFatFile* file) {
if(file == 0) {
return 0;
}
return file->position;
}
os_bool libfat_init(FileHandle file, void* buffer, os_u32 buffer_size, FatControlBlock* result) {
if(libfat_read_header_32(file, &result->header) != OS_TRUE) {
return OS_FALSE;
}
result->handle = file;
result->loaded_fat_segment = (os_u32*)buffer;
result->loaded_fat_cluster_amount = buffer_size / sizeof(os_u32);
result->first_loaded_cluster = 0;
if(libfat_load_fat_cluster(result, 2, OS_TRUE) != OS_TRUE) {
return OS_FALSE;
}
return OS_TRUE;
}
void libfat_test(FileHandle handle, PrintRoutine print, PrintNumber printNumber) {
FatControlBlock cb;
if (libfat_init(handle, loaded_fat_segment, 512 * sizeof(os_u32), &cb) != OS_TRUE) {
print("Failed to init FAT.", 0);
return;
}
LibFatDirectory dir;
if (libfat_open_directory(&cb, 0, &dir) != OS_TRUE) {
print("Failecd to open directory.", 0);
return;
}
FatDirectoryEntry entry;
while(libfat_read_directory(&dir, &entry) == OS_TRUE) {
if ((entry.attribute & (os_s8)FAT_HIDDEN_BIT) != 0 ||
(entry.attribute & (os_s8)FAT_VOLUME_BIT) != 0 ||
(entry.attribute & (os_s8)FAT_SYSTEM_BIT) != 0) {
continue;
}
print("Entry name: ", 0);
print(entry.file_name, 11);
os_u32 cluster = (((os_u32)entry.start_cluster_high) << 16) + entry.start_cluster;
print("Cluster: ", 0);
printNumber(cluster);
print("Size: ", 0);
printNumber(entry.file_size);
os_u32 effective_size = entry.file_size > 512 ? 512 : entry.file_size;
if(effective_size > 0) {
LibFatFile f;
if (libfat_open_read(&cb, &entry, &f) == OS_TRUE) {
char buffer[512];
os_u32 amount = libfat_read(&f, buffer, 512);
print("Content: ", 0);
print(buffer, amount);
}
}
print("--------", 0);
}
}