Filesystem now uses an abstract representation

This commit is contained in:
Lucia Ceionia 2023-02-14 23:48:11 -06:00
parent 1b2184fe52
commit 5fe565b6f7
18 changed files with 585 additions and 236 deletions

View File

@ -1,5 +1,6 @@
objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o dosfs/dosfs.o gdt.o\
paging.o fault.o tests.o kbd.o helper.o progs.o disk.o hexedit.o textedit.o
objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o gdt.o\
paging.o fault.o tests.o kbd.o helper.o disk.o file.o fs.o dosfs/dosfs.o fs_dos.o\
progs.o hexedit.o textedit.o
CFLAGS = -target "i686-elf" -m32 -mgeneral-regs-only -ffreestanding\
-march=i686 -fno-stack-protector -Wno-int-conversion -nostdlib -c
LFLAGS = -Wl,--gc-sections -Wl,--print-gc-sections -m32 -nostartfiles -nostdlib

6
disk.c
View File

@ -1,11 +1,11 @@
#include "disk.h"
#include "v86defs.h"
#include "print.h"
#include "dosfs/dosfs.h"
#include "stdint.h"
extern void *memcpy(void *restrict dest, const void *restrict src, uintptr_t n);
#define SECTOR_SIZE 512
#define DISKCACHEBLOCKSIZE 0x1000 // 512 * 4
#define DISKCACHESECTORMASK 7
#define DISKCACHESECTORSIZE 8
@ -104,7 +104,7 @@ void InitDisk() {
Disk_SetupCHS();
}
uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
uint32_t Disk_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
uint8_t *cache = FindInCache(sector);
if (cache) {
memcpy(buffer, cache, count * SECTOR_SIZE);
@ -158,7 +158,7 @@ uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t
memcpy(buffer, v86buf, count * SECTOR_SIZE);
return 0;
}
uint32_t DFS_WriteSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
uint32_t Disk_WriteSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
// NOTE If the buffer provided is outside the 0x20000-0x2FE00 range,
// the function will use copy that buffer into the Virtual 8086 disk range
uint8_t *v86buf = buffer;

6
disk.h
View File

@ -1 +1,7 @@
#pragma once
#include <stdint.h>
void InitDisk();
uint32_t Disk_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count);
uint32_t Disk_WriteSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count);

78
file.c Normal file
View File

@ -0,0 +1,78 @@
#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;
// 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);
}
// Returns 0 on success, non-zero error code on error.
int file_seek(FILE *file, uint32_t offset) {
filesystem *fs = &(*FilesystemTable)[0];
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];
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];
return fs->ops.file_write(fs->fs_data, file, src, len);
}
void file_close(FILE *file) {
filesystem *fs = &(*FilesystemTable)[0];
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);
}
// 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];
return fs->ops.dir_nextentry(fs->fs_data, dir, ent);
}
void dir_close(DIR *dir) {
filesystem *fs = &(*FilesystemTable)[0];
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);
}
// 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);
}
// 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);
}
// 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);
}

36
file.h Normal file
View File

@ -0,0 +1,36 @@
#pragma once
#include "file_s.h"
// Returns 0 on success, non-zero error code on error. Fills provided struct FILE
int file_open(FILE *file, char *path, char mode);
// Returns 0 on success, non-zero error code on error.
int file_seek(FILE *file, uint32_t offset);
// Returns 0 on error, bytes read on success.
int file_read(FILE *file, uint8_t *dest, uint32_t len);
// Returns 0 on error, bytes written on success.
int file_write(FILE *file, uint8_t *src, uint32_t len);
void file_close(FILE *file);
// Returns 0 on success, non-zero error code on error. Fills provided struct DIR
int dir_open(DIR *dir, char *path);
// Return 0 on success, non-zero error code on error. Fills provided struct dirent.
int dir_nextentry(DIR *dir, dirent *ent);
void dir_close(DIR *dir);
// Returns 0 on success, non-zero error code on error. Fills provided struct dirent.
int path_getinfo(char *path, dirent *ent);
// Returns 0 on success, non-zero error code on error.
int path_mkdir(char *path);
// Returns 0 on success, non-zero error code on error.
int path_rmdir(char *path);
// Returns 0 on success, non-zero error code on error.
int path_rmfile(char *path);

31
file_s.h Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#include <stdint.h>
typedef struct FILE {
uint8_t filesystem_id;
uint8_t bytes[0x3F];
} __attribute__((__packed__)) FILE;
typedef struct DIR {
uint8_t filesystem_id;
uint8_t bytes[0x3F];
} __attribute__((__packed__)) DIR;
typedef enum filetype {
FT_UNKNOWN,
FT_REG,
FT_DIR
} filetype;
typedef struct dirent {
filetype type;
uint32_t size;
uint32_t last_modified;
uint32_t last_accessed;
uint32_t created;
uint8_t namelen;
char name[255];
} dirent;
#define OPENREAD 1
#define OPENWRITE 2

36
fs.c Normal file
View File

@ -0,0 +1,36 @@
#include "fs.h"
struct FsType {
uint32_t type_id;
int (*init_func)(filesystem *, char);
// Not yet decided
char (*detect_func)();
};
// TODO Get these dynamically somehow
int InitDosFs(filesystem *fs, char partition);
char DetectDosPart();
struct FsType SupportedFilesystems[] = {
{
.type_id = 0xD05,
.init_func = InitDosFs,
.detect_func = DetectDosPart
}
};
#define MAXFS (0x20000/sizeof(filesystem))
filesystem (*const ActiveFilesystems)[MAXFS] = (filesystem (* const)[MAXFS])0x240000;
// TODO Replace with something better
uint8_t ActiveFsId;
// 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;
}

