Support for multiple volumes, filesystem detection (currently FAT)

This commit is contained in:
Lucia Ceionia 2023-02-17 06:21:43 -06:00
parent d0a5eb4c6f
commit e688617286
9 changed files with 300 additions and 79 deletions

77
file.c
View File

@ -1,78 +1,113 @@
#include "file.h"
#include "fs.h"
#define MAXFS (0x20000/sizeof(filesystem))
filesystem (*const FilesystemTable)[MAXFS] = (filesystem (* const)[MAXFS])0x240000;
// TODO Replace with something better
extern uint8_t ActiveFsId;
// Sets adjusted_path to the path without filesystem info,
// returns the filesystem calculated
uint8_t GetFsFromPath(char *path, char **adjusted_path) {
// On active filsystem
if (*path == '/') {
*adjusted_path = path;
return GetActiveFilesystemId();
}
// Read the filesystem ID
uint8_t id = 0;
char *tmp_path = path;
// Find first /
for (;*tmp_path != '/';tmp_path++);
*adjusted_path = tmp_path;
// Read octal num
tmp_path--;
for (uint8_t bit_off = 0; tmp_path >= path; tmp_path--, bit_off+=3) {
// Outside of octal range, error
if (*tmp_path < '0' || *tmp_path > '8') return 0;
id += (*tmp_path - '0') << bit_off;
}
// Return filesystem
return id;
}
// Returns 0 on success, non-zero error code on error. Fills provided struct FILE
int file_open(FILE *file, char *path, char mode) {
filesystem *fs = &(*FilesystemTable)[0];
return fs->ops.file_open(fs->fs_data, file, path, mode);
char *adj_path;
uint8_t fsid = GetFsFromPath(path, &adj_path);
filesystem *fs = GetFilesystem(fsid);
int err = fs->ops.file_open(fs->fs_data, file, adj_path, mode);
file->filesystem_id = fsid;
return err;
}
// Returns 0 on success, non-zero error code on error.
int file_seek(FILE *file, uint32_t offset) {
filesystem *fs = &(*FilesystemTable)[0];
filesystem *fs = GetFilesystem(file->filesystem_id);
return fs->ops.file_seek(fs->fs_data, file, offset);
}
// Returns 0 on error, bytes read on success.
int file_read(FILE *file, uint8_t *dest, uint32_t len) {
filesystem *fs = &(*FilesystemTable)[0];
filesystem *fs = GetFilesystem(file->filesystem_id);
return fs->ops.file_read(fs->fs_data, file, dest, len);
}
// Returns 0 on error, bytes written on success.
int file_write(FILE *file, uint8_t *src, uint32_t len) {
filesystem *fs = &(*FilesystemTable)[0];
filesystem *fs = GetFilesystem(file->filesystem_id);
return fs->ops.file_write(fs->fs_data, file, src, len);
}
void file_close(FILE *file) {
filesystem *fs = &(*FilesystemTable)[0];
filesystem *fs = GetFilesystem(file->filesystem_id);
return fs->ops.file_close(fs->fs_data, file);
}
// Returns 0 on success, non-zero error code on error. Fills provided struct DIR
int dir_open(DIR *dir, char *path) {
filesystem *fs = &(*FilesystemTable)[0];
return fs->ops.dir_open(fs->fs_data, dir, path);
char *adj_path;
uint8_t fsid = GetFsFromPath(path, &adj_path);
filesystem *fs = GetFilesystem(fsid);
int err = fs->ops.dir_open(fs->fs_data, dir, adj_path);
dir->filesystem_id = fsid;
return err;
}
// Return 0 on success, non-zero error code on error. Fills provided struct dirent.
int dir_nextentry(DIR *dir, dirent *ent) {
filesystem *fs = &(*FilesystemTable)[0];
filesystem *fs = GetFilesystem(dir->filesystem_id);
return fs->ops.dir_nextentry(fs->fs_data, dir, ent);
}
void dir_close(DIR *dir) {
filesystem *fs = &(*FilesystemTable)[0];
filesystem *fs = GetFilesystem(dir->filesystem_id);
return fs->ops.dir_close(fs->fs_data, dir);
}
// Returns 0 on success, non-zero error code on error. Fills provided struct dirent.
int path_getinfo(char *path, dirent *ent) {
filesystem *fs = &(*FilesystemTable)[0];
return fs->ops.path_getinfo(fs->fs_data, path, ent);
char *adj_path;
filesystem *fs = GetFilesystem(GetFsFromPath(path, &adj_path));
return fs->ops.path_getinfo(fs->fs_data, adj_path, ent);
}
// Returns 0 on success, non-zero error code on error.
int path_mkdir(char *path) {
filesystem *fs = &(*FilesystemTable)[0];
return fs->ops.path_mkdir(fs->fs_data, path);
char *adj_path;
filesystem *fs = GetFilesystem(GetFsFromPath(path, &adj_path));
return fs->ops.path_mkdir(fs->fs_data, adj_path);
}
// Returns 0 on success, non-zero error code on error.
int path_rmdir(char *path) {
filesystem *fs = &(*FilesystemTable)[0];
return fs->ops.path_rmdir(fs->fs_data, path);
char *adj_path;
filesystem *fs = GetFilesystem(GetFsFromPath(path, &adj_path));
return fs->ops.path_rmdir(fs->fs_data, adj_path);
}
// Returns 0 on success, non-zero error code on error.
int path_rmfile(char *path) {
filesystem *fs = &(*FilesystemTable)[0];
return fs->ops.path_rmfile(fs->fs_data, path);
char *adj_path;
filesystem *fs = GetFilesystem(GetFsFromPath(path, &adj_path));
return fs->ops.path_rmfile(fs->fs_data, adj_path);
}

