summaryrefslogtreecommitdiff
path: root/src/kernel/fat.c
diff options
context:
space:
mode:
authorBenji Dial <Benji3.141@gmail.com>2020-08-13 23:59:14 -0400
committerBenji Dial <Benji3.141@gmail.com>2020-08-13 23:59:14 -0400
commit7ff724fe8f709440da9c730fdb8dcbaa4f989ed5 (patch)
treee7f768ff56798bef3edc166a30e9cb8d7f25bd1e /src/kernel/fat.c
parent2ddbeb9f7214f6d3feef651eba83e6a9d120a743 (diff)
downloadportland-os-7ff724fe8f709440da9c730fdb8dcbaa4f989ed5.tar.gz
FAT16 directory enumeration, making many functions static, new 'log' functions to wrap vga and serial
Diffstat (limited to 'src/kernel/fat.c')
-rw-r--r--src/kernel/fat.c221
1 files changed, 190 insertions, 31 deletions
diff --git a/src/kernel/fat.c b/src/kernel/fat.c
index 807af00..ff01d7d 100644
--- a/src/kernel/fat.c
+++ b/src/kernel/fat.c
@@ -8,6 +8,9 @@
#define MAX_FAT_DRIVES 16
#define MAX_OPEN_FILES_PER_DRIVE 32
+#define PATH_SEP_CHAR '/'
+#define EXT_SEP_CHAR '.'
+
enum {
FA_READ_ONLY = 0x01,
FA_HIDDEN = 0x02,
@@ -59,33 +62,44 @@ struct fat_info {
#define CTOS(c, fdi) ((fdi)->data_start + (c) - 2)
+struct open_file_info {
+ //directory entry is the di_number'th entry in the di_sector'th sector
+ //di_sector of 0 indicates an unused handle
+ uint32_t di_sector;
+ uint8_t di_number;
+
+ uint16_t start_cluster;
+ uint32_t length;
+};
+
struct fat_drive_info {
const struct fat_info *fi;
uint16_t *fat;
uint16_t root_start;
uint16_t data_start;
- struct directory_entry open_files[MAX_OPEN_FILES_PER_DRIVE];
+ struct open_file_info open_files[MAX_OPEN_FILES_PER_DRIVE];
};
-struct fat_drive_info infos[MAX_FAT_DRIVES];
-uint8_t next_id = 0;
+static struct fat_drive_info infos[MAX_FAT_DRIVES];
+static uint8_t next_id = 0;
-uint8_t fat_driver_buffer[512];
-struct fat_info *next_fi;
+static uint8_t fat_driver_buffer[512];
+static struct fat_info *next_fi;
-void alloc_next_fi() {
+static void alloc_next_fi() {
if (!((uint32_t)(next_fi = (struct fat_info *)((uint32_t)next_fi + 64)) & 0xfff))
if (!(next_fi = allocate_pages(1)))
panic("Out of memory in FAT driver.");
}
-const struct drive *cur_drive;
-fs_id_t cur_id;
-const struct fat_drive_info *cur_fdi;
-struct directory_entry *cur_dir;
+static const struct drive *cur_drive;
+static fs_id_t cur_id;
+static const struct fat_drive_info *cur_fdi;
+static struct directory_entry *cur_dir;
+static uint32_t cur_sect;
//loads cluster `c`
-void load_cluster(uint16_t c, void *to) {
+static void load_cluster(uint16_t c, void *to) {
if (c == 0) {
*(uint8_t *)to = 0;
return;
@@ -95,26 +109,29 @@ void load_cluster(uint16_t c, void *to) {
cur_drive->read_sectors(cur_drive, s, 1, to);
}
-uint16_t next_cluster(uint16_t c) {
+static uint16_t next_cluster(uint16_t c) {
panic("TODO: compute next sector (or 0 for none)");
}
+static const uint8_t this_dir[] = {'.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
+static const uint8_t parent_dir[] = {'.', '.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
+
static inline bool check_fat_names(const uint8_t *a, const uint8_t *b) {
return (((uint32_t *)a)[0] == ((uint32_t *)b)[0]) &&
(((uint32_t *)a)[1] == ((uint32_t *)b)[1]) &&
- (((uint16_t *)a)[8] == ((uint16_t *)b)[8]) &&
+ (((uint16_t *)a)[4] == ((uint16_t *)b)[4]) &&
(((uint8_t *)a)[10] == ((uint8_t *)b)[10]);
}
//after: cur_dir -> specified entry in root
-bool try_locate_root_entry(const uint8_t *fat_name) {
- uint32_t cur_dir_sect = cur_fdi->root_start - 1;
+static bool try_locate_root_entry(const uint8_t *fat_name) {
+ cur_sect = cur_fdi->root_start - 1;
cur_dir = (struct directory_entry *)(fat_driver_buffer + 512);
while (true) {
if (cur_dir == (struct directory_entry *)(fat_driver_buffer + 512)) {
cur_dir = (struct directory_entry *)fat_driver_buffer;
- ++cur_dir_sect;
- cur_drive->read_sectors(cur_drive, cur_dir_sect, 1, cur_dir);
+ ++cur_sect;
+ cur_drive->read_sectors(cur_drive, cur_sect, 1, cur_dir);
}
if (!*(uint8_t *)cur_dir)
return false;
@@ -127,53 +144,109 @@ bool try_locate_root_entry(const uint8_t *fat_name) {
//before: cur_dir -> entry of dir to search
//after: cur_dir -> specified entry in dir
-bool try_locate_entry(const uint8_t *fat_name) {
+static bool try_locate_entry(const uint8_t *fat_name) {
uint16_t cur_dir_cluster = cur_dir->first_cluster;
load_cluster(cur_dir_cluster, fat_driver_buffer);
cur_dir = (struct directory_entry *)fat_driver_buffer;
while (true) {
if (cur_dir == (struct directory_entry *)(fat_driver_buffer + 512)) {
cur_dir = (struct directory_entry *)fat_driver_buffer;
- ++cur_dir_cluster;
load_cluster(cur_dir_cluster = next_cluster(cur_dir_cluster), fat_driver_buffer);
}
if (!*(uint8_t *)cur_dir)
return false;
- if (check_fat_names(cur_dir -> name, fat_name))
+ if (check_fat_names(cur_dir->name, fat_name)) {
+ cur_sect = CTOS(cur_dir_cluster, cur_fdi);
return true;
+ }
else
++cur_dir;
}
}
-drive_file_id_t fat_get_file(const struct drive *d, const char *path) {
+//puts first path component's fat name into fat_name_buffer,
+//returns rest of path
+static const char *split_path(const char *path, uint8_t *fat_name_buffer) {
+ uint8_t pi = 0, fi = 0;
+ while (1) {
+ if ((path[pi] == PATH_SEP_CHAR) || !path[pi]) {
+ while (fi != 11)
+ fat_name_buffer[fi++] = (uint8_t)' ';
+ return path + (path[pi] ? pi + 1 : pi);
+ }
+ if (path[pi] == EXT_SEP_CHAR)
+ if (fi <= 8) {
+ while (fi != 8)
+ fat_name_buffer[fi++] = (uint8_t)' ';
+ ++pi;
+ }
+ else
+ panic("Bad path in FAT16 driver");
+ else if ((fi == 8) || (fi == 11))
+ panic("Bad path in FAT16 driver");
+ else {
+ fat_name_buffer[fi++] = (uint8_t)path[pi++];
+ }
+ }
+}
+
+//cur_dir -> specified entry
+static bool try_load_from_path(const struct drive *d, const char *path) {
cur_drive = d;
cur_id = d->drive_id;
cur_fdi = &infos[cur_id];
- const struct directory_entry *open_files = cur_fdi->open_files - 1;
+
+ uint8_t fat_name[11];
+ path = split_path(path, fat_name);
+ if (!try_locate_root_entry(fat_name))
+ return false;
+ while (*path) {
+ path = split_path(path, fat_name);
+ if (!try_locate_entry(fat_name))
+ return false;
+ }
+
+ return true;
+}
+
+static drive_file_id_t fat_get_file(const struct drive *d, const char *path) {
+ struct open_file_info *open_files = infos[d->drive_id].open_files - 1;
for (drive_file_id_t n = 1; n != MAX_OPEN_FILES_PER_DRIVE + 1; ++n)
- if (!*(uint8_t *)(&open_files[n])) {
- panic("TODO: open path into open_files[n]");
+ if (!open_files[n].di_sector) {
+ if (!try_load_from_path(d, path))
+ return 0;
+
+ open_files[n].di_sector = cur_sect;
+ open_files[n].di_number = cur_dir - (struct directory_entry *)fat_driver_buffer;
+ open_files[n].start_cluster = cur_dir->first_cluster;
+ open_files[n].length = cur_dir->length;
return n;
}
+
panic("Maximum number of files open reached for FAT drive.");
}
-void fat_free_file(const struct drive *d, drive_file_id_t fid) {
- *(uint8_t *)(&infos[d->drive_id].open_files[fid - 1]) = 0;
+static void fat_free_file(const struct drive *d, drive_file_id_t fid) {
+ infos[d->drive_id].open_files[fid - 1].di_sector = 0;
}
-void fat_load_sector(const struct drive *d, drive_file_id_t fid, uint32_t sector, void *at) {
+static void fat_load_sector(const struct drive *d, drive_file_id_t fid, uint32_t sector, void *at) {
cur_drive = d;
cur_id = d->drive_id;
cur_fdi = &infos[cur_id];
- uint16_t c = cur_fdi->open_files[fid - 1].first_cluster;
+ uint16_t c = cur_fdi->open_files[fid - 1].start_cluster;
for (uint32_t i = 0; i < sector; ++i)
c = next_cluster(c);
load_cluster(c, at);
}
-__attribute__ ((pure)) uint32_t fat_get_free_sectors(const struct drive *d) {
+__attribute__ ((pure))
+static uint32_t fat_get_file_length(const struct drive *d, drive_file_id_t fid) {
+ return infos[d->drive_id].open_files[fid - 1].length;
+}
+
+__attribute__ ((pure))
+static uint32_t fat_get_free_sectors(const struct drive *d) {
uint16_t *start = infos[d->fs_id].fat + 2;
uint16_t *end = start + d->n_sectors - infos[d->fs_id].data_start;
uint32_t count = 0;
@@ -183,6 +256,90 @@ __attribute__ ((pure)) uint32_t fat_get_free_sectors(const struct drive *d) {
return count;
}
+static void fat_name_to_path(const uint8_t *fat_name, char *path) {
+ uint8_t last_visible = -1;
+ for (uint8_t i = 0; i < 8; ++i) {
+ if (fat_name[i] != (uint8_t)' ')
+ last_visible = i;
+ path[i] = (char)fat_name[i];
+ }
+
+ if (fat_name[8] || fat_name[9] || fat_name[10]) {
+ path[last_visible + 1] = EXT_SEP_CHAR;
+ for (uint8_t fi = 8, ti = last_visible + 2; fi < 11; ++fi, ++ti) {
+ if (fat_name[fi] != (uint8_t)' ')
+ last_visible = ti;
+ path[ti] = (char)fat_name[fi];
+ }
+ }
+
+ path[last_visible + 1] = '\0';
+}
+
+static uint32_t enumerate_root(const struct drive *d, struct directory_content_info *info, uint32_t max) {
+ uint32_t sect = infos[d->drive_id].root_start - 1;
+ struct directory_entry *entry = (struct directory_entry *)(fat_driver_buffer + 512);
+ struct directory_content_info *fill = info;
+
+ while (true) {
+ if (entry == (struct directory_entry *)(fat_driver_buffer + 512)) {
+ entry = (struct directory_entry *)fat_driver_buffer;
+ ++sect;
+ d->read_sectors(d, sect, 1, entry);
+ }
+
+ if (!*(uint8_t *)entry || (info == fill + max))
+ return fill - info;
+
+ if (entry-> attrib & FA_LABEL) {
+ ++entry;
+ continue;
+ }
+
+ fill->is_dir = entry->attrib & FA_DIRECTORY;
+ fill->size = entry->length;
+ fat_name_to_path(entry->name, fill->name);
+
+ ++entry;
+ ++fill;
+ }
+}
+
+static uint32_t fat_enumerate_dir(const struct drive *d, const char *path, struct directory_content_info *info, uint32_t max) {
+ if (!*path)
+ return enumerate_root(d, info, max);
+
+ if (!try_load_from_path(d, path))
+ return 0;
+
+ uint16_t cluster = cur_dir->first_cluster;
+ load_cluster(cluster, fat_driver_buffer);
+ struct directory_entry *entry = (struct directory_entry *)fat_driver_buffer;
+ struct directory_content_info *fill = info;
+
+ while (true) {
+ if (entry == (struct directory_entry *)(fat_driver_buffer + 512)) {
+ entry = (struct directory_entry *)fat_driver_buffer;
+ load_cluster(cluster = next_cluster(cluster), fat_driver_buffer);
+ }
+
+ if (!*(uint8_t *)entry || (fill == info + max))
+ return fill - info;
+
+ if (check_fat_names(entry->name, this_dir) || check_fat_names(entry->name, parent_dir)) {
+ ++entry;
+ continue;
+ }
+
+ fill->is_dir = entry->attrib & FA_DIRECTORY;
+ fill->size = entry->length;
+ fat_name_to_path(entry->name, fill->name);
+
+ ++entry;
+ ++fill;
+ }
+}
+
void init_fat() {
next_fi = allocate_pages(1);
}
@@ -203,6 +360,8 @@ bool try_fat_init_drive(struct drive *d) {
d->get_file = &fat_get_file;
d->free_file = &fat_free_file;
d->load_sector = &fat_load_sector;
+ d->get_file_length = &fat_get_file_length;
+ d->enumerate_dir = &fat_enumerate_dir;
d->get_free_sectors = &fat_get_free_sectors;
d->fs_id = next_id;
@@ -214,9 +373,9 @@ bool try_fat_init_drive(struct drive *d) {
((next_fi->root_entries - 1) >> 4) + 1;
d->read_sectors(d, next_fi->reserved_sectors, next_fi->sectors_per_fat, infos[next_id].fat);
- struct directory_entry *open_files = infos[next_id].open_files - 1;
+ struct open_file_info *open_files = infos[next_id].open_files - 1;
for (drive_file_id_t i = 0; i < MAX_OPEN_FILES_PER_DRIVE; ++i)
- *(uint8_t *)&open_files[i] = 0;
+ open_files[i].di_sector = 0;
alloc_next_fi();
++next_id;