// io_file.c - VFS dispatch layer #include #include #include #include #include #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); }