Add file and directory creation, mkdir
This commit is contained in:
+118
-26
@@ -5,6 +5,7 @@
|
||||
#include "src/kernel/stream.h"
|
||||
#include "src/lib/memory.h"
|
||||
#include "src/lib/string.h"
|
||||
#include "src/lib/syscall.h"
|
||||
#include "src/lib/util.h"
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
static fat16_dir_entry_t *read_directory(uint16_t dir_cluster) {
|
||||
fat16_dir_entry_t *entries;
|
||||
|
||||
static uint16_t read_directory(uint16_t dir_cluster, fat16_dir_entry_t **entries) {
|
||||
if (!dir_cluster) {
|
||||
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.
|
||||
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.fats_count * bpb.sectors_per_fat, sectors, entries);
|
||||
*entries = memory_allocate(sectors * SECTOR_SIZE);
|
||||
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.fats_count * bpb.sectors_per_fat, sectors, *entries);
|
||||
return bpb.root_entry_count;
|
||||
} else {
|
||||
ensure_fat();
|
||||
|
||||
uint16_t next_cluster = dir_cluster;
|
||||
uint32_t cluster_count = 0;
|
||||
uint16_t cluster_count = 0;
|
||||
while (next_cluster < 0xFFF8) {
|
||||
cluster_count++;
|
||||
next_cluster = fat[next_cluster];
|
||||
}
|
||||
entries =
|
||||
memory_allocate(cluster_count * bpb.sectors_per_cluster * SECTOR_SIZE + sizeof(fat16_dir_entry_t)); // One extra as null terminator.
|
||||
*entries = memory_allocate(cluster_count * bpb.sectors_per_cluster * SECTOR_SIZE);
|
||||
|
||||
uint8_t *chunk = (uint8_t *)entries;
|
||||
uint8_t *chunk = (uint8_t *)*entries;
|
||||
next_cluster = dir_cluster;
|
||||
while (next_cluster < 0xFFF8) {
|
||||
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, chunk);
|
||||
chunk += bpb.sectors_per_cluster * SECTOR_SIZE;
|
||||
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) {
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
} else {
|
||||
ensure_fat();
|
||||
|
||||
// Assuming no entries were added or removed.
|
||||
uint8_t *chunk = (uint8_t *)entries;
|
||||
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);
|
||||
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];
|
||||
}
|
||||
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) {
|
||||
return NUL;
|
||||
}
|
||||
|
||||
uint16_t dir_cluster = ((fat16_node_t *)directory)->inode->first_cluster;
|
||||
|
||||
char name_8_3[12];
|
||||
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;
|
||||
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)) {
|
||||
break;
|
||||
}
|
||||
@@ -271,20 +281,82 @@ fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name) {
|
||||
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);
|
||||
|
||||
if (!result) {
|
||||
return NUL;
|
||||
}
|
||||
|
||||
if (result->is_dir && !(flags & OPEN_DIRECTORY)) {
|
||||
return NUL;
|
||||
}
|
||||
|
||||
if (!result->is_dir && !(flags & OPEN_FILE)) {
|
||||
return NUL;
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
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 (vi == index) {
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
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].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);
|
||||
}
|
||||
|
||||
@@ -482,10 +573,11 @@ uint64_t fat16_truncate(fs_node_t *file, uint32_t size) {
|
||||
flush_fat();
|
||||
|
||||
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].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);
|
||||
|
||||
return size;
|
||||
@@ -535,7 +627,7 @@ static void file_stream_close(stream_t *self) {
|
||||
typedef struct {
|
||||
stream_t stream;
|
||||
fs_node_t *node;
|
||||
uint32_t index;
|
||||
uint16_t index;
|
||||
} fat16_directory_stream_t;
|
||||
|
||||
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) {
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user