feat: implement utime libc function, SYS_UTIME syscall, filesystem support (ext2 only)

This commit is contained in:
daniel committed 2026-08-09 11:16:59 +02:00
1 parent 771c3a5a98
commit 1c498ffa6a
15 files changed
+158 -30

No files matched your search

+1
View File
@@ -101,6 +101,7 @@ namespace Fs {
.GetLabel = RdGetLabel,
.ReadDirAt = RdReadDirAt,
.Stat = RdStat,
.SetTimes = nullptr,
// Statically allocated: nothing to release.
.Unmount = nullptr,
};
+27
View File
@@ -1234,6 +1234,31 @@ namespace Fs::Ext2 {
return 0;
}
static int SetTimesImpl(int inst, const char* path, int64_t atime, int64_t mtime) {
if (InstanceAt(inst) == nullptr) return -4;
if (atime < 0 || atime > 0xFFFFFFFFLL ||
mtime < 0 || mtime > 0xFFFFFFFFLL) return -3;
auto& self = g_instances[inst];
uint32_t inodeNum;
Inode inode;
if (!TraversePath(self, path, &inodeNum, &inode)) return -1;
inode.i_atime = (uint32_t)atime;
inode.i_mtime = (uint32_t)mtime;
inode.i_ctime = Ext2Now();
if (!WriteInode(self, inodeNum, &inode)) return -4;
// Open files cache their inode. Keep every alias coherent so a later
// write through an existing handle cannot restore stale metadata.
for (int i = 0; i < MaxFilesPerInstance; i++) {
if (self.files[i].inUse && self.files[i].inodeNum == inodeNum) {
self.files[i].inode = inode;
}
}
return 0;
}
static int ReadImpl(int inst, int handle, uint8_t* buffer,
uint64_t offset, uint64_t size) {
if (InstanceAt(inst) == nullptr) return -1;
@@ -1830,6 +1855,7 @@ namespace Fs::Ext2 {
static int DrvRename(void* c, const char* o, const char* n) { return RenameImpl(CtxToInst(c), o, n); }
static const char* DrvGetLabel(void* c) { return GetLabelImpl(CtxToInst(c)); }
static int DrvStat(void* c, const char* p, Vfs::StatInfo* o) { return StatImpl(CtxToInst(c), p, o); }
static int DrvSetTimes(void* c, const char* p, int64_t a, int64_t m) { return SetTimesImpl(CtxToInst(c), p, a, m); }
// Release everything the mount owns. The driver is either not registered
// yet, or the VFS has deactivated its drive and drained dispatches.
@@ -2040,6 +2066,7 @@ namespace Fs::Ext2 {
.GetLabel = DrvGetLabel,
.ReadDirAt = DrvReadDirAt,
.Stat = DrvStat,
.SetTimes = DrvSetTimes,
.Unmount = DrvUnmount,
};
+1
View File
@@ -2099,6 +2099,7 @@ namespace Fs::Fat32 {
.GetLabel = DrvGetLabel,
.ReadDirAt = DrvReadDirAt,
.Stat = DrvStat,
.SetTimes = nullptr,
.Unmount = DrvUnmount,
};
+15
View File
@@ -307,6 +307,21 @@ namespace Fs::Vfs {
return result;
}
int VfsSetTimes(const char* path, int64_t atime, int64_t mtime) {
int drive;
const char* localPath;
if (!ParsePath(path, drive, localPath)) return -1;
vfsLock.Acquire();
FsDriver* driver = DriverForLocked(drive);
int result = (driver != nullptr && driver->SetTimes != nullptr)
? driver->SetTimes(driver->ctx, localPath, atime, mtime)
: -2;
vfsLock.Release();
return result;
}
int VfsMkdir(const char* path) {
int drive;
const char* localPath;
+5
View File
@@ -65,6 +65,10 @@ namespace Fs::Vfs {
// Optional: fill metadata for a path. Drivers that leave this null do
// not support stat and VfsStat returns -1 for their paths.
int (*Stat)(void* ctx, const char* path, StatInfo* out);
// Optional: set access and modification times for a path. Return 0 on
// success, -1 for a missing path, -3 for an unrepresentable time, or
// -4 for an I/O error. A null hook yields -2 (unsupported).
int (*SetTimes)(void* ctx, const char* path, int64_t atime, int64_t mtime);
// Optional: release everything this mount owns, including the FsDriver
// itself. Called either when registration fails, before the driver has
// become reachable, or by UnregisterDrive once the slot is deactivated
@@ -90,6 +94,7 @@ namespace Fs::Vfs {
int VfsDelete(const char* path);
int VfsStat(const char* path, StatInfo& out);
int VfsSetTimes(const char* path, int64_t atime, int64_t mtime);
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);