diff options
Diffstat (limited to 'src/kernel/fat.c')
-rw-r--r-- | src/kernel/fat.c | 104 |
1 files changed, 97 insertions, 7 deletions
diff --git a/src/kernel/fat.c b/src/kernel/fat.c index 5ba62cf..b865859 100644 --- a/src/kernel/fat.c +++ b/src/kernel/fat.c @@ -3,6 +3,7 @@ #include "util.h" #include "ata.h" #include "fat.h" +#include "log.h" #include "pmap.h" #define MAX_FAT_DRIVES 16 @@ -18,14 +19,17 @@ enum { FA_LABEL = 0x08, FA_DIRECTORY = 0x10, FA_ARCHIVE = 0x20, +}; - FA_LFN = 0x0f +enum { + //applied to every file without FA_READ_ONLY + FEA_OPEN_EXCLUSIVE = 0x01 }; struct directory_entry { uint8_t name[11]; uint8_t attrib; - uint8_t name_case; + uint8_t extra_attrib;//non-standard attributes uint8_t created_decimal; uint16_t created_time; uint16_t created_date; @@ -70,9 +74,12 @@ struct open_file_info { uint16_t start_cluster; uint32_t length; + + uint8_t attrib; }; struct fat_drive_info { + const struct drive *from_drive; const struct fat_info *fi; uint16_t *fat; uint16_t root_start; @@ -109,6 +116,11 @@ static void load_cluster(uint16_t c, void *to) { cur_drive->read_sectors(cur_drive, s, 1, to); } +static void save_cluster(uint16_t c, const void *from) { + uint32_t s = CTOS(c, cur_fdi); + cur_drive->write_sectors(cur_drive, s, 1, from); +} + __attribute__ ((pure)) static uint16_t next_cluster(uint16_t c) { uint16_t found = infos[cur_id].fat[c]; @@ -226,22 +238,47 @@ static file_id_t fat_get_file(const struct drive *d, const char *path) { return 0; } + if (cur_dir->extra_attrib & FEA_OPEN_EXCLUSIVE) { + d->done(d); + return 0;//maybe have a special return value for this? + } + + if (!(cur_dir->attrib & FA_READ_ONLY)) { + cur_dir->extra_attrib |= FEA_OPEN_EXCLUSIVE; + d->write_sectors(d, cur_sect, 1, fat_driver_buffer); + } + d->done(d); + 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; + open_files[n].attrib = cur_dir->attrib; + return n; } - PANIC("Maximum number of files open reached for FAT drive."); + d->done(d); + logf(LOG_ERROR, "Maximum number of open files (%d) reached for drive %u (%s, FAT).", MAX_OPEN_FILES_PER_DRIVE, d - drives + 1, d->drive_type); + return 0; } static void fat_free_file(const struct drive *d, file_id_t fid) { - infos[d->drive_id].open_files[fid - 1].di_sector = 0; + struct open_file_info *const of = infos[d->drive_id].open_files + fid - 1; + + if (!(of->attrib & FA_READ_ONLY)) { + d->ready(d); + d->read_sectors(d, of->di_sector, 1, fat_driver_buffer); + ((struct directory_entry *)fat_driver_buffer)[of->di_number].extra_attrib &= ~FEA_OPEN_EXCLUSIVE; + d->write_sectors(d, of->di_sector, 1, fat_driver_buffer); + d->done(d); + } + + of->di_sector = 0; } -static void fat_load_sector(const struct drive *d, file_id_t fid, uint32_t sector, void *at) { +static uint16_t get_nth_cluster(const struct drive *d, file_id_t fid, uint32_t sector) { cur_drive = d; cur_id = d->drive_id; cur_fdi = &infos[cur_id]; @@ -250,16 +287,48 @@ static void fat_load_sector(const struct drive *d, file_id_t fid, uint32_t secto for (uint32_t i = 0; i < sector; ++i) c = next_cluster(c); + return c; +} + +static void fat_load_sector(const struct drive *d, file_id_t fid, uint32_t sector, void *at) { + uint16_t c = get_nth_cluster(d, fid, sector); + d->ready(d); load_cluster(c, at); d->done(d); } +static void fat_save_sector(const struct drive *d, file_id_t fid, uint32_t sector, const void *from) { + if (infos[d->drive_id].open_files[fid - 1].attrib & FA_READ_ONLY) + return;//maybe return special value for this + + uint16_t c = get_nth_cluster(d, fid, sector); + + d->ready(d); + save_cluster(c, from); + d->done(d); +} + __attribute__ ((pure)) static uint32_t fat_get_file_length(const struct drive *d, file_id_t fid) { return infos[d->drive_id].open_files[fid - 1].length; } +static void fat_set_file_length(const struct drive *d, file_id_t fid, uint32_t new_length) { + struct open_file_info *const of = infos[d->drive_id].open_files + fid - 1; + if (of->attrib & FA_READ_ONLY) + return;//maybe return special vlue for this + + if (((new_length - 1) >> 9) + 1 != ((of->length - 1) >> 9) + 1) + PANIC("TODO: resizing FAT file to different sector count"); + + of->length = new_length; + + d->read_sectors(d, of->di_sector, 1, fat_driver_buffer); + ((struct directory_entry *)fat_driver_buffer)[of->di_number].length = new_length; + d->write_sectors(d, of->di_sector, 1, fat_driver_buffer); +} + __attribute__ ((pure)) static uint32_t fat_get_free_sectors(const struct drive *d) { uint16_t *start = infos[d->fs_id].fat + 2; @@ -429,6 +498,11 @@ static uint32_t fat_n_dir_entries(const struct drive *d, const char *path) { } } +__attribute__ ((__pure__)) +static bool fat_is_writable(const struct drive *d, file_id_t fid) { + return !(infos[d->drive_id].open_files[fid - 1].attrib & FA_READ_ONLY); +} + void init_fat() { next_fi = allocate_kernel_pages(1); next_id = 0; @@ -450,25 +524,41 @@ 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->save_sector = &fat_save_sector; d->get_file_length = &fat_get_file_length; + d->set_file_length = &fat_set_file_length; d->enumerate_dir = &fat_enumerate_dir; d->n_dir_entries = &fat_n_dir_entries; d->get_free_sectors = &fat_get_free_sectors; + d->is_writable = &fat_is_writable; d->fs_id = next_id; infos[next_id].fi = next_fi; infos[next_id].fat = allocate_kernel_pages(((next_fi->sectors_per_fat - 1) >> 3) + 1); - infos[next_id].root_start = next_fi->reserved_sectors + + infos[next_id].root_start = next_fi->reserved_sectors + next_fi->sectors_per_fat * next_fi->fats; infos[next_id].data_start = infos[next_id].root_start + ((next_fi->root_entries - 1) >> 4) + 1; + logf(LOG_INFO, "0x%h <- 0x%h", &infos[next_id].from_drive, drives + n_drives); + infos[next_id].from_drive = drives + n_drives; d->read_sectors(d, next_fi->reserved_sectors, next_fi->sectors_per_fat, infos[next_id].fat); - struct open_file_info *open_files = infos[next_id].open_files - 1; + struct open_file_info *open_files = infos[next_id].open_files; for (file_id_t i = 0; i < MAX_OPEN_FILES_PER_DRIVE; ++i) open_files[i].di_sector = 0; alloc_next_fi(); ++next_id; return true; +} + +void fat_ready_shutdown() { + for (uint8_t i = 0; i < next_id; ++i) + for (uint8_t j = 0; j < MAX_OPEN_FILES_PER_DRIVE; ++j) + if (infos[i].open_files[j].di_sector) { + logf(LOG_INFO, "i = %d, j = %d", i, j); + logf(LOG_INFO, "freeing file %d from drive 0x%h (number %d)", j + 1, infos[i].from_drive, infos[i].from_drive - drives + 1); + logf(LOG_INFO, "0x%h -> 0x%h", &infos[i].from_drive, infos[i].from_drive); + fat_free_file(infos[i].from_drive, j + 1); + } }
\ No newline at end of file |