feat: vfs - add stat syscall

This commit is contained in:
2026-07-21 14:23:06 +02:00
parent 5c02c5fe79
commit de7edaf623
12 changed files with 110 additions and 1 deletions
+1 -1
View File
@@ -12,4 +12,4 @@
#pragma once
#define MONTAUK_BUILD_NUMBER 2
#define MONTAUK_BUILD_NUMBER 4
+17
View File
@@ -116,6 +116,23 @@ namespace montauk::abi {
return Fs::Vfs::VfsDelete(resolved);
}
static int Sys_Stat(const char* path, FileStat* out) {
if (out == nullptr) return -1;
char resolved[256];
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
Fs::Vfs::StatInfo info;
if (Fs::Vfs::VfsStat(resolved, info) != 0) return -1;
out->size = info.size;
out->mtime = info.mtime;
out->ctime = info.ctime;
out->atime = info.atime;
out->mode = info.mode;
out->isDir = info.isDir ? 1u : 0u;
return 0;
}
static int Sys_FMkdir(const char* path) {
char resolved[256];
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
+4
View File
@@ -153,6 +153,10 @@ namespace montauk::abi {
case SYS_GETEXECPATH:
if (!UserMemory::Range(frame->arg2 ? frame->arg1 : frame->arg1, frame->arg2, true)) return -1;
return Sys_GetExecPath((char*)frame->arg1, frame->arg2);
case SYS_STAT:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (!UserMemory::Writable<FileStat>(frame->arg2)) return -1;
return (int64_t)Sys_Stat((const char*)frame->arg1, (FileStat*)frame->arg2);
case SYS_TERMSIZE:
return (int64_t)Sys_TermSize();
case SYS_GETARGS:
+14
View File
@@ -285,6 +285,9 @@ namespace montauk::abi {
// Absolute path of the running executable (for argv[0]).
static constexpr uint64_t SYS_GETEXECPATH = 151; // (index, flags) -> new front index; index=-1 queries support (1/0); flags bit0 = wait vsync
// Path metadata (size, timestamps, mode). (const char* path, FileStat* out) -> 0, -1 on error/unsupported.
static constexpr uint64_t SYS_STAT = 152;
// Tunable parameters (for SYS_SDR_SETPARAM / SYS_SDR_GETPARAM).
static constexpr int SDR_PARAM_FREQ = 0; // center frequency, Hz
static constexpr int SDR_PARAM_SAMPLE_RATE = 1; // sample rate, Hz
@@ -326,6 +329,17 @@ namespace montauk::abi {
uint8_t Second;
};
// Path metadata returned by SYS_STAT. Timestamps are UTC unix seconds;
// a filesystem that does not record a given time reports it as 0.
struct FileStat {
uint64_t size; // file size in bytes
int64_t mtime; // last data modification time
int64_t ctime; // last inode (metadata) change time
int64_t atime; // last access time
uint32_t mode; // ext2/POSIX mode bits (type + permissions)
uint32_t isDir; // 1 if the entry is a directory, else 0
};
struct FbInfo {
uint64_t width;
uint64_t height;
+20
View File
@@ -1189,6 +1189,24 @@ namespace Fs::Ext2 {
return -1;
}
static int StatImpl(int inst, const char* path, Vfs::StatInfo* out) {
if (!out) return -1;
if (inst < 0 || inst >= g_instanceCount || !g_instances[inst].active) return -1;
auto& self = g_instances[inst];
uint32_t inodeNum;
Inode inode;
if (!TraversePath(self, path, &inodeNum, &inode)) return -1;
out->size = inode.i_size;
out->mtime = (int64_t)inode.i_mtime;
out->ctime = (int64_t)inode.i_ctime;
out->atime = (int64_t)inode.i_atime;
out->mode = inode.i_mode;
out->isDir = (inode.i_mode & IMODE_TYPE_MASK) == IMODE_DIR;
return 0;
}
static int ReadImpl(int inst, int handle, uint8_t* buffer,
uint64_t offset, uint64_t size) {
if (inst < 0 || inst >= g_instanceCount) return -1;
@@ -1764,6 +1782,7 @@ namespace Fs::Ext2 {
static int Mkdir(const char* p) { return MkdirImpl(N, p); }
static int Rename(const char* o, const char* n) { return RenameImpl(N, o, n); }
static const char* GetLabel() { return GetLabelImpl(N); }
static int Stat(const char* p, Vfs::StatInfo* o) { return StatImpl(N, p, o); }
};
template<int N>
@@ -1781,6 +1800,7 @@ namespace Fs::Ext2 {
Thunks<N>::Rename,
Thunks<N>::GetLabel,
Thunks<N>::ReadDirAt,
Thunks<N>::Stat,
};
}
+19
View File
@@ -288,6 +288,25 @@ namespace Fs::Vfs {
return result;
}
int VfsStat(const char* path, StatInfo& out) {
int drive;
const char* localPath;
out = StatInfo{};
if (!ParsePath(path, drive, localPath)) return -1;
if (drive < 0 || drive >= MaxDrives || !driveActive[drive] || driveTable[drive] == nullptr) return -1;
if (driveTable[drive]->Stat == nullptr) return -1;
vfsLock.Acquire();
FsDriver* driver = driveTable[drive];
int result = (driveActive[drive] && driver && driver->Stat)
? driver->Stat(localPath, &out)
: -1;
vfsLock.Release();
return result;
}
int VfsMkdir(const char* path) {
int drive;
const char* localPath;
+15
View File
@@ -18,6 +18,17 @@ namespace Fs::Vfs {
uint32_t generation;
};
// Metadata for a single path, filled by FsDriver::Stat. Timestamps are UTC
// unix seconds; a filesystem that does not record a given time leaves it 0.
struct StatInfo {
uint64_t size; // file size in bytes
int64_t mtime; // last data modification time
int64_t ctime; // last inode (metadata) change time
int64_t atime; // last access time
uint32_t mode; // ext2/POSIX i_mode bits (type + permissions)
bool isDir; // true if the entry is a directory
};
struct FsDriver {
int (*Open)(const char* path);
int (*Read)(int handle, uint8_t* buffer, uint64_t offset, uint64_t size);
@@ -33,6 +44,9 @@ namespace Fs::Vfs {
// Optional: paginated directory read returning entries [startIndex, startIndex+maxEntries).
// Drivers that leave this null are read via ReadDir at startIndex 0 only.
int (*ReadDirAt)(const char* path, const char** outNames, int maxEntries, int startIndex);
// Optional: fill metadata for a path. Drivers that leave this null do
// not support stat and VfsStat returns -1 for their paths.
int (*Stat)(const char* path, StatInfo* out);
};
void Initialize();
@@ -51,6 +65,7 @@ namespace Fs::Vfs {
void CloseBackendFile(BackendFile& file);
int VfsDelete(const char* path);
int VfsStat(const char* path, StatInfo& out);
int VfsReadDir(const char* path, const char** outNames, int maxEntries);
int VfsReadDirAt(const char* path, const char** outNames, int maxEntries, int startIndex);
int VfsMkdir(const char* path);
+14
View File
@@ -209,6 +209,9 @@ namespace montauk::abi {
// Absolute path of the running executable (for argv[0]).
static constexpr uint64_t SYS_GETEXECPATH = 151; // (index, flags) -> new front index; index=-1 queries support (1/0); flags bit0 = wait vsync
// Path metadata (size, timestamps, mode). (const char* path, FileStat* out) -> 0, -1 on error/unsupported.
static constexpr uint64_t SYS_STAT = 152;
// Tunable parameters (for SYS_SDR_SETPARAM / SYS_SDR_GETPARAM).
static constexpr int SDR_PARAM_FREQ = 0; // center frequency, Hz
static constexpr int SDR_PARAM_SAMPLE_RATE = 1; // sample rate, Hz
@@ -287,6 +290,17 @@ namespace montauk::abi {
uint8_t Second;
};
// Path metadata returned by SYS_STAT. Timestamps are UTC unix seconds;
// a filesystem that does not record a given time reports it as 0.
struct FileStat {
uint64_t size; // file size in bytes
int64_t mtime; // last data modification time
int64_t ctime; // last inode (metadata) change time
int64_t atime; // last access time
uint32_t mode; // ext2/POSIX mode bits (type + permissions)
uint32_t isDir; // 1 if the entry is a directory, else 0
};
struct FbInfo {
uint64_t width;
uint64_t height;
+1
View File
@@ -175,6 +175,7 @@ extern "C" {
#define MTK_SYS_POWERINFO 149
#define MTK_SYS_FBFLIP 150
#define MTK_SYS_GETEXECPATH 151
#define MTK_SYS_STAT 152
/* @SYSCALLS-END */
#define MTK_SOCK_TCP 1
+5
View File
@@ -165,6 +165,11 @@ namespace montauk {
inline int frename(const char* oldPath, const char* newPath) {
return (int)syscall2(montauk::abi::SYS_FRENAME, (uint64_t)oldPath, (uint64_t)newPath);
}
// Fill *out with metadata (size, timestamps, mode) for the path.
// Returns 0 on success, -1 on error or if the filesystem lacks stat support.
inline int stat(const char* path, montauk::abi::FileStat* out) {
return (int)syscall2(montauk::abi::SYS_STAT, (uint64_t)path, (uint64_t)out);
}
inline int drivelist(int* outDrives, int max) {
return (int)syscall2(montauk::abi::SYS_DRIVELIST, (uint64_t)outDrives, (uint64_t)max);
}