feat: real stat metadata across all filesystems, plus mkdir and rmdir

This commit is contained in:
2026-08-04 13:03:08 +02:00
parent ca5331c9db
commit edc3452d61
14 changed files with 557 additions and 25 deletions
+71 -1
View File
@@ -11,6 +11,7 @@
#include <Libraries/Memory.hpp>
#include <Memory/PageFrameAllocator.hpp>
#include <CppLib/Vector.hpp>
#include <Timekeeping/Time.hpp>
using namespace Kt;
@@ -107,6 +108,13 @@ namespace Fs::Fat32 {
// Location of the SFN entry on disk (for write support)
uint64_t sfnPartSector;
uint32_t sfnOffInSector;
// Packed FAT date/time words straight from the SFN entry, decoded
// on demand by Stat. Zero means "not recorded".
uint16_t writeTime;
uint16_t writeDate;
uint16_t createTime;
uint16_t createDate;
uint16_t accessDate;
};
// =========================================================================
@@ -853,6 +861,13 @@ namespace Fs::Fat32 {
out->firstCluster = ((uint32_t)clHi << 16) | (uint32_t)clLo;
memcpy(&out->fileSize, e + 28, 4);
out->attributes = attr;
// SFN timestamp words: creation at 14/16, last access
// date at 18, last write at 22/24.
memcpy(&out->createTime, e + 14, 2);
memcpy(&out->createDate, e + 16, 2);
memcpy(&out->accessDate, e + 18, 2);
memcpy(&out->writeTime, e + 22, 2);
memcpy(&out->writeDate, e + 24, 2);
int j = 0;
while (entryName[j] && j < MaxNameLen - 1) {
out->name[j] = entryName[j]; j++;
@@ -888,6 +903,12 @@ namespace Fs::Fat32 {
out->attributes = ATTR_DIRECTORY;
out->name[0] = '/';
out->name[1] = '\0';
// The root has no directory entry, so it has no timestamps.
out->writeTime = 0;
out->writeDate = 0;
out->createTime = 0;
out->createDate = 0;
out->accessDate = 0;
return true;
}
@@ -1578,6 +1599,54 @@ namespace Fs::Fat32 {
return 0;
}
// =========================================================================
// Stat — metadata for a single path
// =========================================================================
// Decode a packed FAT date/time pair into a Unix timestamp.
// date: bits 15-9 year since 1980, 8-5 month (1-12), 4-0 day (1-31)
// time: bits 15-11 hour, 10-5 minute, 4-0 seconds/2
// FAT stores local time with no recorded offset, so it is taken as UTC.
// A zero date means the field was never written; report 0 rather than
// inventing 1980-00-00.
static int64_t FatDateTimeToEpoch(uint16_t date, uint16_t time) {
if (date == 0) return 0;
int year = 1980 + ((date >> 9) & 0x7F);
int month = (date >> 5) & 0x0F;
int day = date & 0x1F;
int hour = (time >> 11) & 0x1F;
int minute = (time >> 5) & 0x3F;
int second = (time & 0x1F) * 2;
return Timekeeping::DateToUnixTimestamp(year, month, day, hour, minute, second);
}
static int StatImpl(int inst, const char* path, Vfs::StatInfo* out) {
if (out == nullptr) return -1;
if (InstanceAt(inst) == nullptr) return -1;
ParsedEntry entry;
if (!TraversePath(inst, path, &entry)) return -1;
bool isDir = (entry.attributes & ATTR_DIRECTORY) != 0;
out->size = isDir ? 0 : entry.fileSize;
out->mtime = FatDateTimeToEpoch(entry.writeDate, entry.writeTime);
out->ctime = FatDateTimeToEpoch(entry.createDate, entry.createTime);
// Access date has no time-of-day component on FAT.
out->atime = FatDateTimeToEpoch(entry.accessDate, 0);
// FAT carries no POSIX permissions; synthesize them from the
// read-only attribute so callers see a plausible mode.
uint32_t perms = (entry.attributes & ATTR_READ_ONLY)
? (isDir ? 0555u : 0444u)
: (isDir ? 0755u : 0644u);
out->mode = (isDir ? Vfs::ModeDir : Vfs::ModeReg) | perms;
out->isDir = isDir;
return 0;
}
// =========================================================================
// Rename — atomic directory entry move
// =========================================================================
@@ -1821,6 +1890,7 @@ namespace Fs::Fat32 {
static int DrvMkdir(void* c, const char* p) { return MkdirImpl(CtxToInst(c), p); }
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); }
// Release everything the mount owns. The driver is either not registered
// yet, or the VFS has deactivated its drive and drained dispatches.
@@ -2028,7 +2098,7 @@ namespace Fs::Fat32 {
.Rename = DrvRename,
.GetLabel = DrvGetLabel,
.ReadDirAt = DrvReadDirAt,
.Stat = nullptr,
.Stat = DrvStat,
.Unmount = DrvUnmount,
};