28
fs.h Normal file
View File

@ -0,0 +1,28 @@
#include <stdint.h>
#include "file_s.h"
typedef struct filesystem {
uint8_t id;
uint8_t resv0;
uint16_t resv1;
uint32_t type;
struct fs_operations {
int (*file_open)(uint8_t *, FILE *, char *, char);
int (*file_seek)(uint8_t *, FILE *, uint32_t);
int (*file_read)(uint8_t *, FILE *, uint8_t *, uint32_t);
int (*file_write)(uint8_t *, FILE *, uint8_t *, uint32_t);
void (*file_close)(uint8_t *, FILE *);
int (*dir_open)(uint8_t *, DIR *, char *);
int (*dir_nextentry)(uint8_t *, DIR *, dirent *);
void (*dir_close)(uint8_t *, DIR *);
int (*path_getinfo)(uint8_t *, char *, dirent *);
int (*path_mkdir)(uint8_t *, char *);
int (*path_rmdir)(uint8_t *, char *);
int (*path_rmfile)(uint8_t *, char *);
void (*endfs)(uint8_t *);
} ops;
uint8_t labellen;
char label[255];
uint8_t fs_data[512-4-4-44-256];
} __attribute__((packed)) filesystem;

192
fs_dos.c Normal file
View File

@ -0,0 +1,192 @@
#include "disk.h"
#include "fs.h"
#include "dosfs/dosfs.h"
// Implementations for DOSFS
uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
return Disk_ReadSector(unit, buffer, sector, count);
}
uint32_t DFS_WriteSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) {
return Disk_WriteSector(unit, buffer, sector, count);
}
// System Implementations
typedef struct fsdat {
VOLINFO vi;
} fsdat;
int file83ToPath(uint8_t *src, char *path) {
uint8_t tmp, trailingSpace;
for (trailingSpace=0, tmp = 0; tmp < 8 && src[tmp]; tmp++) {
path[tmp] = src[tmp];
if (src[tmp] == ' ') trailingSpace++;
else trailingSpace = 0;
}
tmp -= trailingSpace;
path[tmp++] = '.';
trailingSpace = 0;
for (int i = 8; i < 11 && src[i]; i++, tmp++) {
path[tmp] = src[i];
if (src[i] == ' ') trailingSpace++;
else trailingSpace = 0;
}
tmp -= trailingSpace;
if (trailingSpace == 3) tmp--;
path[tmp] = 0;
return tmp;
}
int dos_file_open(uint8_t *dat, FILE *f, char *path, char mode) {
fsdat *fs = (fsdat *)dat;
uint8_t *scratch = (uint8_t *)0x20000;
uint8_t dfs_mode =
(mode & OPENREAD ? DFS_READ : 0) |
(mode & OPENWRITE ? DFS_WRITE : 0);
return DFS_OpenFile(&fs->vi, (uint8_t *)path, dfs_mode, scratch, (FILEINFO *)f->bytes);
}
int dos_file_seek(uint8_t *dat, FILE *f, uint32_t offset) {
fsdat *fs = (fsdat *)dat;
uint8_t *scratch = (uint8_t *)0x20000;
DFS_Seek((FILEINFO *)f->bytes, offset, scratch);
if (((FILEINFO *)f->bytes)->pointer != offset) return -1;
return 0;
}
int dos_file_read(uint8_t *dat, FILE *f, uint8_t *dest, uint32_t len) {
fsdat *fs = (fsdat *)dat;
uint8_t *scratch = (uint8_t *)0x20000;
uint32_t successcount;
uint32_t err = DFS_ReadFile((FILEINFO *)f->bytes, scratch, dest, &successcount, len);
// Error
if (err != 0 && err != DFS_EOF)
return 0;
// Success or EOF
return successcount;
}
int dos_file_write(uint8_t *dat, FILE *f, uint8_t *src, uint32_t len) {
fsdat *fs = (fsdat *)dat;
uint8_t *scratch = (uint8_t *)0x20000;
uint32_t successcount;
uint32_t err = DFS_WriteFile((FILEINFO *)f->bytes, scratch, src, &successcount, len);
// Error
if (err != 0) return 0;
// Success
return successcount;
}
// DOSFS doesn't have anything to clean up
void dos_file_close(uint8_t *dat, FILE *f) { return; }
int dos_dir_open(uint8_t *dat, DIR *d, char *path) {
fsdat *fs = (fsdat *)dat;
uint8_t *scratch = (uint8_t *)0x20000;
((DIRINFO *)d->bytes)->scratch = scratch;
return DFS_OpenDir(&fs->vi, (uint8_t *)path, (DIRINFO *)d->bytes);
}
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);
if (code == DFS_EOF) return 1;
if (code != DFS_OK) return -1;
// Deleted file, continue to next entry
if (de.name[0] == 0) continue;
break;
}
// Copy info
ent->type = de.attr & ATTR_DIRECTORY ? FT_DIR : FT_REG;
ent->size = (uint32_t)de.filesize_0 +
((uint32_t)de.filesize_1 << 8) +
((uint32_t)de.filesize_2 << 16) +
((uint32_t)de.filesize_3 << 24);
// Haven't decided format on these yet
ent->last_modified = 0;
ent->last_accessed = 0;
ent->created = 0;
ent->namelen = file83ToPath(de.name, ent->name);
return 0;
}
// DOSFS doesn't have anything to clean up
void dos_dir_close(uint8_t *dat, DIR *d) { return; }
// TODO Unimplemented
int dos_path_getinfo(uint8_t *dat, char *path, dirent *d) {
fsdat *fs = (fsdat *)dat;
uint8_t *scratch = (uint8_t *)0x20000;
return -1;
}
// TODO Unimplemented
int dos_path_mkdir(uint8_t *dat, char *path) {
fsdat *fs = (fsdat *)dat;
uint8_t *scratch = (uint8_t *)0x20000;
return -1;
}
// TODO Unimplemented
int dos_path_rmdir(uint8_t *dat, char *path) {
fsdat *fs = (fsdat *)dat;
uint8_t *scratch = (uint8_t *)0x20000;
return -1;
}
// TODO Unimplemented
int dos_path_rmfile(uint8_t *dat, char *path) {
fsdat *fs = (fsdat *)dat;
uint8_t *scratch = (uint8_t *)0x20000;
return -1;
}
// DOSFS doesn't have anything to clean up
void dos_endfs(uint8_t *dat) { return; }
// Not yet decided
char DetectDosPart() {
return 1;
}
int InitDosFs(filesystem *fs, char partition) {
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)) {
return -1;
}
int i;
for (i = 0; vi->label[i] && i < sizeof(vi->label); i++)
fs->label[i] = vi->label[i];
fs->labellen = i;
fs->ops.file_open = dos_file_open;
fs->ops.file_seek = dos_file_seek;
fs->ops.file_read = dos_file_read;
fs->ops.file_write = dos_file_write;
fs->ops.file_close = dos_file_close;
fs->ops.dir_open = dos_dir_open;
fs->ops.dir_nextentry = dos_dir_nextentry;
fs->ops.dir_close = dos_dir_close;
fs->ops.path_getinfo = dos_path_getinfo;
fs->ops.path_mkdir = dos_path_mkdir;
fs->ops.path_rmdir = dos_path_rmdir;
fs->ops.path_rmfile = dos_path_rmfile;
fs->ops.endfs = dos_endfs;
return 0;
}

