114 lines
4.1 KiB
C
114 lines
4.1 KiB
C
// io_file.c - VFS dispatch layer
|
|
#include <string.h>
|
|
#include <ke_list.h>
|
|
#include <io_file.h>
|
|
#include <mm_virt.h>
|
|
#include <ob_object.h>
|
|
|
|
#define MAX_DRIVES 8
|
|
|
|
typedef struct {
|
|
IO_FILESYSTEM *Fs;
|
|
IO_VOLUME_PARAMS Vol;
|
|
} VOLUME_ENTRY;
|
|
|
|
static VOLUME_ENTRY gVolumes[MAX_DRIVES];
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Registration
|
|
// ---------------------------------------------------------------------------
|
|
__declspec(dllexport) KSTATUS IoRegisterFilesystem(uint8_t volumeIndex,
|
|
IO_FILESYSTEM *fs,
|
|
const IO_VOLUME_PARAMS *vol) {
|
|
if (volumeIndex >= MAX_DRIVES || !fs || !vol)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (gVolumes[volumeIndex].Fs)
|
|
return STATUS_ALREADY_EXISTS;
|
|
gVolumes[volumeIndex].Fs = fs;
|
|
gVolumes[volumeIndex].Vol = *vol;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Path parsing - "0:\apps\shell.exe" or just "apps\shell.exe" (drive 0)
|
|
// ---------------------------------------------------------------------------
|
|
static uint8_t ParseDrive(const char* path, const char **pathOut) {
|
|
// Accept "N:\..." prefix, otherwise default to drive 0.
|
|
if (path[0] >= '0' && path[0] <= '7' &&
|
|
path[1] == ':' && (path[2] == '\\' || path[2] == '/')) {
|
|
*pathOut = path + 3;
|
|
return (uint8_t)(path[0] - '0');
|
|
}
|
|
*pathOut = path;
|
|
return 0;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Destructor
|
|
// ---------------------------------------------------------------------------
|
|
static void FileDestroy(OBJECT* obj) {
|
|
FILE_OBJECT* f = CONTAINING_RECORD(obj, FILE_OBJECT, Header);
|
|
if (f->Fs && f->FileCtx) f->Fs->Close(f->Fs, f->FileCtx);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// IoOpenFile
|
|
// ---------------------------------------------------------------------------
|
|
__declspec(dllexport) KSTATUS IoOpenFile(const char* path, FILE_OBJECT **out) {
|
|
if (!path || !out) return STATUS_INVALID_PARAMETER;
|
|
|
|
const char* relPath;
|
|
uint8_t drive = ParseDrive(path, &relPath);
|
|
|
|
IO_FILESYSTEM* fs = gVolumes[drive].Fs;
|
|
if (!fs) return STATUS_NOT_FOUND;
|
|
|
|
void* fileCtx;
|
|
KSTATUS s = fs->Open(fs, relPath, &fileCtx);
|
|
if (!KSUCCESS(s)) return s;
|
|
|
|
FILE_OBJECT* f = (FILE_OBJECT *)ObAllocateObject(ObjectTypeFile /* reuse slot */,
|
|
sizeof(FILE_OBJECT));
|
|
if (!f) { fs->Close(fs, fileCtx); return STATUS_NO_MEMORY; }
|
|
f->Header.Destroy = FileDestroy;
|
|
f->Fs = fs;
|
|
f->FileCtx = fileCtx;
|
|
f->Size = fs->GetSize(fs, fileCtx);
|
|
f->Offset = 0;
|
|
|
|
*out = f;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// IoReadFile - sequential read at current offset
|
|
// ---------------------------------------------------------------------------
|
|
__declspec(dllexport) KSTATUS IoReadFile(FILE_OBJECT* file, void* buf, size_t size, size_t* bytesRead) {
|
|
if (!file || !buf) return STATUS_INVALID_PARAMETER;
|
|
if (file->Offset >= file->Size) { *bytesRead = 0; return STATUS_SUCCESS; }
|
|
|
|
// Clamp to remaining bytes.
|
|
size_t remaining = (size_t)(file->Size - file->Offset);
|
|
if (size > remaining) size = remaining;
|
|
|
|
KSTATUS s = file->Fs->Read(file->Fs, file->FileCtx,
|
|
file->Offset, buf, size, bytesRead);
|
|
if (KSUCCESS(s)) file->Offset += *bytesRead;
|
|
return s;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
__declspec(dllexport) KSTATUS IoSeekFile(FILE_OBJECT* file, uint64_t offset) {
|
|
if (!file) return STATUS_INVALID_PARAMETER;
|
|
file->Offset = offset;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
__declspec(dllexport) uint64_t IoGetFileSize(FILE_OBJECT* file) {
|
|
return file ? file->Size : 0;
|
|
}
|
|
|
|
__declspec(dllexport) void IoCloseFile(FILE_OBJECT* file) {
|
|
if (file) ObDereferenceObject(&file->Header);
|
|
}
|