272 lines
No EOL
8 KiB
C
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);
|
|
}
|
|
} |