#include "libfat.h" #define FAT_ENTRY_CLUSTER(entry) ((((os_u32)entry.start_cluster_high) << 16) + entry.start_cluster) #define DIRECTORY_BUFFER_SIZE 32 FatDirectoryEntry directory_buffer[DIRECTORY_BUFFER_SIZE]; os_bool libfat_read_header_12(LFFileHandle 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(LFFileHandle 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_load_fat_cluster(LFControlBlock* 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->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(LFControlBlock* 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_bool libfat_write_fat_cluster(LFControlBlock* fat, os_u32 cluster_id, os_u32 cluster_value) { os_u32 fat_size = fat->header.sectors_per_fat_32 * fat->header.base.bytes_per_sector; if (cluster_id < 2 || cluster_id >= fat_size / sizeof(os_u32)) { return OS_FALSE; } os_u32 first_fat_offset = (fat->header.base.reserved_sectors * fat->header.base.bytes_per_sector); os_u32 second_fat_offset = first_fat_offset + fat_size; os_u32 fisrt_fat_cluster_offset = first_fat_offset + (cluster_id * sizeof(os_u32)); os_u32 second_fat_cluster_offset = second_fat_offset + (cluster_id * sizeof(os_u32)); fat->handle.seek(fisrt_fat_cluster_offset, LIBFAT_SEEK_ORIGIN, fat->handle.user_data); fat->handle.write(sizeof(os_u32), (void*)&cluster_value, fat->handle.user_data); fat->handle.seek(second_fat_cluster_offset, LIBFAT_SEEK_ORIGIN, fat->handle.user_data); fat->handle.write(sizeof(os_u32), (void*)&cluster_value, fat->handle.user_data); return OS_TRUE; } os_u32 libfat_load_cluster(LFControlBlock* 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_u32 libfat_write_cluster(LFControlBlock* 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 + buffer_size >= cluster_size) { return 0; } os_u32 cluster_offset = data_offset + ((cluster - 2) * cluster_size) + offset_in_cluster; if(fat->handle.seek(cluster_offset, LIBFAT_SEEK_ORIGIN, fat->handle.user_data) != OS_TRUE) { return 0; } os_u32 written = fat->handle.write(buffer_size, buffer, fat->handle.user_data); return written; } os_bool libfat_open(LFControlBlock* fat, LFDirectoryEntry* entry, LFFile* result) { if(result == 0 || fat == 0 || entry == 0) { return OS_FALSE; } if ((entry->entry.attribute & FAT_SYSTEM_BIT) != 0 || (entry->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->position = 0; result->current_cluster = FAT_ENTRY_CLUSTER(entry->entry); result->in_cluster_position = 0; return OS_TRUE; } os_bool libfat_open_directory(LFControlBlock* fat, LFDirectoryEntry* entry, LFDirectory* result) { if (fat == 0 || result == 0) { return OS_FALSE; } if (entry != 0 && (entry->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 : FAT_ENTRY_CLUSTER(entry->entry); result->base_cluster = result->current_cluster; result->position_in_cluster = 0; result->done = 0; return OS_TRUE; } os_bool libfat_read_directory(LFDirectory* dir, LFDirectoryEntry* 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); os_u32 cluster = dir->current_cluster; os_u32 offset = 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; } dir->current_cluster = next_cluster; } if (my_entry.file_name[0] == '\0') { dir->done = OS_TRUE; return OS_FALSE; } entry->entry = my_entry; entry->entry_cluster = cluster; entry->entry_offset = offset; return OS_TRUE; } os_u32 libfat_read(LFFile* file, void* buffer, os_u32 buffer_size) { os_u32 read = 0; os_bool eof = file->position >= file->file_entry.entry.file_size ? OS_TRUE : OS_FALSE; while(read < buffer_size && eof != OS_TRUE) { os_u32 amount_left = file->file_entry.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 = ((char*) 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.entry.file_size) { eof = OS_TRUE; } } return read; } os_u32 libfat_tell(LFFile* file) { if(file == 0) { return 0; } return file->position; } os_bool libfat_init(LFFileHandle file, void* buffer, os_u32 buffer_size, LFControlBlock* 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; } os_bool libfat_seek(LFFile* file, os_s32 position, os_u32 direction) { if (direction != LIBFAT_SEEK_CURRENT && direction != LIBFAT_SEEK_END && direction != LIBFAT_SEEK_ORIGIN) { return OS_FALSE; } if (file == 0) { return OS_FALSE; } os_u32 target = 0; os_s32 final = 0; os_s32 reverse = 0; switch(direction) { case LIBFAT_SEEK_ORIGIN: target = (os_u32)position; break; case LIBFAT_SEEK_CURRENT: final = position + file->position; if (final < 0) { return OS_FALSE; } target = (os_u32)final; break; case LIBFAT_SEEK_END: reverse = file->file_entry.entry.file_size - position; if (reverse < 0) { return OS_FALSE; } target = (os_u32)reverse; break; } if (target >= file->file_entry.entry.file_size) { return OS_FALSE; } os_u32 cluster = FAT_ENTRY_CLUSTER(file->file_entry.entry); os_u32 tmp_pos = 0; while((tmp_pos + file->fat_cluster_size) <= target) { os_u32 next_cluster = libfat_read_cluster(file->fat, cluster); tmp_pos += file->fat_cluster_size; cluster = next_cluster; } file->current_cluster = cluster; file->in_cluster_position = target - tmp_pos; file->position = target; return OS_TRUE; } os_u32 libfat_find_free_cluster(LFControlBlock* fat) { os_u32 cluster_id = 2; os_u32 cluster_value = FAT_LAST_CLUSTER_32; do { cluster_value = libfat_read_cluster(fat, cluster_id); if (cluster_value != 0) { cluster_id++; } if (cluster_id >= (fat->header.sectors_per_fat_32 * fat->header.base.bytes_per_sector) / sizeof(os_u32)) { return 0; } } while(cluster_value != 0); return cluster_id; } os_bool libfat_fsinfo_update(LFControlBlock* fat) { os_u32 fsinfo_offset = fat->header.fsinfo_sector * fat->header.base.bytes_per_sector; if(fat->handle.seek(fsinfo_offset, LIBFAT_SEEK_ORIGIN, fat->handle.user_data) != OS_TRUE) { return OS_FALSE; } os_u32 sig = 0; os_u32 read = fat->handle.read(sizeof(os_u32), (void*)&sig, fat->handle.user_data); if (read != sizeof(os_u32) || sig != FAT_FSINFO_SIG_0) { return OS_FALSE; } if(fat->handle.seek(fsinfo_offset + 484, LIBFAT_SEEK_ORIGIN, fat->handle.user_data) != OS_TRUE) { return OS_FALSE; } read = fat->handle.read(sizeof(os_u32), (void*)&sig, fat->handle.user_data); if (read != sizeof(os_u32) || sig != FAT_FSINFO_SIG_1) { return OS_FALSE; } os_u32 free_clusters = 0; read = fat->handle.read(sizeof(os_u32), (void*)&free_clusters, fat->handle.user_data); if (read != sizeof(os_u32)) { return OS_FALSE; } os_u32 next_free_cluster = 0; read = fat->handle.read(sizeof(os_u32), (void*)&next_free_cluster, fat->handle.user_data); if (read != sizeof(os_u32)) { return OS_FALSE; } if (free_clusters != 0xffffffff) { free_clusters--; if(fat->handle.seek(fsinfo_offset + 488, LIBFAT_SEEK_ORIGIN, fat->handle.user_data) == OS_TRUE) { fat->handle.write(sizeof(os_u32), (void*)&free_clusters, fat->handle.user_data); } } if (next_free_cluster != 0xffffffff) { next_free_cluster = libfat_find_free_cluster(fat); if (next_free_cluster < 2) { next_free_cluster = 0xffffffff; } if (fat->handle.seek(fsinfo_offset + 492, LIBFAT_SEEK_ORIGIN, fat->handle.user_data) == OS_TRUE) { fat->handle.write(sizeof(os_u32), (void*)&next_free_cluster, fat->handle.user_data); } } return OS_TRUE; } os_bool libfat_fsinfo_free(LFControlBlock* fat, os_u32 freed_cluster) { os_u32 fsinfo_offset = fat->header.fsinfo_sector * fat->header.base.bytes_per_sector; if(fat->handle.seek(fsinfo_offset, LIBFAT_SEEK_ORIGIN, fat->handle.user_data) != OS_TRUE) { return OS_FALSE; } os_u32 sig = 0; os_u32 read = fat->handle.read(sizeof(os_u32), (void*)&sig, fat->handle.user_data); if (read != sizeof(os_u32) || sig != FAT_FSINFO_SIG_0) { return OS_FALSE; } if(fat->handle.seek(fsinfo_offset + 484, LIBFAT_SEEK_ORIGIN, fat->handle.user_data) != OS_TRUE) { return OS_FALSE; } read = fat->handle.read(sizeof(os_u32), (void*)&sig, fat->handle.user_data); if (read != sizeof(os_u32) || sig != FAT_FSINFO_SIG_1) { return OS_FALSE; } os_u32 free_clusters = 0; read = fat->handle.read(sizeof(os_u32), (void*)&free_clusters, fat->handle.user_data); if (read != sizeof(os_u32)) { return OS_FALSE; } os_u32 next_free_cluster = 0; read = fat->handle.read(sizeof(os_u32), (void*)&next_free_cluster, fat->handle.user_data); if (read != sizeof(os_u32)) { return OS_FALSE; } if (free_clusters != 0xffffffff) { free_clusters++; if(fat->handle.seek(fsinfo_offset + 488, LIBFAT_SEEK_ORIGIN, fat->handle.user_data) == OS_TRUE) { fat->handle.write(sizeof(os_u32), (void*)&free_clusters, fat->handle.user_data); } } if (next_free_cluster != 0xffffffff && freed_cluster < next_free_cluster) { next_free_cluster = libfat_find_free_cluster(fat); if (next_free_cluster < 2) { next_free_cluster = 0xffffffff; } if (fat->handle.seek(fsinfo_offset + 492, LIBFAT_SEEK_ORIGIN, fat->handle.user_data) == OS_TRUE) { fat->handle.write(sizeof(os_u32), (void*)&next_free_cluster, fat->handle.user_data); } } return OS_TRUE; } os_bool libfat_truncate(LFControlBlock* fat, LFDirectoryEntry* entry) { if (fat == 0 || entry == 0) { return OS_FALSE; } if ((entry->entry.attribute & FAT_SUBDIRECTORY_BIT) != 0) { return OS_FALSE; //Disable truncating subdirectories } entry->entry.file_size = 0; os_u32 written = libfat_write_cluster(fat, entry->entry_cluster, &entry->entry, sizeof(FatDirectoryEntry), entry->entry_offset); if (written != sizeof(FatDirectoryEntry)) { return OS_FALSE; } os_u32 cluster = libfat_read_cluster(fat, FAT_ENTRY_CLUSTER(entry->entry)); libfat_write_fat_cluster(fat, FAT_ENTRY_CLUSTER(entry->entry), FAT_LAST_CLUSTER_32_2); while(cluster < FAT_LAST_CLUSTER_32) { os_u32 next_cluster = libfat_read_cluster(fat, cluster); libfat_write_fat_cluster(fat, cluster, 0); libfat_fsinfo_free(fat, cluster); cluster = next_cluster; } return OS_TRUE; } os_u32 libfat_add_cluster_to_chain(LFControlBlock* fat, os_u32 last_cluster_id) { os_u32 cluster_value; do { cluster_value = libfat_read_cluster(fat, last_cluster_id); if(cluster_value == 0) { return 0; } } while(cluster_value < FAT_LAST_CLUSTER_32); os_u32 free_cluster = libfat_find_free_cluster(fat); if (free_cluster == 0) { return 0; } if(libfat_write_fat_cluster(fat, last_cluster_id, free_cluster) != OS_TRUE) { return 0; } if(libfat_write_fat_cluster(fat, free_cluster, FAT_LAST_CLUSTER_32_2) != OS_TRUE) { return 0; } libfat_fsinfo_update(fat); return free_cluster; } os_bool libfat_add_entry_to_directory(LFControlBlock* fat, LFDirectoryEntry* parent, FatDirectoryEntry* entry, LFDirectoryEntry* result) { os_u32 cluster = fat->header.first_root_cluster; if (parent != 0) { cluster = FAT_ENTRY_CLUSTER(parent->entry); } os_u32 cluster_offset = 0; os_u32 next_cluster = libfat_read_cluster(fat, cluster); FatDirectoryEntry local_entry; do { os_u32 read = libfat_load_cluster(fat, cluster, (void*)&local_entry, sizeof(FatDirectoryEntry), cluster_offset); if (local_entry.file_name[0] == '\0') { break; } cluster_offset += read; if (cluster_offset >= fat->header.base.sectors_per_cluster * fat->header.base.bytes_per_sector) { cluster_offset = 0; if (next_cluster >= FAT_LAST_CLUSTER_32) { next_cluster = libfat_add_cluster_to_chain(fat, next_cluster); if (next_cluster == 0) { //Invalid end cluster or no more available clusters return OS_FALSE; } } cluster = next_cluster; next_cluster = libfat_read_cluster(fat, cluster); break; } } while(local_entry.file_name[0] != '\0'); if(libfat_write_cluster(fat, cluster, (void*)entry, sizeof(FatDirectoryEntry), cluster_offset) == 0) { return OS_FALSE; //TODO: Maybe undo added cluster } result->entry_cluster = cluster; result->entry_offset = cluster_offset; result->entry = *entry; cluster_offset += sizeof(FatDirectoryEntry); if (cluster_offset >= fat->header.base.bytes_per_sector * fat->header.base.sectors_per_cluster) { cluster = libfat_add_cluster_to_chain(fat, cluster); cluster_offset = 0; } char buffer[sizeof(FatDirectoryEntry)]; for(int i = 0; i < sizeof(FatDirectoryEntry); i++) { buffer[i] = '\0'; } libfat_write_cluster(fat, cluster, (void*)buffer, sizeof(FatDirectoryEntry), cluster_offset); return OS_TRUE; } os_bool libfat_create(LFControlBlock* fat, LFDirectoryEntry* parent_entry, os_s8* name, os_bool directory, LFDirectoryEntry* result) { FatDirectoryEntry new_entry; for(int i = 0; i < 8; i++) { new_entry.file_name[i] = name[i]; } for(int i = 0; i < 3; i++) { new_entry.extension[i] = name[8 + i]; } new_entry.attribute = directory != OS_FALSE ? FAT_SUBDIRECTORY_BIT : 0; new_entry.date = 0; for(int i = 0; i < 8; i++) { new_entry.reserved[i] = 0; } new_entry.time = 0; new_entry.file_size = 0; os_u32 cluster = libfat_find_free_cluster(fat); if (cluster < 2) { return OS_FALSE; } new_entry.start_cluster = (os_u16) cluster; new_entry.start_cluster_high = (os_u16) (cluster >> 16); if (libfat_write_fat_cluster(fat, cluster, FAT_LAST_CLUSTER_32_2) != OS_TRUE) { return OS_FALSE; } if(libfat_add_entry_to_directory(fat, parent_entry, &new_entry, result) != OS_TRUE) { libfat_write_fat_cluster(fat, cluster, 0); return OS_FALSE; } libfat_fsinfo_update(fat); return OS_TRUE; } os_u32 libfat_write(LFFile* f, void* buffer, os_u32 buffer_size) { if (f == 0 || buffer == 0 || buffer_size == 0) { return 0; } os_u32 start_position = f->position; os_u32 written = 0; while (buffer_size > 0) { os_u32 amount = f->fat_cluster_size - f->in_cluster_position; if (amount > buffer_size) { amount = buffer_size; } os_u32 w = libfat_write_cluster(f->fat, f->current_cluster, buffer, amount, f->in_cluster_position); written += w; f->position += w; f->in_cluster_position += w; buffer = ((char*)buffer) + w; buffer_size -= w; if (f->in_cluster_position >= f->fat_cluster_size) { f->in_cluster_position = 0; os_u32 next = libfat_read_cluster(f->fat, f->current_cluster); if (next >= FAT_LAST_CLUSTER_32_2) { next = libfat_add_cluster_to_chain(f->fat, next); } f->current_cluster = next; } } if(f->position > f->file_entry.entry.file_size) { f->file_entry.entry.file_size = f->position; libfat_write_cluster(f->fat, f->file_entry.entry_cluster, (void*)&f->file_entry.entry, sizeof(FatDirectoryEntry), f->file_entry.entry_offset); } return written; } os_u32 libfat_get_true_entry_offset(LFControlBlock* fat, LFDirectoryEntry* entry) { if (fat == 0 || entry == 0) { return 0; } 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; return data_offset + (cluster_size * FAT_ENTRY_CLUSTER(entry->entry) - 2); } os_bool libfat_test_mbr(LFFileHandle* mbr) { if (mbr == 0) { return OS_FALSE; } if(mbr->seek(0, LIBFAT_SEEK_ORIGIN, mbr->user_data) != OS_TRUE) { return OS_FALSE; } char buffer[6]; os_u32 read = mbr->read(6, buffer, mbr->user_data); if (read < 6) { return OS_FALSE; } return (buffer[2] != 0x49 && buffer[3] == 0x49) ? OS_TRUE : OS_FALSE; } /* void libfat_test(LFFileHandle handle, PrintRoutine print, PrintNumber printNumber) { LFControlBlock cb; if (libfat_init(handle, loaded_fat_segment, 512 * sizeof(os_u32), &cb) != OS_TRUE) { print("Failed to init FAT.", 0); return; } LFDirectory dir; if (libfat_open_directory(&cb, 0, &dir) != OS_TRUE) { print("Failecd to open directory.", 0); return; } os_bool any = OS_FALSE; LFDirectoryEntry entry; while(libfat_read_directory(&dir, &entry) == OS_TRUE) { if ((entry.entry.attribute & (os_s8)FAT_HIDDEN_BIT) != 0 || (entry.entry.attribute & (os_s8)FAT_VOLUME_BIT) != 0 || (entry.entry.attribute & (os_s8)FAT_SYSTEM_BIT) != 0) { continue; } any = OS_TRUE; print("Entry name: ", 0); print(entry.entry.file_name, 11); os_u32 cluster = FAT_ENTRY_CLUSTER(entry.entry); print("Cluster: ", 0); printNumber(cluster); print("Size: ", 0); printNumber(entry.entry.file_size); os_u32 effective_size = entry.entry.file_size > 512 ? 512 : entry.entry.file_size; if(effective_size > 0) { LFFile f; if (libfat_open(&cb, &entry, &f) == OS_TRUE) { char buffer[512]; os_u32 amount = libfat_read(&f, buffer, 512); print("Content: ", 0); print(buffer, amount); } } print("--------", 0); } if(any == OS_FALSE) { LFDirectoryEntry created_file; libfat_create(&cb, 0, "TEST TXT", OS_FALSE, &created_file); print("Added file 'test.txt'", 0); LFFile new_file; if(libfat_open(&cb, &created_file, &new_file) != OS_TRUE) { print("Failed to open new file", 0); return; } char* data = "test"; libfat_write(&new_file, data, 5); } } */