126
fs.c
View File

@ -1,15 +1,16 @@
#include "fs.h"
#include "disk.h"
struct FsType {
uint32_t type_id;
int (*init_func)(filesystem *, char);
int (*init_func)(filesystem *, uint32_t);
// Not yet decided
char (*detect_func)();
char (*detect_func)(uint32_t);
};
// TODO Get these dynamically somehow
int InitDosFs(filesystem *fs, char partition);
char DetectDosPart();
int InitDosFs(filesystem *fs, uint32_t start_sector);
char DetectDosPart(uint32_t start_sector);
struct FsType SupportedFilesystems[] = {
{
@ -19,18 +20,111 @@ struct FsType SupportedFilesystems[] = {
}
};
#define MAXFS (0x20000/sizeof(filesystem))
filesystem (*const ActiveFilesystems)[MAXFS] = (filesystem (* const)[MAXFS])0x240000;
#define MAXFS 255
filesystem *ActiveFilesystems = (filesystem *)0x240000;
// TODO Replace with something better
uint8_t ActiveFsId;
uint8_t ActiveFsIdx;
// TODO Make functions and just use those instead
int MakeSystemVolume(uint8_t sysPartition) {
filesystem *sys = &(*ActiveFilesystems)[0];
SupportedFilesystems[0].init_func(sys, sysPartition);
sys->type = SupportedFilesystems[0].type_id;
sys->id = 0;
ActiveFsId = 0;
return 0;
filesystem *GetFilesystem(uint8_t idx) {
if (idx >= MAXFS) return 0;
filesystem *fs = &ActiveFilesystems[idx];
return fs->type != 0 ? fs : 0;
}
filesystem *GetActiveFilesystem() {
return &ActiveFilesystems[ActiveFsIdx];
}
uint8_t GetActiveFilesystemId() {
return ActiveFsIdx;
}
filesystem *SetActiveFilesystem(uint8_t idx) {
if (idx >= MAXFS) return 0;
filesystem *fs = &ActiveFilesystems[idx];
if (fs->type == 0) return 0;
ActiveFsIdx = idx;
return fs;
}
void ActiveFilesystemBitmap(char *bitmap) {
for (int i = 0; i < 256; i++)
bitmap[i] = ActiveFilesystems[i].type != 0;
}
struct PartTableEntry_t {
uint8_t attr;
uint8_t start_chs0;
uint8_t start_chs1;
uint8_t start_chs2;
uint8_t type;
uint8_t end_chs0;
uint8_t end_chs1;
uint8_t end_chs2;
uint32_t start_lba;
uint32_t num_sectors;
};
typedef struct MBR_t {
char boot_code[0x1B8];
uint32_t signature;
uint16_t reserved;
struct PartTableEntry_t partTable[4];
uint16_t boot_sig;
} __attribute__((__packed__)) MBR_t;
// TODO Just check for this
uint8_t BootPartition;
uint8_t NextAvailableFilesystem;
MBR_t SysMbr;
void MakeMBRPartitions() {
// Get MBR
MBR_t *mbr = &SysMbr;
Disk_ReadSector(0, (uint8_t*)mbr, 0, 1);
// Scan partitions
for (int p = 0; p < 4; p++) {
if (p == BootPartition) continue;
if (mbr->partTable[p].type == 0) continue;
uint32_t partStart = mbr->partTable[p].start_lba;
if (partStart == 0) continue;
// Scan supported filesystems
filesystem *sys = &ActiveFilesystems[NextAvailableFilesystem];
for (int i = 0; i < sizeof(SupportedFilesystems)/sizeof(struct FsType); i++) {
if (!SupportedFilesystems[i].detect_func(partStart)) continue;
SupportedFilesystems[i].init_func(sys, partStart);
sys->type = SupportedFilesystems[i].type_id;
ActiveFsIdx = NextAvailableFilesystem;
NextAvailableFilesystem++;
break;
}
}
}
int MakeSystemVolume(uint8_t bootPartition) {
// Clear out filesystem area
for (int i = 0; i < (sizeof(filesystem)*MAXFS)/sizeof(uint32_t);i++)
((uint32_t*)ActiveFilesystems)[i] = 0;
BootPartition = bootPartition;
NextAvailableFilesystem = 1;
// Get MBR
MBR_t *mbr = &SysMbr;
Disk_ReadSector(0, (uint8_t*)mbr, 0, 1);
// Get boot partition sector
uint32_t sys_sector = mbr->partTable[bootPartition].start_lba;
// Scan supported filesystems
filesystem *sys = &ActiveFilesystems[0];
for (int i = 0; i < sizeof(SupportedFilesystems)/sizeof(struct FsType); i++) {
asm volatile("xchg %bx,%bx");
if (!SupportedFilesystems[i].detect_func(sys_sector)) continue;
SupportedFilesystems[i].init_func(sys, sys_sector);
sys->type = SupportedFilesystems[i].type_id;
ActiveFsIdx = 0;
return 0;
}
// Init Failed
return -1;
}

12
fs.h
View File

@ -3,9 +3,7 @@
#include "file_s.h"
typedef struct filesystem {
uint8_t id;
uint8_t resv0;
uint16_t resv1;
uint32_t resv0;
uint32_t type;
struct fs_operations {
int (*file_open)(uint8_t *, FILE *, char *, char);
@ -24,5 +22,11 @@ typedef struct filesystem {
} ops;
uint8_t labellen;
char label[255];
uint8_t fs_data[512-4-4-44-256];
uint8_t fs_data[2048-4-4-44-256];
} __attribute__((packed)) filesystem;
filesystem *GetFilesystem(uint8_t idx);
filesystem *GetActiveFilesystem();
uint8_t GetActiveFilesystemId();
filesystem *SetActiveFilesystem(uint8_t idx);
void ActiveFilesystemBitmap(char *bitmap);

View File

@ -2,6 +2,10 @@
#include "fs.h"
#include "dosfs/dosfs.h"
char *strncpy(char *restrict d, const char *restrict s, uintptr_t n);
int strcmp(const char *l, const char *r);
void *memcpy(void *restrict dest, const void *restrict src, uintptr_t n);
// Implementations for DOSFS
uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
@ -40,6 +44,18 @@ int file83ToPath(uint8_t *src, char *path) {
return tmp;
}
uintptr_t stripToDir(char *path) {
int i = 0;
// find end of string
for (;path[i];i++);
// find last /
for (;path[i] != '/' && i >= 0;i--);
// path[i] == '/'
// set next to end, return split location
path[i+1] = 0;
return i + 1;
}
int dos_file_open(uint8_t *dat, FILE *f, char *path, char mode) {
fsdat *fs = (fsdat *)dat;
uint8_t *scratch = (uint8_t *)0x20000;
@ -92,7 +108,6 @@ int dos_dir_open(uint8_t *dat, DIR *d, char *path) {
int dos_dir_nextentry(uint8_t *dat, DIR *d, dirent *ent) {
fsdat *fs = (fsdat *)dat;
uint8_t *scratch = (uint8_t *)0x20000;
DIRENT de;
for (;;) {
uint32_t code = DFS_GetNext(&fs->vi, (DIRINFO *)d->bytes, &de);
@ -121,10 +136,35 @@ int dos_dir_nextentry(uint8_t *dat, DIR *d, dirent *ent) {
// DOSFS doesn't have anything to clean up
void dos_dir_close(uint8_t *dat, DIR *d) { return; }
// TODO Unimplemented
// TODO Make this less expensive -> Use DOSFS directly?
int dos_path_getinfo(uint8_t *dat, char *path, dirent *d) {
fsdat *fs = (fsdat *)dat;
uint8_t *scratch = (uint8_t *)0x20000;
// Get directory path is in
uint8_t tmppath[MAX_PATH];
strncpy((char*)tmppath,path,MAX_PATH);
tmppath[MAX_PATH-1]=0;
uintptr_t nameidx = stripToDir((char*)tmppath);
char *name = &path[nameidx];
// Open directory
DIR dir;
dos_dir_open(dat, &dir, (char*)tmppath);
dirent de;
// Enumerate info
for (;dos_dir_nextentry(dat, &dir, &de) == 0;) {
// Check if correct entry
if (strcmp(de.name, name) == 0) {
// Copy to caller dirent
for (int i = 0; i < sizeof(dirent); i++)
((uint8_t*)d)[i] = ((uint8_t*)&de)[i];
return 0;
}
}
// Did not find or error
return -1;
}
@ -152,20 +192,27 @@ int dos_path_rmfile(uint8_t *dat, char *path) {
// DOSFS doesn't have anything to clean up
void dos_endfs(uint8_t *dat) { return; }
// Not yet decided
char DetectDosPart() {
// Try to detect if partition is a valid DOS partition
char DetectDosPart(uint32_t start_sector) {
// Read sector
//uint8_t *scratch = (uint8_t *)0x20000;
//Disk_ReadSector(0, scratch, start_sector, 1);
//// Check for start bytes EBXX90
//if (((*(uint32_t*)&scratch[0]) & 0x00FF00FF) != 0x9000EB) return 0;
//// Check for bytes per sector == 512 (We don't support other values anyway)
//if (*(uint16_t*)&scratch[0xB] != 512) return 0;
// TODO Check more, so we *know* it's FAT
// We're probably FAT
return 1;
}
int InitDosFs(filesystem *fs, char partition) {
int InitDosFs(filesystem *fs, uint32_t start_sector) {
uint8_t *diskReadBuf = (uint8_t *)0x20000;
uint8_t pactive, ptype;
uint32_t pstart, psize;
pstart = DFS_GetPtnStart(0, diskReadBuf, partition, &pactive, &ptype, &psize);
if (pstart == -1) return -1;
VOLINFO *vi = (VOLINFO *)fs->fs_data;
if (DFS_GetVolInfo(0, diskReadBuf, pstart, (VOLINFO *)fs->fs_data)) {
if (DFS_GetVolInfo(0, diskReadBuf, start_sector, (VOLINFO *)fs->fs_data)) {
return -1;
}

View File

@ -12,30 +12,28 @@ uint32_t blockLenMap[TOTALBLOCKS] __attribute__((section(".hexbss")));;
// so that it can be expanded without telling C how much
// it actually needs
uint8_t writeStoreBase[BLOCKSIZE] __attribute__((section(".hexlatebss")));
void HexEditor(char *path, dirent *de) {
void HexEditor(char *path) {
uint32_t err;
uint16_t *vga_text = (uint16_t *)0xb8000;
uint32_t screenSize = 80*25;
uint8_t *scratch = (uint8_t *)0x20000;
uint8_t (*writeStore)[BLOCKSIZE] = &writeStoreBase;
uint32_t filelen = de->size;
for (int i = 0; i < TOTALBLOCKS; i++)
writtenMap[i] = 0;
uint8_t *screenBuff = *writeStore;
// First two blocks are screen buffer
uint32_t nextFreeBlock = 2;
FILE file;
vga_text = (uint16_t *)0xb8000;
for (int i = 0; i < 80*50; i++)
vga_text[i] = 0x0f00;
err = file_open(&file, path, OPENREAD|OPENWRITE);
dirent de;
err = path_getinfo(path, &de);
if (err) {
vga_text += printStr("Open Error: ", vga_text);
printDword(err, vga_text);
vga_text += printStr("Error getting file info.", vga_text);
kbd_wait();
return;
}
uint32_t filelen = de.size;
if (filelen == 0) {
vga_text += printStr("File ", vga_text);
vga_text += printStr((char*)path, vga_text);
@ -50,6 +48,14 @@ void HexEditor(char *path, dirent *de) {
kbd_wait();
return;
}
FILE file;
err = file_open(&file, path, OPENREAD|OPENWRITE);
if (err) {
vga_text += printStr("Open Error: ", vga_text);
printDword(err, vga_text);
kbd_wait();
return;
}
uint32_t drawOffset = 0, lastDrawOffset = -1;
char cont = 1;
uint32_t byteCount = 16*24, lastByteCount = 0;

View File

@ -1,6 +1,7 @@
#include <stdint.h>
#include "file.h"
#include "fs.h"
#include "print.h"
#include "interrupt.h"
#include "kbd.h"
@ -281,13 +282,17 @@ void ScancodeTest() {
}
extern void create_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
uint16_t FileSelectScreen[80*25];
char ValidFilesystems[256];
void FileSelect() {
ActiveFilesystemBitmap(ValidFilesystems);
uint8_t currentFsId = 0;
char current_path[80];
uintptr_t current_path_end;
for (int i = 0; i < sizeof(current_path); i++)
current_path[i] = 0;
current_path[0] = '/';
current_path_end = 1;
current_path[0] = '0';
current_path[1] = '/';
current_path_end = 2;
fileCount = 5;
uint16_t *vga_text = (uint16_t *)FileSelectScreen;
int32_t fileHovered = 0;
@ -305,6 +310,8 @@ void FileSelect() {
vga += 80;
printStr("O to open directory", vga);
vga += 80;
printStr("S to switch volume", vga);
vga += 80;
printStr("F4 to run tests", vga);
}
printStr(current_path, &vga_text[80*4 + 2]);
@ -360,7 +367,7 @@ void FileSelect() {
for (int i = 0; i < DirEntries[fileHovered].namelen; i++)
current_path[current_path_end + i] = DirEntries[fileHovered].name[i];
current_path[current_path_end + DirEntries[fileHovered].namelen] = 0;
create_child(GetFreeStack(), (uintptr_t)ProgramLoadTest, 2, current_path, &DirEntries[fileHovered]);
create_child(GetFreeStack(), (uintptr_t)ProgramLoadTest, 1, current_path);
current_path[current_path_end] = 0;
RestoreVGA();
reload = 1;
@ -370,7 +377,7 @@ void FileSelect() {
for (int i = 0; i < DirEntries[fileHovered].namelen; i++)
current_path[current_path_end + i] = DirEntries[fileHovered].name[i];
current_path[current_path_end + DirEntries[fileHovered].namelen] = 0;
create_child(GetFreeStack(), (uintptr_t)HexEditor, 2, current_path, &DirEntries[fileHovered]);
create_child(GetFreeStack(), (uintptr_t)HexEditor, 1, current_path);
current_path[current_path_end] = 0;
RestoreVGA();
reload = 1;
@ -381,7 +388,7 @@ void FileSelect() {
for (int i = 0; i < DirEntries[fileHovered].namelen; i++)
current_path[current_path_end + i] = DirEntries[fileHovered].name[i];
current_path[current_path_end + DirEntries[fileHovered].namelen] = 0;
create_child(GetFreeStack(), (uintptr_t)TextViewTest, 2, current_path, &DirEntries[fileHovered]);
create_child(GetFreeStack(), (uintptr_t)TextViewTest, 1, current_path);
current_path[current_path_end] = 0;
RestoreVGA();
reload = 1;
@ -419,6 +426,25 @@ void FileSelect() {
fileOffset = 0;
}
break;
case KEY_S:
// Next filesystem TODO Support over 077 I'm so lazy right now
for (currentFsId = (currentFsId + 1) % 64; !ValidFilesystems[currentFsId]; currentFsId = (currentFsId + 1) % 64);
if (currentFsId < 8) {
current_path[0] = '0' + currentFsId;
current_path[1] = '/';
current_path[2] = 0;
current_path_end = 2;
} else {
current_path[0] = '0' + (currentFsId >> 3);
current_path[1] = '0' + (currentFsId & 7);
current_path[2] = '/';
current_path[3] = 0;
current_path_end = 3;
}
reload = 1;
fileHovered = 0;
fileOffset = 0;
break;
case KEY_F6:
ScancodeTest();
reload = 1;
@ -430,6 +456,7 @@ void FileSelect() {
}
int MakeSystemVolume(uint8_t sysPartition);
void MakeMBRPartitions();
void SystemRun(uint8_t sysPartition) {
uint16_t *vga_text = (word *)0xb8000;
RestoreVGA();
@ -439,7 +466,6 @@ void SystemRun(uint8_t sysPartition) {
// Check for FAT partition
{
// TODO Check partitions beyond 0
while (1) {
create_child(GetFreeStack(), (uintptr_t)MakeSystemVolume, 1, sysPartition);
if (!check_error_code()) break;
@ -449,6 +475,7 @@ void SystemRun(uint8_t sysPartition) {
vga_text += printStr("Press R to retry.", vga_text);
for (;(get_scancode() & 0xff) != KEY_R;);
}
create_child(GetFreeStack(), (uintptr_t)MakeMBRPartitions, 0);
}
for (;;) {

19
progs.c
View File

@ -3,7 +3,7 @@
extern char _USERMODE, _USERMODE_END;
extern uint32_t create_user_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
void ProgramLoadTest(char *path, dirent *de) {
void ProgramLoadTest(char *path) {
uint16_t *vga_text = (uint16_t *)0xb8000;
for (int i = 0; i < 80*25; i++)
vga_text[i] = 0x0f00;
@ -11,7 +11,13 @@ void ProgramLoadTest(char *path, dirent *de) {
uint8_t *diskReadBuf = (uint8_t *)&_USERMODE;
{
uint32_t err;
uint8_t *scratch = (uint8_t *)0x20000;
dirent de;
err = path_getinfo(path, &de);
if (de.size > 0x300000 || err) {
vga_text += printStr("File too large or error.", vga_text);
kbd_wait();
return;
}
FILE file;
err = file_open(&file, path, OPENREAD);
if (err) {
@ -19,18 +25,13 @@ void ProgramLoadTest(char *path, dirent *de) {
printDword(err, vga_text);
return;
}
if (de->size > 0x300000) {
vga_text += printStr("File too large.", vga_text);
kbd_wait();
return;
}
err = file_seek(&file, 0);
if (err) {
vga_text += printStr("Seek Error", vga_text);
return;
}
err = file_read(&file, diskReadBuf, de->size);
if (!err && de->size > 0) {
successcount = err = file_read(&file, diskReadBuf, de.size);
if (!err && de.size > 0) {
vga_text += printStr("Read Error", vga_text);
printDword(err, vga_text);
return;

View File

@ -7,6 +7,6 @@
#include "helper.h"
#include "file.h"
void HexEditor(char *path, dirent *de);
void TextViewTest(char *path, dirent *de);
void ProgramLoadTest(char *path, dirent *de);
void HexEditor(char *path);
void TextViewTest(char *path);
void ProgramLoadTest(char *path);

View File

@ -12,12 +12,19 @@ uint8_t editedBlocks[TOTALBLOCKS] __attribute__((section(".textbss")));;
uint8_t fileBuffer[MAXFILESIZE]
__attribute__((aligned(0x1000)))
__attribute__((section(".textlatebss")));
void TextViewTest(char *path, dirent *de) {
void TextViewTest(char *path) {
uint16_t *vga_text = (uint16_t *)0xb8000;
uint32_t fileLen = de->size;
uint32_t fileLen;
{
uint32_t err;
uint8_t *scratch = (uint8_t *)0x20000;
dirent de;
err = path_getinfo(path, &de);
if (err) {
vga_text += printStr("Error getting file info.", vga_text);
kbd_wait();
return;
}
fileLen = de.size;
FILE file;
err = file_open(&file, path, OPENREAD);
if (err) {