summaryrefslogtreecommitdiff
path: root/src/kernel/fat.c
diff options
context:
space:
mode:
authorBenji Dial <benji6283@gmail.com>2021-03-01 22:35:26 -0500
committerBenji Dial <benji6283@gmail.com>2021-03-01 22:35:26 -0500
commit1d69a46f5d9823bbf2e6211ca367b409d2d5f7a7 (patch)
treea49a5498080551270a827a205cde49477d4d89ff /src/kernel/fat.c
parent6f1b50a4cc6c232ee505a543f006abb1c6cd33cf (diff)
downloadportland-os-1d69a46f5d9823bbf2e6211ca367b409d2d5f7a7.tar.gz
minimal file writing, shutdown keybinding (Win+Shift+Q)
Diffstat (limited to 'src/kernel/fat.c')
-rw-r--r--src/kernel/fat.c104
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