View File

@ -48,55 +48,6 @@ void SetCursorDisabled() {
V8086Int(0x10, &regs);
}
// This should DEFINITELY be an argument
uint8_t SystemPartition = 0;
uint32_t OpenVol(VOLINFO *vi) {
uint8_t *diskReadBuf = (uint8_t *)0x20000;
uint8_t pactive, ptype;
uint32_t pstart, psize;
pstart = DFS_GetPtnStart(0, diskReadBuf, SystemPartition, &pactive, &ptype, &psize);
if (pstart == -1) return -1;
return DFS_GetVolInfo(0, diskReadBuf, pstart, vi);
}
uint32_t OpenDir(uint8_t *path, VOLINFO *vi, DIRINFO *di) {
uint8_t *diskReadBuf = (uint8_t *)0x20000;
di->scratch = diskReadBuf;
return DFS_OpenDir(vi, path, di);
}
void File83ToPath(char *src, char *path) {
uint8_t tmp, trailingSpace;
for (trailingSpace=0, tmp = 0; tmp < 8 && src[tmp]; tmp++) {
path[tmp] = src[tmp];
if (src[tmp] == ' ') trailingSpace++;
else trailingSpace = 0;
}
tmp -= trailingSpace;
path[tmp++] = '.';
trailingSpace = 0;
for (int i = 8; i < 11 && src[i]; i++, tmp++) {
path[tmp] = src[i];
if (src[i] == ' ') trailingSpace++;
else trailingSpace = 0;
}
tmp -= trailingSpace;
if (trailingSpace == 3) tmp--;
path[tmp] = 0;
}
void GetFileList(DIRENT *entries, int32_t *entCount, int32_t maxEntries, VOLINFO *vi, DIRINFO *di) {
uint8_t *diskReadBuf = (uint8_t *)0x20000;
DIRENT de;
int32_t fileCount = 0;
while (!DFS_GetNext(vi, di, &de)) {
if (de.name[0]) {
uint8_t *d = (uint8_t*)&entries[fileCount];
uint8_t *s = (uint8_t*)&de;
for (int i = 0; i < sizeof(DIRENT); i++)
d[i] = s[i];
fileCount++;
}
if (fileCount >= maxEntries) break;
}
*entCount = fileCount;
void GetFileList(DIR *dir, dirent *entries, int32_t *entCount, int32_t maxEntries) {
for ((*entCount) = 0; *entCount < maxEntries && !dir_nextentry(dir, &entries[*entCount]); (*entCount)++);
}

View File

@ -3,7 +3,7 @@
#include "interrupt.h"
#include "v86defs.h"
#include "dosfs/dosfs.h"
#include "file.h"
void V8086Int(uint8_t interrupt, union V86Regs_t *regs);
@ -14,7 +14,4 @@ void SetCursorDisabled();
uint16_t *nextLine(uint16_t *p, uint16_t *b);
void trimPath(char *path, char *buff, uint32_t maxLen);
uint32_t OpenVol(VOLINFO *vi);
uint32_t OpenDir(uint8_t *path, VOLINFO *vi, DIRINFO *di);
void File83ToPath(char *src, char *path);
void GetFileList(DIRENT *entries, int32_t *entCount, int32_t maxEntries, VOLINFO *vi, DIRINFO *di);
void GetFileList(DIR *dir, dirent *entries, int32_t *entCount, int32_t maxEntries);

View File

@ -1,3 +1,4 @@
#include "file.h"
#include "progs.h"
#define BLOCKSIZE 0x10000 // 64K
@ -11,37 +12,38 @@ 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(uint8_t *path, VOLINFO *vi) {
void HexEditor(char *path, dirent *de) {
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;
FILEINFO fi;
FILE file;
vga_text = (uint16_t *)0xb8000;
for (int i = 0; i < 80*50; i++)
vga_text[i] = 0x0f00;
err = DFS_OpenFile(vi, path, DFS_READ | DFS_WRITE, scratch, &fi);
err = file_open(&file, path, OPENREAD|OPENWRITE);
if (err) {
vga_text += printStr("Open Error: ", vga_text);
printDword(err, vga_text);
kbd_wait();
return;
}
if (fi.filelen == 0) {
if (filelen == 0) {
vga_text += printStr("File ", vga_text);
vga_text += printStr((char*)path, vga_text);
vga_text += printStr(" has no data.", vga_text);
kbd_wait();
return;
}
if (fi.filelen > MAXFILESIZE) {
if (filelen > MAXFILESIZE) {
vga_text += printStr("File ", vga_text);
vga_text += printStr((char*)path, vga_text);
vga_text += printStr(" is too large (> 2GB).", vga_text);
@ -70,13 +72,13 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
// things will be caught by sanity checks.
// Scroll Back
if (cursorScreenOff < 0) {
if (drawOffset - 16 < fi.filelen)
if (drawOffset - 16 < filelen)
drawOffset -= 16;
cursorScreenOff += 16;
}
// Scroll Forward
if (cursorScreenOff >= byteCount) {
if (drawOffset + 16 < fi.filelen)
if (drawOffset + 16 < filelen)
drawOffset += 16;
cursorScreenOff -= 16;
}
@ -84,8 +86,8 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
// Sanity checks
if (cursorScreenOff >= byteCount)
cursorScreenOff = byteCount - 1;
if (cursorScreenOff + drawOffset >= fi.filelen)
cursorScreenOff = fi.filelen - drawOffset - 1;
if (cursorScreenOff + drawOffset >= filelen)
cursorScreenOff = filelen - drawOffset - 1;
if (cursorScreenOff < 0) cursorScreenOff = 0;
if (cursorNibble != lastCursorNibble)
@ -185,16 +187,14 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
} else {
uint32_t blockOffset = drawOffset & BLOCKMASK;
vga_text = &((uint16_t*)0xb8000)[80];
DFS_Seek(&fi, blockOffset, scratch);
if (fi.pointer != blockOffset) {
if (file_seek(&file, blockOffset)) {
vga_text += printStr("Seek Error", vga_text);
kbd_wait();
return;
}
err = DFS_ReadFile(&fi, scratch, screenBuff, &currBuffLength, BLOCKSIZE);
if (err && err != DFS_EOF) {
vga_text += printStr("Read Error: ", vga_text);
printDword(err, vga_text);
currBuffLength = file_read(&file, screenBuff, BLOCKSIZE);
if (!currBuffLength && blockOffset != filelen) {
vga_text += printStr("Read Error", vga_text);
kbd_wait();
return;
}
@ -222,16 +222,14 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
} else {
uint32_t blockOffset = (drawOffset & BLOCKMASK) + BLOCKSIZE;
vga_text = &((uint16_t*)0xb8000)[80];
DFS_Seek(&fi, blockOffset, scratch);
if (fi.pointer != blockOffset) {
if (file_seek(&file, blockOffset)) {
vga_text += printStr("Seek Error", vga_text);
kbd_wait();
return;
}
err = DFS_ReadFile(&fi, scratch, &screenBuff[BLOCKSIZE], &nextBuffLength, BLOCKSIZE);
if (err && err != DFS_EOF) {
vga_text += printStr("Read Error: ", vga_text);
printDword(err, vga_text);
nextBuffLength = file_read(&file, &screenBuff[BLOCKSIZE], BLOCKSIZE);
if (!nextBuffLength && blockOffset != filelen) {
vga_text += printStr("Read Error", vga_text);
kbd_wait();
return;
}
@ -301,12 +299,12 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
switch (key & 0xff) {
case KEY_DOWN:
// Stay in file
if ((cursorScreenOff + 16 + drawOffset) < fi.filelen)
if ((cursorScreenOff + 16 + drawOffset) < filelen)
cursorScreenOff += 16;
break;
case KEY_UP:
// Stay in file
if ((uint32_t)(cursorScreenOff - 16 + drawOffset) < fi.filelen)
if ((uint32_t)(cursorScreenOff - 16 + drawOffset) < filelen)
cursorScreenOff -= 16;
break;
case KEY_LEFT:
@ -316,7 +314,7 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
cursorNibble = 0;
cursorScreenOff |= 0xF;
// Stay in file
} else if ((cursorScreenOff - 1 + drawOffset) < fi.filelen) {
} else if ((cursorScreenOff - 1 + drawOffset) < filelen) {
cursorScreenOff--;
if (cursorNibble == 1) cursorNibble = 0;
}
@ -328,19 +326,19 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
cursorNibble = 2;
cursorScreenOff &= ~0xF;
// Stay in file
} else if ((cursorScreenOff + 1 + drawOffset) < fi.filelen) {
} else if ((cursorScreenOff + 1 + drawOffset) < filelen) {
cursorScreenOff++;
if (cursorNibble == 0) cursorNibble = 1;
}
break;
case KEY_PGDOWN:
if (drawOffset + byteCount < fi.filelen)
if (drawOffset + byteCount < filelen)
drawOffset += byteCount;
else if ((fi.filelen / byteCount) * byteCount > drawOffset)
drawOffset = (fi.filelen / byteCount) * byteCount;
else if ((filelen / byteCount) * byteCount > drawOffset)
drawOffset = (filelen / byteCount) * byteCount;
break;
case KEY_PGUP:
if (drawOffset - byteCount < fi.filelen)
if (drawOffset - byteCount < filelen)
drawOffset -= byteCount;
else drawOffset = 0;
break;
@ -359,8 +357,8 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
drawOffset = 0;
break;
case KEY_F4: // end of file
if ((fi.filelen / byteCount) * byteCount > drawOffset)
drawOffset = (fi.filelen / byteCount) * byteCount;
if ((filelen / byteCount) * byteCount > drawOffset)
drawOffset = (filelen / byteCount) * byteCount;
break;
case KEY_F6: // TODO write file
break;
@ -425,23 +423,21 @@ void HexEditor(uint8_t *path, VOLINFO *vi) {
for(;(key & 0xff) != KEY_N && (key & 0xff) != KEY_Y;key = get_scancode());
if ((key & 0xff) != KEY_Y) return;
// Write changes
for (int i = 0; i < TOTALBLOCKS && (i << BLOCKSHIFT) < fi.filelen; i++) {
for (int i = 0; i < TOTALBLOCKS && (i << BLOCKSHIFT) < filelen; i++) {
// No change in current block
uint16_t blockIdx = writtenMap[i];
uint32_t blockLen = blockLenMap[i];
if (!blockIdx) continue;
// Write block to file
uint32_t successcount;
uint32_t blockOff = i << BLOCKSHIFT;
DFS_Seek(&fi, blockOff, scratch);
if (fi.pointer != blockOff) {
if (file_seek(&file, blockOff)) {
vga_text = (uint16_t*)0xb8000;
vga_text += printStr("Seek Error ", vga_text);
kbd_wait();
return;
}
uint32_t err = DFS_WriteFile(&fi, scratch, writeStore[blockIdx], &successcount, blockLen);
if (successcount < blockLen || err) {
uint32_t successcount = file_write(&file, writeStore[blockIdx], blockLen);
if (successcount < blockLen) {
vga_text = (uint16_t*)0xb8000;
vga_text += printStr("Write Error ", vga_text);
kbd_wait();

View File

@ -1,6 +1,6 @@
#include <stdint.h>
#include "dosfs/dosfs.h"
#include "file.h"
#include "print.h"
#include "interrupt.h"
#include "kbd.h"
@ -182,7 +182,9 @@ Protected Only (1MB+)
100000 - 200000 Kernel Code (1mB)
200000 - 200080 TSS (128B)
200080 - 202080 TSS IOMAP (8kB)
202080 - 300000 Free (~1/2mB)
202080 - 208000 Free (~24kB)
208000 - 240000 Kernel File Stack (224kB)
240000 - 280000 Active Filesystems (128kB)
280000 - 300000 Disk Cache (512kB)
300000 - 310000 Task Stack (64kB)
310000 - 320000 Interrupt Stack (64kB)
@ -191,9 +193,6 @@ Protected Only (1MB+)
700000 - 800000 Usermode Stack (1mB)
*/
// FIXME Truly awful
extern uint8_t SystemPartition;
void DrawScreen(uint16_t *vga) {
uint16_t *vga_text = vga;
// clear screen
@ -227,7 +226,6 @@ void DrawScreen(uint16_t *vga) {
vga_text[80+42] = 0x1f00 | 'S';
vga_text[80+43] = 0x1f00 | ' ';
vga_text[80+44] = 0x1f00 | '-';
printByte(SystemPartition, &vga_text[80+50]);
}
void SetPalette() {
@ -253,28 +251,22 @@ int32_t fileCount, fileOffset;
// after every task called. This might be fine,
// since the task might have modified the directory.
extern char _USERMODE;
DIRENT *const DirEntries = (DIRENT*)&_USERMODE;
dirent *const DirEntries = (dirent*)&_USERMODE;
#define MAXDISPFILES 16
void PrintFileList(uint16_t *vga) {
uint16_t *vga_text = &((uint16_t *)vga)[80*6+3];
for (int i = 0; (i + fileOffset) < fileCount && i < MAXDISPFILES; i++) {
DIRENT *de = &DirEntries[i + fileOffset];
for (int i = 0; i < 11 && de->name[i]; i++) {
if (i == 8) { *(uint8_t*)vga_text = ' '; vga_text++; } // space for 8.3
*(uint8_t *)vga_text = de->name[i];
vga_text++;
}
dirent *de = &DirEntries[i + fileOffset];
de->name[de->namelen < 20 ? de->namelen : 20] = 0;
vga_text += printStr(de->name, vga_text);
vga_text += printStr(" ", vga_text);
vga_text += printDec((uint32_t)de->filesize_0 +
((uint32_t)de->filesize_1 << 8) +
((uint32_t)de->filesize_2 << 16) +
((uint32_t)de->filesize_3 << 24), vga_text);
vga_text += printDec(de->size, vga_text);
*(uint8_t*)vga_text++ = 'B';
vga_text = nextLine(vga_text, vga) + 3;
}
}
char IsDir(DIRENT *de) {
return de->attr & ATTR_DIRECTORY;
char IsDir(dirent *de) {
return de->type == FT_DIR;
}
void ScancodeTest() {
uint16_t *vga = (uint16_t*)0xb8000;
@ -289,7 +281,7 @@ void ScancodeTest() {
extern void create_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
uint16_t FileSelectScreen[80*25];
void FileSelect() {
uint8_t current_path[80];
char current_path[80];
uintptr_t current_path_end;
for (int i = 0; i < sizeof(current_path); i++)
current_path[i] = 0;
@ -314,15 +306,14 @@ void FileSelect() {
vga += 80;
printStr("F4 to run tests", vga);
}
printStr((char*)current_path, &vga_text[80*4 + 2]);
printStr(current_path, &vga_text[80*4 + 2]);
for (int i = 2; i < 15; i++)
*(uint8_t*)&vga_text[80*5 + i] = '-';
VOLINFO vi; DIRINFO di;
DIR dir;
if (reload) {
OpenVol(&vi);
current_path[current_path_end] = 0;
OpenDir(current_path, &vi, &di);
GetFileList(DirEntries, &fileCount, INT32_MAX, &vi, &di);
dir_open(&dir, current_path);
GetFileList(&dir, DirEntries, &fileCount, INT32_MAX);
reload = 0;
}
if (fileHovered >= fileCount) {
@ -365,23 +356,32 @@ void FileSelect() {
break;
case KEY_P:
if (IsDir(&DirEntries[fileHovered])) break;
File83ToPath((char*)DirEntries[fileHovered].name, (char*)&current_path[current_path_end]);
create_child(GetFreeStack(), (uintptr_t)ProgramLoadTest, 2, current_path, &vi);
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]);
current_path[current_path_end] = 0;
RestoreVGA();
reload = 1;
break;
case KEY_X:
if (IsDir(&DirEntries[fileHovered])) break;
File83ToPath((char*)DirEntries[fileHovered].name, (char*)&current_path[current_path_end]);
create_child(GetFreeStack(), (uintptr_t)HexEditor, 2, current_path, &vi);
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]);
current_path[current_path_end] = 0;
RestoreVGA();
reload = 1;
break;
case KEY_T:
if (IsDir(&DirEntries[fileHovered])) break;
File83ToPath((char*)DirEntries[fileHovered].name, (char*)&current_path[current_path_end]);
//TextViewTest(path, &vi);
create_child(GetFreeStack(), (uintptr_t)TextViewTest, 2, current_path, &vi);
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]);
current_path[current_path_end] = 0;
RestoreVGA();
reload = 1;
break;
@ -389,7 +389,12 @@ void FileSelect() {
case 0x9C: // enter release
if (IsDir(&DirEntries[fileHovered])) {
uint8_t tmp_path[80];
File83ToPath((char*)DirEntries[fileHovered].name, (char*)tmp_path);
{
int i;
for (i = 0; i < DirEntries[fileHovered].namelen && i < sizeof(tmp_path)-1; i++)
tmp_path[i] = DirEntries[fileHovered].name[i];
tmp_path[i] = 0;
}
if ((*(uint32_t*)tmp_path & 0xffff) == ('.' | 0x0000)) {
// Current dir, do nothing
break;
@ -423,17 +428,17 @@ void FileSelect() {
}
}
void SystemRun() {
int MakeSystemVolume(uint8_t sysPartition);
void SystemRun(uint8_t sysPartition) {
uint16_t *vga_text = (word *)0xb8000;
RestoreVGA();
DrawScreen((uint16_t*)0xb8000);
// Check for FAT partition
{
VOLINFO vi;
// TODO Check partitions beyond 0
while (1) {
create_child(GetFreeStack(), (uintptr_t)OpenVol, 1, &vi);
create_child(GetFreeStack(), (uintptr_t)MakeSystemVolume, 1, sysPartition);
if (!check_error_code()) break;
vga_text = &((word*)0xb8000)[80*4 + 2];
vga_text += printStr("Error loading file select. Ensure the disk has a valid MBR and FAT partition.", vga_text);
@ -526,9 +531,9 @@ void start() {
InitDisk();
// DL contained disk number, DH contained active partition
SystemPartition = boot_dx >> 8;
uint8_t SystemPartition = boot_dx >> 8;
create_child(GetFreeStack(), (uintptr_t)SystemRun, 0);
create_child(GetFreeStack(), (uintptr_t)SystemRun, 1, SystemPartition);
// If this returns, something is *very* wrong, reboot the system
// TODO Maybe try to recover?

23
progs.c
View File

@ -1,10 +1,11 @@
#include "progs.h"
#include "file.h"
// 400000 - 700000 Usermode Code (3mB)
// 700000 - 800000 Usermode Stack (1mB)
extern char _USERMODE;
extern uint32_t create_user_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
void ProgramLoadTest(uint8_t *path, VOLINFO *vi) {
void ProgramLoadTest(char *path, dirent *de) {
uint16_t *vga_text = (uint16_t *)0xb8000;
for (int i = 0; i < 80*25; i++)
vga_text[i] = 0x0f00;
@ -13,33 +14,29 @@ void ProgramLoadTest(uint8_t *path, VOLINFO *vi) {
{
uint32_t err;
uint8_t *scratch = (uint8_t *)0x20000;
FILEINFO fi;
err = DFS_OpenFile(vi, path, DFS_READ, scratch, &fi);
FILE file;
err = file_open(&file, path, OPENREAD);
if (err) {
vga_text += printStr("Open Error: ", vga_text);
printDword(err, vga_text);
return;
}
if (fi.filelen > 0x300000) {
if (de->size > 0x300000) {
vga_text += printStr("File too large.", vga_text);
kbd_wait();
return;
}
DFS_Seek(&fi, 0, scratch);
if (fi.pointer != 0) {
err = file_seek(&file, 0);
if (err) {
vga_text += printStr("Seek Error", vga_text);
return;
}
err = DFS_ReadFile(&fi, scratch, diskReadBuf, &successcount, fi.filelen);
if (err && err != DFS_EOF) {
vga_text += printStr("Read Error: ", vga_text);
err = file_read(&file, diskReadBuf, de->size);
if (!err && de->size > 0) {
vga_text += printStr("Read Error", vga_text);
printDword(err, vga_text);
return;
}
if (successcount < fi.filelen) {
vga_text += printStr("Could not read all file bytes.", vga_text);
return;
}
}
vga_text += printStr("Successfully loaded program \"", vga_text);
vga_text += printStr((char*)path, vga_text);

View File

@ -1,12 +1,12 @@
#pragma once
#include <stdint.h>
#include "dosfs/dosfs.h"
#include "print.h"
#include "kbd.h"
#include "v86defs.h"
#include "helper.h"
#include "file.h"
void HexEditor(uint8_t *path, VOLINFO *vi);
void TextViewTest(uint8_t *path, VOLINFO *vi);
void ProgramLoadTest(uint8_t *path, VOLINFO *vi);
void HexEditor(char *path, dirent *de);
void TextViewTest(char *path, dirent *de);
void ProgramLoadTest(char *path, dirent *de);

145
tests.c
View File

@ -123,79 +123,76 @@ void TestCHS() {
}
}
// FIXME Just horrible
extern uint8_t SystemPartition;
void TestFAT() {
uint16_t *vga_text = (uint16_t *)0xb8000;
uint8_t *diskReadBuf = (uint8_t *)0x22400;
for (int i = 0; i < 80*25; i++)
vga_text[i] = 0x0f00;
VOLINFO vi;
uint8_t pactive, ptype;
uint32_t pstart, psize;
pstart = DFS_GetPtnStart(0, diskReadBuf, SystemPartition, &pactive, &ptype, &psize);
vga_text = (uint16_t *)0xb8000;
vga_text += printStr("PartStart: ", vga_text);
vga_text += printDword(pstart, vga_text);
vga_text += 2;
vga_text += printStr("PartSize: ", vga_text);
vga_text += printDword(psize, vga_text);
vga_text += 2;
vga_text += printStr("PartActive: ", vga_text);
vga_text += printByte(pactive, vga_text);
vga_text += 2;
vga_text += printStr("PartType: ", vga_text);
vga_text += printByte(ptype, vga_text);
vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
//asm ("xchgw %bx, %bx");
DFS_GetVolInfo(0, diskReadBuf, pstart, &vi);
vga_text += printStr("Label: ", vga_text);
vga_text += printStr((char*)vi.label, vga_text);
vga_text += 2;
vga_text += printStr("Sec/Clus: ", vga_text);
vga_text += printByte(vi.secperclus, vga_text);
vga_text += 2;
vga_text += printStr("ResrvSec: ", vga_text);
vga_text += printWord(vi.reservedsecs, vga_text);
vga_text += 2;
vga_text += printStr("NumSec: ", vga_text);
vga_text += printDword(vi.numsecs, vga_text);
vga_text += 2;
vga_text += printStr("Sec/FAT: ", vga_text);
vga_text += printDword(vi.secperfat, vga_text);
vga_text += 2;
vga_text += printStr("FAT1@: ", vga_text);
vga_text += printDword(vi.fat1, vga_text);
vga_text += 2;
vga_text += printStr("ROOT@: ", vga_text);
vga_text += printDword(vi.rootdir, vga_text);
vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
//asm ("xchgw %bx, %bx");
vga_text += printStr("Files in root:", vga_text);
DIRINFO di;
di.scratch = diskReadBuf;
DFS_OpenDir(&vi, (uint8_t*)"", &di);
vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
DIRENT de;
while (!DFS_GetNext(&vi, &di, &de)) {
if (de.name[0]) {
for (int i = 0; i < 11 && de.name[i]; i++) {
if (i == 8) { *(uint8_t*)vga_text = ' '; vga_text++; } // space for 8.3
*(uint8_t *)vga_text = de.name[i];
vga_text++;
}
vga_text += printStr(" ", vga_text);
vga_text += printDec((uint32_t)de.filesize_0 + ((uint32_t)de.filesize_1 << 8) + ((uint32_t)de.filesize_2 << 16) + ((uint32_t)de.filesize_3 << 24), vga_text);
*(uint8_t*)vga_text++ = 'B';
vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
}
//asm ("xchgw %bx, %bx");
}
}
//void TestFAT() {
// uint16_t *vga_text = (uint16_t *)0xb8000;
// uint8_t *diskReadBuf = (uint8_t *)0x22400;
// for (int i = 0; i < 80*25; i++)
// vga_text[i] = 0x0f00;
// VOLINFO vi;
//
// uint8_t pactive, ptype;
// uint32_t pstart, psize;
// pstart = DFS_GetPtnStart(0, diskReadBuf, SystemPartition, &pactive, &ptype, &psize);
// vga_text = (uint16_t *)0xb8000;
// vga_text += printStr("PartStart: ", vga_text);
// vga_text += printDword(pstart, vga_text);
// vga_text += 2;
// vga_text += printStr("PartSize: ", vga_text);
// vga_text += printDword(psize, vga_text);
// vga_text += 2;
// vga_text += printStr("PartActive: ", vga_text);
// vga_text += printByte(pactive, vga_text);
// vga_text += 2;
// vga_text += printStr("PartType: ", vga_text);
// vga_text += printByte(ptype, vga_text);
// vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
// //asm ("xchgw %bx, %bx");
//
// DFS_GetVolInfo(0, diskReadBuf, pstart, &vi);
// vga_text += printStr("Label: ", vga_text);
// vga_text += printStr((char*)vi.label, vga_text);
// vga_text += 2;
// vga_text += printStr("Sec/Clus: ", vga_text);
// vga_text += printByte(vi.secperclus, vga_text);
// vga_text += 2;
// vga_text += printStr("ResrvSec: ", vga_text);
// vga_text += printWord(vi.reservedsecs, vga_text);
// vga_text += 2;
// vga_text += printStr("NumSec: ", vga_text);
// vga_text += printDword(vi.numsecs, vga_text);
// vga_text += 2;
// vga_text += printStr("Sec/FAT: ", vga_text);
// vga_text += printDword(vi.secperfat, vga_text);
// vga_text += 2;
// vga_text += printStr("FAT1@: ", vga_text);
// vga_text += printDword(vi.fat1, vga_text);
// vga_text += 2;
// vga_text += printStr("ROOT@: ", vga_text);
// vga_text += printDword(vi.rootdir, vga_text);
// vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
// //asm ("xchgw %bx, %bx");
//
// vga_text += printStr("Files in root:", vga_text);
// DIRINFO di;
// di.scratch = diskReadBuf;
// DFS_OpenDir(&vi, (uint8_t*)"", &di);
// vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
// DIRENT de;
// while (!DFS_GetNext(&vi, &di, &de)) {
// if (de.name[0]) {
// for (int i = 0; i < 11 && de.name[i]; i++) {
// if (i == 8) { *(uint8_t*)vga_text = ' '; vga_text++; } // space for 8.3
// *(uint8_t *)vga_text = de.name[i];
// vga_text++;
// }
// vga_text += printStr(" ", vga_text);
// vga_text += printDec((uint32_t)de.filesize_0 + ((uint32_t)de.filesize_1 << 8) + ((uint32_t)de.filesize_2 << 16) + ((uint32_t)de.filesize_3 << 24), vga_text);
// *(uint8_t*)vga_text++ = 'B';
// vga_text = (uint16_t *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
// }
// //asm ("xchgw %bx, %bx");
// }
//}
void RunTests() {
char doTests = 1;
@ -258,7 +255,7 @@ void RunTests() {
TestCHS();
kbd_wait();
TestDiskRead();
TestFAT();
//TestFAT();
break;
case 'r':
case 'R':

View File

@ -1,5 +1,4 @@
#pragma once
#include "dosfs/dosfs.h"
#include "print.h"
#include "interrupt.h"
#include "v86defs.h"

View File

@ -12,14 +12,14 @@ uint8_t editedBlocks[TOTALBLOCKS] __attribute__((section(".textbss")));;
uint8_t fileBuffer[MAXFILESIZE]
__attribute__((aligned(0x1000)))
__attribute__((section(".textlatebss")));
void TextViewTest(uint8_t *path, VOLINFO *vi) {
void TextViewTest(char *path, dirent *de) {
uint16_t *vga_text = (uint16_t *)0xb8000;
uint32_t fileLen;
uint32_t fileLen = de->size;
{
uint32_t err;
uint8_t *scratch = (uint8_t *)0x20000;
FILEINFO fi;
err = DFS_OpenFile(vi, path, DFS_READ, scratch, &fi);
FILE file;
err = file_open(&file, path, OPENREAD);
if (err) {
vga_text += printStr("Open Error: ", vga_text);
printDword(err, vga_text);
@ -27,19 +27,18 @@ void TextViewTest(uint8_t *path, VOLINFO *vi) {
return;
}
// file too large
if (fi.filelen > MAXFILESIZE) {
if (fileLen > MAXFILESIZE) {
vga_text += printStr("File too large.", vga_text);
kbd_wait();
return;
}
DFS_Seek(&fi, 0, scratch);
if (fi.pointer != 0) {
if (file_seek(&file, 0)) {
vga_text += printStr("Seek Error", vga_text);
kbd_wait();
return;
}
err = DFS_ReadFile(&fi, scratch, fileBuffer, &fileLen, fi.filelen);
if (err && err != DFS_EOF) {
uint32_t bytesRead = file_read(&file, fileBuffer, fileLen);
if (bytesRead < fileLen) {
vga_text += printStr("Read Error: ", vga_text);
printDword(err, vga_text);
kbd_wait();