|
|
|
@ -5,6 +5,7 @@ |
|
|
|
#include "src/kernel/stream.h" |
|
|
|
#include "src/kernel/stream.h" |
|
|
|
#include "src/lib/memory.h" |
|
|
|
#include "src/lib/memory.h" |
|
|
|
#include "src/lib/string.h" |
|
|
|
#include "src/lib/string.h" |
|
|
|
|
|
|
|
#include "src/lib/syscall.h" |
|
|
|
#include "src/lib/util.h" |
|
|
|
#include "src/lib/util.h" |
|
|
|
|
|
|
|
|
|
|
|
#define SECTOR_SIZE 512 |
|
|
|
#define SECTOR_SIZE 512 |
|
|
|
@ -179,35 +180,34 @@ static void flush_fat() { |
|
|
|
ata_write_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors, (uint8_t)bpb.sectors_per_fat, fat); |
|
|
|
ata_write_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors, (uint8_t)bpb.sectors_per_fat, fat); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static fat16_dir_entry_t *read_directory(uint16_t dir_cluster) { |
|
|
|
static uint16_t read_directory(uint16_t dir_cluster, fat16_dir_entry_t **entries) { |
|
|
|
fat16_dir_entry_t *entries; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!dir_cluster) { |
|
|
|
if (!dir_cluster) { |
|
|
|
uint8_t sectors = (uint8_t)((sizeof(fat16_dir_entry_t) * bpb.root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE); |
|
|
|
uint8_t sectors = (uint8_t)((sizeof(fat16_dir_entry_t) * bpb.root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE); |
|
|
|
entries = memory_allocate(sectors * SECTOR_SIZE + sizeof(fat16_dir_entry_t)); // One extra as null terminator.
|
|
|
|
*entries = memory_allocate(sectors * SECTOR_SIZE); |
|
|
|
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.fats_count * bpb.sectors_per_fat, sectors, entries); |
|
|
|
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.fats_count * bpb.sectors_per_fat, sectors, *entries); |
|
|
|
|
|
|
|
return bpb.root_entry_count; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
ensure_fat(); |
|
|
|
ensure_fat(); |
|
|
|
|
|
|
|
|
|
|
|
uint16_t next_cluster = dir_cluster; |
|
|
|
uint16_t next_cluster = dir_cluster; |
|
|
|
uint32_t cluster_count = 0; |
|
|
|
uint16_t cluster_count = 0; |
|
|
|
while (next_cluster < 0xFFF8) { |
|
|
|
while (next_cluster < 0xFFF8) { |
|
|
|
cluster_count++; |
|
|
|
cluster_count++; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
} |
|
|
|
} |
|
|
|
entries = |
|
|
|
*entries = memory_allocate(cluster_count * bpb.sectors_per_cluster * SECTOR_SIZE); |
|
|
|
memory_allocate(cluster_count * bpb.sectors_per_cluster * SECTOR_SIZE + sizeof(fat16_dir_entry_t)); // One extra as null terminator.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t *chunk = (uint8_t *)entries; |
|
|
|
uint8_t *chunk = (uint8_t *)*entries; |
|
|
|
next_cluster = dir_cluster; |
|
|
|
next_cluster = dir_cluster; |
|
|
|
while (next_cluster < 0xFFF8) { |
|
|
|
while (next_cluster < 0xFFF8) { |
|
|
|
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, chunk); |
|
|
|
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, chunk); |
|
|
|
chunk += bpb.sectors_per_cluster * SECTOR_SIZE; |
|
|
|
chunk += bpb.sectors_per_cluster * SECTOR_SIZE; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return cluster_count * bpb.sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return entries; |
|
|
|
return (uint64_t)-1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static fs_node_t *open_entry(uint16_t dir_cluster, const fat16_dir_entry_t *entries, uint16_t index) { |
|
|
|
static fs_node_t *open_entry(uint16_t dir_cluster, const fat16_dir_entry_t *entries, uint16_t index) { |
|
|
|
@ -233,37 +233,47 @@ static fs_node_t *open_entry(uint16_t dir_cluster, const fat16_dir_entry_t *entr |
|
|
|
return (fs_node_t *)result; |
|
|
|
return (fs_node_t *)result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void write_directory(uint16_t dir_cluster, const fat16_dir_entry_t *entries) { |
|
|
|
static void write_directory(uint16_t dir_cluster, const fat16_dir_entry_t *entries, uint16_t count) { |
|
|
|
|
|
|
|
ASSERT((count * sizeof(fat16_dir_entry_t)) % (bpb.sectors_per_cluster * SECTOR_SIZE) == 0, |
|
|
|
|
|
|
|
"write_directory: entries must be aligned to clusters"); |
|
|
|
|
|
|
|
|
|
|
|
if (!dir_cluster) { |
|
|
|
if (!dir_cluster) { |
|
|
|
ata_write_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.fats_count * bpb.sectors_per_fat, |
|
|
|
ata_write_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.fats_count * bpb.sectors_per_fat, |
|
|
|
(uint8_t)((sizeof(fat16_dir_entry_t) * bpb.root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE), entries); |
|
|
|
(uint8_t)((sizeof(fat16_dir_entry_t) * bpb.root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE), entries); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
ensure_fat(); |
|
|
|
ensure_fat(); |
|
|
|
|
|
|
|
|
|
|
|
// Assuming no entries were added or removed.
|
|
|
|
|
|
|
|
uint8_t *chunk = (uint8_t *)entries; |
|
|
|
uint8_t *chunk = (uint8_t *)entries; |
|
|
|
uint16_t next_cluster = dir_cluster; |
|
|
|
uint16_t next_cluster = dir_cluster; |
|
|
|
while (next_cluster < 0xFFF8) { |
|
|
|
while (count) { |
|
|
|
ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, chunk); |
|
|
|
ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, chunk); |
|
|
|
chunk += bpb.sectors_per_cluster * SECTOR_SIZE; |
|
|
|
chunk += bpb.sectors_per_cluster * SECTOR_SIZE; |
|
|
|
|
|
|
|
count -= bpb.sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t); |
|
|
|
|
|
|
|
if (count && fat[next_cluster] >= 0xFFF8) { |
|
|
|
|
|
|
|
fat[next_cluster] = allocate_cluster(); |
|
|
|
|
|
|
|
} |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
flush_fat(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name) { |
|
|
|
fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name, uint64_t flags) { |
|
|
|
if (directory->type != FAT16 || !directory->is_dir) { |
|
|
|
if (directory->type != FAT16 || !directory->is_dir) { |
|
|
|
return NUL; |
|
|
|
return NUL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t dir_cluster = ((fat16_node_t *)directory)->inode->first_cluster; |
|
|
|
|
|
|
|
|
|
|
|
char name_8_3[12]; |
|
|
|
char name_8_3[12]; |
|
|
|
to_8_3(name, name_8_3); |
|
|
|
to_8_3(name, name_8_3); |
|
|
|
|
|
|
|
|
|
|
|
fat16_dir_entry_t *entries = read_directory(((fat16_node_t *)directory)->inode->first_cluster); |
|
|
|
fat16_dir_entry_t *entries; |
|
|
|
|
|
|
|
uint16_t entries_count = read_directory(dir_cluster, &entries); |
|
|
|
|
|
|
|
|
|
|
|
fat16_dir_entry_t *entry = entries; |
|
|
|
fat16_dir_entry_t *entry = entries; |
|
|
|
uint16_t index = 0; |
|
|
|
uint16_t index = 0; |
|
|
|
while (entry->name[0]) { |
|
|
|
while (index < entries_count && entry->name[0]) { |
|
|
|
if ((uint8_t)entry->name[0] != 0xE5 && (uint8_t)entry->attributes != 0x0F && bytes_equal(name_8_3, (char *)entry, 11)) { |
|
|
|
if ((uint8_t)entry->name[0] != 0xE5 && (uint8_t)entry->attributes != 0x0F && bytes_equal(name_8_3, (char *)entry, 11)) { |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -271,20 +281,82 @@ fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name) { |
|
|
|
index++; |
|
|
|
index++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fs_node_t *result = open_entry(((fat16_node_t *)directory)->inode->first_cluster, entries, index); |
|
|
|
fs_node_t *result = open_entry(dir_cluster, entries, index); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (result && (flags & OPEN_EXCLUSIVE)) { |
|
|
|
|
|
|
|
memory_free(entries); |
|
|
|
|
|
|
|
return NUL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!result && (flags & OPEN_CREATE)) { |
|
|
|
|
|
|
|
index = 0; |
|
|
|
|
|
|
|
while (index < entries_count && entries[index].name[0]) { |
|
|
|
|
|
|
|
index++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (index >= entries_count) { |
|
|
|
|
|
|
|
if (!dir_cluster) { |
|
|
|
|
|
|
|
memory_free(entries); |
|
|
|
|
|
|
|
return NUL; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
uint16_t new_entries_count = entries_count + bpb.sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t); |
|
|
|
|
|
|
|
fat16_dir_entry_t *new_entries = memory_allocate(new_entries_count * sizeof(fat16_dir_entry_t)); |
|
|
|
|
|
|
|
memory_copy(entries, entries_count * sizeof(fat16_dir_entry_t), new_entries); |
|
|
|
|
|
|
|
memory_free(entries); |
|
|
|
|
|
|
|
entries_count = new_entries_count; |
|
|
|
|
|
|
|
entries = new_entries; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
memory_copy(name_8_3, 11, &entries[index]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (flags & OPEN_DIRECTORY && !(flags & OPEN_FILE)) { |
|
|
|
|
|
|
|
entries[index].attributes = ATTRIBUTE_SUBDIRECTORY; |
|
|
|
|
|
|
|
entries[index].first_cluster = allocate_cluster(); |
|
|
|
|
|
|
|
fat16_dir_entry_t *inner_entries = memory_allocate(bpb.sectors_per_cluster * SECTOR_SIZE); |
|
|
|
|
|
|
|
memory_copy(". ", 11, inner_entries[0].name); |
|
|
|
|
|
|
|
inner_entries[0].attributes = ATTRIBUTE_SUBDIRECTORY; |
|
|
|
|
|
|
|
inner_entries[0].first_cluster = entries[index].first_cluster; |
|
|
|
|
|
|
|
memory_copy(".. ", 11, inner_entries[1].name); |
|
|
|
|
|
|
|
inner_entries[1].attributes = ATTRIBUTE_SUBDIRECTORY; |
|
|
|
|
|
|
|
inner_entries[1].first_cluster = dir_cluster; |
|
|
|
|
|
|
|
write_directory(entries[index].first_cluster, inner_entries, bpb.sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t)); |
|
|
|
|
|
|
|
memory_free(inner_entries); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
write_directory(dir_cluster, entries, entries_count); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result = open_entry(dir_cluster, entries, index); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
memory_free(entries); |
|
|
|
memory_free(entries); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!result) { |
|
|
|
|
|
|
|
return NUL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (result->is_dir && !(flags & OPEN_DIRECTORY)) { |
|
|
|
|
|
|
|
return NUL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!result->is_dir && !(flags & OPEN_FILE)) { |
|
|
|
|
|
|
|
return NUL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fs_node_t *fat16_open_at(const fs_node_t *directory, uint64_t index) { |
|
|
|
fs_node_t *fat16_open_at(const fs_node_t *directory, uint16_t index, uint64_t flags) { |
|
|
|
if (directory->type != FAT16 || !directory->is_dir) { |
|
|
|
if (directory->type != FAT16 || !directory->is_dir) { |
|
|
|
return NUL; |
|
|
|
return NUL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fat16_dir_entry_t *entries = read_directory(((fat16_node_t *)directory)->inode->first_cluster); |
|
|
|
uint16_t dir_cluster = ((fat16_node_t *)directory)->inode->first_cluster; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fat16_dir_entry_t *entries; |
|
|
|
|
|
|
|
uint16_t entries_count = read_directory(dir_cluster, &entries); |
|
|
|
|
|
|
|
|
|
|
|
uint16_t ei = 0, vi = 0; |
|
|
|
uint16_t ei = 0, vi = 0; |
|
|
|
while (entries[ei].name[0]) { |
|
|
|
while (ei < entries_count && entries[ei].name[0]) { |
|
|
|
if ((uint8_t)entries[ei].name[0] != 0xE5 && (uint8_t)entries[ei].attributes != 0x0F) { |
|
|
|
if ((uint8_t)entries[ei].name[0] != 0xE5 && (uint8_t)entries[ei].attributes != 0x0F) { |
|
|
|
if (vi == index) { |
|
|
|
if (vi == index) { |
|
|
|
break; |
|
|
|
break; |
|
|
|
@ -295,7 +367,25 @@ fs_node_t *fat16_open_at(const fs_node_t *directory, uint64_t index) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fs_node_t *result = open_entry(((fat16_node_t *)directory)->inode->first_cluster, entries, ei); |
|
|
|
fs_node_t *result = open_entry(((fat16_node_t *)directory)->inode->first_cluster, entries, ei); |
|
|
|
|
|
|
|
|
|
|
|
memory_free(entries); |
|
|
|
memory_free(entries); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (result && (flags & OPEN_EXCLUSIVE)) { |
|
|
|
|
|
|
|
return NUL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!result) { |
|
|
|
|
|
|
|
return NUL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (result->is_dir && !(flags & OPEN_DIRECTORY)) { |
|
|
|
|
|
|
|
return NUL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!result->is_dir && !(flags & OPEN_FILE)) { |
|
|
|
|
|
|
|
return NUL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -432,10 +522,11 @@ uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_ |
|
|
|
if (offset + written > fat_file->inode->size) { |
|
|
|
if (offset + written > fat_file->inode->size) { |
|
|
|
fat_file->inode->size = offset + written; |
|
|
|
fat_file->inode->size = offset + written; |
|
|
|
|
|
|
|
|
|
|
|
fat16_dir_entry_t *entries = read_directory(fat_file->inode->dir_cluster); |
|
|
|
fat16_dir_entry_t *entries; |
|
|
|
|
|
|
|
uint16_t entries_count = read_directory(fat_file->inode->dir_cluster, &entries); |
|
|
|
entries[fat_file->inode->dir_index].first_cluster = fat_file->inode->first_cluster; |
|
|
|
entries[fat_file->inode->dir_index].first_cluster = fat_file->inode->first_cluster; |
|
|
|
entries[fat_file->inode->dir_index].size = fat_file->inode->size; |
|
|
|
entries[fat_file->inode->dir_index].size = fat_file->inode->size; |
|
|
|
write_directory(fat_file->inode->dir_cluster, entries); |
|
|
|
write_directory(fat_file->inode->dir_cluster, entries, entries_count); |
|
|
|
memory_free(entries); |
|
|
|
memory_free(entries); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -482,10 +573,11 @@ uint64_t fat16_truncate(fs_node_t *file, uint32_t size) { |
|
|
|
flush_fat(); |
|
|
|
flush_fat(); |
|
|
|
|
|
|
|
|
|
|
|
fat_file->inode->size = size; |
|
|
|
fat_file->inode->size = size; |
|
|
|
fat16_dir_entry_t *entries = read_directory(fat_file->inode->dir_cluster); |
|
|
|
fat16_dir_entry_t *entries; |
|
|
|
|
|
|
|
uint16_t entries_count = read_directory(fat_file->inode->dir_cluster, &entries); |
|
|
|
entries[fat_file->inode->dir_index].first_cluster = fat_file->inode->first_cluster; |
|
|
|
entries[fat_file->inode->dir_index].first_cluster = fat_file->inode->first_cluster; |
|
|
|
entries[fat_file->inode->dir_index].size = fat_file->inode->size; |
|
|
|
entries[fat_file->inode->dir_index].size = fat_file->inode->size; |
|
|
|
write_directory(fat_file->inode->dir_cluster, entries); |
|
|
|
write_directory(fat_file->inode->dir_cluster, entries, entries_count); |
|
|
|
memory_free(entries); |
|
|
|
memory_free(entries); |
|
|
|
|
|
|
|
|
|
|
|
return size; |
|
|
|
return size; |
|
|
|
@ -535,7 +627,7 @@ static void file_stream_close(stream_t *self) { |
|
|
|
typedef struct { |
|
|
|
typedef struct { |
|
|
|
stream_t stream; |
|
|
|
stream_t stream; |
|
|
|
fs_node_t *node; |
|
|
|
fs_node_t *node; |
|
|
|
uint32_t index; |
|
|
|
uint16_t index; |
|
|
|
} fat16_directory_stream_t; |
|
|
|
} fat16_directory_stream_t; |
|
|
|
|
|
|
|
|
|
|
|
static uint64_t directory_stream_write(__attribute__((unused)) stream_t *self, __attribute__((unused)) const char *from, |
|
|
|
static uint64_t directory_stream_write(__attribute__((unused)) stream_t *self, __attribute__((unused)) const char *from, |
|
|
|
@ -545,7 +637,7 @@ static uint64_t directory_stream_write(__attribute__((unused)) stream_t *self, _ |
|
|
|
|
|
|
|
|
|
|
|
static uint64_t directory_stream_read(stream_t *self, uint64_t max, char *to) { |
|
|
|
static uint64_t directory_stream_read(stream_t *self, uint64_t max, char *to) { |
|
|
|
fat16_directory_stream_t *fds = (fat16_directory_stream_t *)self; |
|
|
|
fat16_directory_stream_t *fds = (fat16_directory_stream_t *)self; |
|
|
|
fs_node_t *node = fat16_open_at(fds->node, fds->index++); |
|
|
|
fs_node_t *node = fat16_open_at(fds->node, fds->index++, OPEN_FILE | OPEN_DIRECTORY); |
|
|
|
if (!node) { |
|
|
|
if (!node) { |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|