diff options
Diffstat (limited to 'src/kernel/fat.c')
-rw-r--r-- | src/kernel/fat.c | 271 |
1 files changed, 183 insertions, 88 deletions
diff --git a/src/kernel/fat.c b/src/kernel/fat.c index b8d1c3b..087d79e 100644 --- a/src/kernel/fat.c +++ b/src/kernel/fat.c @@ -1,115 +1,210 @@ #include "fat.h" #include "ata.h" #include "panic.h" -#include "fs.h" +#include "drive.h" +#include "mem.h" +#include "util.h" -void load_fat() { - read_sectors(FAT_INFO->reserved_sectors, FAT_INFO->sectors_per_fat, FAT); +#define MAX_FAT_DRIVES 16 +#define MAX_OPEN_FILES_PER_DRIVE 32 + +enum { + FA_READ_ONLY = 0x01, + FA_HIDDEN = 0x02, + FA_SYSTEM = 0x04, + FA_LABEL = 0x08, + FA_DIRECTORY = 0x10, + FA_ARCHIVE = 0x20, + + FA_LFN = 0x0f +}; + +struct directory_entry { + uint8_t name[11]; + uint8_t attrib; + uint8_t name_case; + uint8_t created_decimal; + uint16_t created_time; + uint16_t created_date; + uint16_t accessed_date; + uint16_t ignore; + uint16_t modified_time; + uint16_t modified_date; + uint16_t first_cluster; + uint32_t length; +} __attribute__ ((packed)); + +struct fat_info { + //3 bytes jump + uint8_t oem[8]; + uint16_t bytes_per_sector;//Assumed to be 512 + uint8_t sectors_per_cluster;//Assumed to be 1 + uint16_t reserved_sectors; + uint8_t fats;//Only first is used + uint16_t root_entries; + uint16_t sectors;//Assumed not to be 0 + uint8_t media_type; + uint16_t sectors_per_fat; + uint16_t sectors_per_track; + uint16_t heads; + uint32_t hidden_sectors; + uint32_t sectors_long; + uint8_t drive_number; + uint8_t reserved; + uint8_t ext_boot_marker; + uint32_t volume_id; + uint8_t label[11]; + uint8_t fs_type[8]; +} __attribute__ ((packed)); + +#define CTOS(c, fi) ((fi)->reserved_sectors + (fi)->sectors_per_fat * (fi)->fats + ((fi)->root_entries >> 4) + (c) - 2) + +struct fat_drive_info { + struct fat_info *fi; + uint16_t *fat; + struct directory_entry open_files[MAX_OPEN_FILES_PER_DRIVE]; +}; + +struct fat_drive_info infos[MAX_FAT_DRIVES]; +uint8_t next_id = 0; + +#define FI(n) ((struct fat_info *)(infos[n].fi + 3)) +#define FN(n, f) (infos[n].open_files[f - 1]) + +uint8_t fat_driver_buffer[512]; +struct fat_info *next_fi; + +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."); } -bool to_fat_name(uint8_t *sname, uint8_t *fname) { - uint8_t *sp = sname, *fp = fname; - while (*sp != '.') { - if (!*sp) { - while (fp != fname + 11) - *(fp++) = ' '; - return false; - } - if (sp == sname + 8) - return true; - *(fp++) = *(sp++); - } - while (fp != fname + 8) - *(fp++) = ' '; - while (*++sp) { - if (fp == fname + 11) - return true; - *(fp++) = *sp; +struct drive *cur_drive; +fs_id_t cur_id; +struct directory_entry *cur_dir; + +//loads cluster `c` +void load_cluster(uint16_t c, void *to) { + if (c == 0) { + *(uint8_t *)to = 0; + return; } - while (fp != fname + 11) - *(fp++) = ' '; - return false; + + uint32_t s = CTOS(c, FI(cur_id)); + cur_drive->read_sectors(cur_drive, s, 1, to); } -bool check_fat_names(uint8_t *lname, uint8_t *rname) { - return (* (uint32_t *)lname == *(uint32_t *)rname) && - (*((uint32_t *)lname + 1) == *((uint32_t *)rname + 1)) && - (*((uint16_t *)lname + 4) == *((uint16_t *)rname + 4)) && - (*( lname + 10) == *( rname + 10)); +uint16_t next_cluster(uint16_t c) { + panic("TODO: compute next sector (or 0 for none)"); } -struct directory_entry buffer[16]; -uint16_t dir_start, buffer_from; +static inline bool check_fat_names(uint8_t *a, 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]) && + (((uint8_t *)a)[10] == ((uint8_t *)b)[10]); +} +//after: cur_dir -> specified entry in root +bool try_locate_root_entry(uint8_t *fat_name) { + uint32_t cur_dir_sect = FI(cur_id)->reserved_sectors + FI(cur_id)->sectors_per_fat * FI(cur_id)->fats - 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); + } + if (!*(uint8_t *)cur_dir) + return false; + if (check_fat_names(cur_dir->name, fat_name)) + return true; + else + ++cur_dir; + } +} -void load_root() { - dir_start = FAT_INFO->reserved_sectors + FAT_INFO->sectors_per_fat; +//before: cur_dir -> entry of dir to search +//after: cur_dir -> specified entry in dir +bool try_locate_entry(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)) + return true; + else + ++cur_dir; + } } -struct directory_entry *load_subentry(uint8_t *name) { - uint8_t fname[11]; - if (to_fat_name(name, fname)) - return 0; - struct directory_entry *ptr = buffer; - uint16_t dir_current = dir_start; - read_sectors(buffer_from = dir_current, 1, buffer); - while (*(uint8_t *)ptr) { - if (check_fat_names(ptr->name, fname)) - return ptr; - if (++ptr == buffer + 16) { - read_sectors(buffer_from = ++dir_current, 1, buffer); - ptr = buffer; +drive_file_id_t fat_get_file(struct drive *d, char *path) { + cur_drive = d; + cur_id = d->drive_id; + for (drive_file_id_t n = 1; n != MAX_OPEN_FILES_PER_DRIVE + 1; ++n) + if (!*(uint8_t *)(&FN(d->drive_id, n))) { + panic("TODO: open path at FN(id, n)"); + return n; } - }; - return 0; + panic("Maximum number of files open reached for FAT drive."); } -bool load_subdir(uint8_t *name) { - struct directory_entry *e = load_subentry(name); - if (!e) - return true; - dir_start = CTOS(e->first_cluster); - return false; +void fat_free_file(struct drive *d, drive_file_id_t fid) { + *(uint8_t *)(&FN(d->drive_id, fid)) = 0; } -struct directory_entry *load_entry(uint8_t *path) { - load_root(); - for (uint8_t *ptr = path; *ptr; ++ptr) - if (*ptr == '/') { - *ptr = 0; - if (load_subdir(path)) - return 0; - path = ptr + 1; - } - return load_subentry(path); +void fat_load_sector(struct drive *d, drive_file_id_t fid, uint32_t sector, void *at) { + cur_drive = d; + cur_id = d->drive_id; + uint16_t c = FN(d->drive_id, fid).first_cluster; + for (uint32_t i = 0; i < sector; ++i) + c = next_cluster(c); + load_cluster(c, at); } -bool get_entry(uint8_t *path, struct directory_entry *at) { - struct directory_entry *e = load_entry(path); - if (!e) - return true; - *at = *e; - return false; +uint32_t fat_get_free_sectors(struct drive *d) { + panic("TODO: get free sectors of drive"); } -bool update_entry(uint8_t *path, struct directory_entry *value) { - struct directory_entry *e = load_entry(path); - if (!e) - return true; - *e = *value; - write_sectors(buffer_from, 1, buffer); - return false; +void init_fat() { + next_fi = allocate_pages(1); } -bool create_entry(uint8_t *dir_path, struct directory_entry *value) { - fs_handle h = fs_open(dir_path); - struct directory_entry *check; - while (fs_read(h, 32, check)) - if (check_fat_names(check->name, value->name)) { - fs_close(h); - return true; - } - fs_write(h, 32, value); - fs_close(h); - return false; +bool try_fat_init_drive(struct drive *d) { + if (next_id >= MAX_FAT_DRIVES) + panic("Maximum number of FAT drives reached."); + + if (!d->read_sectors(d, 0, 1, fat_driver_buffer)) + return false; + memcpy(next_fi, fat_driver_buffer + 3, sizeof(struct fat_info)); + uint32_t *fs_type_32 = (uint32_t *)next_fi->fs_type; + if ((fs_type_32[0] != ('F' + 'A' * 256 + 'T' + 65536 + '1' * 16777216)) || + (fs_type_32[1] != ('6' + ' ' * 256 + ' ' + 65536 + ' ' * 16777216))) + return false; + + d->fs_type = "FAT16"; + d->get_file = &fat_get_file; + d->free_file = &fat_free_file; + d->load_sector = &fat_load_sector; + d->get_free_sectors = &fat_get_free_sectors; + + d->fs_id = next_id; + infos[next_id].fi = next_fi; + infos[next_id].fat = allocate_pages(((next_fi->sectors_per_fat - 1) >> 3) + 1); + for (drive_file_id_t i = 0; i < MAX_OPEN_FILES_PER_DRIVE; ++i) + *(uint8_t *)&FN(next_id, i) = 0; + + d->read_sectors(d, next_fi->reserved_sectors, next_fi->sectors_per_fat, infos[next_id].fat); + + alloc_next_fi(); + ++next_id; + return true; }
\ No newline at end of file |