add system time, clean up pci into pci.sys, clean up syscall names, fix USERAPC1 typo

This commit is contained in:
maksw committed 2026-06-11 18:11:59 +02:00
1 parent c1a291c4c9
commit e41bf6e2c0
64 files changed
+4514 -2220

No files matched your search

+274 -28
View File
@@ -101,6 +101,8 @@ typedef struct {
#define ATTR_DIRECTORY 0x10
#define ATTR_ARCHIVE 0x20
#define ATTR_LFN 0x0F
#define FAT_NTRES_BASE_LOWER 0x08u
#define FAT_NTRES_EXT_LOWER 0x10u
#define FAT32_EOC 0x0FFFFFF8u
#define FAT32_EOC_MARK 0x0FFFFFFFu
#define FAT32_FREE 0x00000000u
@@ -343,34 +345,186 @@ static void FreeClusterChain(FAT32_VOL *v, uint32_t start) {
}
// ---------------------------------------------------------------------------
// DIRENT update helpers
// FAT timestamp and DIRENT metadata helpers
// ---------------------------------------------------------------------------
static KSTATUS DirentUpdateSize(FAT32_VOL *v, uint64_t lba,
uint32_t offset, uint32_t size) {
typedef struct FAT32_ENCODED_TIME {
uint16_t Date;
uint16_t Time;
uint8_t CreateTimeTenth;
} FAT32_ENCODED_TIME;
typedef struct FAT32_DIRENT_UPDATE {
uint32_t Flags;
uint32_t Size;
uint32_t FirstCluster;
FAT32_ENCODED_TIME Timestamp;
} FAT32_DIRENT_UPDATE;
#define FAT32_DIRENT_UPDATE_SIZE 0x00000001u
#define FAT32_DIRENT_UPDATE_FIRST_CLUSTER 0x00000002u
#define FAT32_DIRENT_UPDATE_CREATE_TIME 0x00000004u
#define FAT32_DIRENT_UPDATE_WRITE_TIME 0x00000008u
#define FAT32_DIRENT_UPDATE_ACCESS_DATE 0x00000010u
static int FatIsLeapYear(uint32_t year) {
return ((year % 4u) == 0u && (year % 100u) != 0u) || ((year % 400u) == 0u);
}
static uint32_t FatDaysInMonth(uint32_t year, uint32_t month) {
static const uint8_t days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
if (month < 1u || month > 12u) return 31u;
if (month == 2u && FatIsLeapYear(year)) return 29u;
return days[month - 1u];
}
static uint64_t FatCalendarToEpochSeconds(uint32_t year, uint32_t month, uint32_t day,
uint32_t hour, uint32_t minute, uint32_t second) {
uint64_t days = 0;
for (uint32_t y = 1970u; y < year; y++)
days += FatIsLeapYear(y) ? 366u : 365u;
for (uint32_t m = 1u; m < month; m++)
days += FatDaysInMonth(year, m);
days += day - 1u;
return (((days * 24u) + hour) * 60u + minute) * 60u + second;
}
static uint8_t FatDayOfWeek(uint32_t year, uint32_t month, uint32_t day) {
uint64_t epoch = FatCalendarToEpochSeconds(year, month, day, 0, 0, 0);
return (uint8_t)(((epoch / 86400u) + 4u) % 7u);
}
static uint16_t FatEncodeDate(const SYS_SYSTEM_TIME* t) {
uint32_t year = t && t->Year ? t->Year : 1980u;
uint32_t month = t && t->Month ? t->Month : 1u;
uint32_t day = t && t->Day ? t->Day : 1u;
if (year < 1980u) year = 1980u;
if (year > 2107u) year = 2107u;
if (month < 1u) month = 1u;
if (month > 12u) month = 12u;
uint32_t dim = FatDaysInMonth(year, month);
if (day < 1u) day = 1u;
if (day > dim) day = dim;
return (uint16_t)(((year - 1980u) << 9) | (month << 5) | day);
}
static uint16_t FatEncodeTime(const SYS_SYSTEM_TIME* t) {
uint32_t hour = t ? t->Hour : 0u;
uint32_t minute = t ? t->Minute : 0u;
uint32_t second = t ? t->Second : 0u;
if (hour > 23u) hour = 23u;
if (minute > 59u) minute = 59u;
if (second > 59u) second = 59u;
return (uint16_t)((hour << 11) | (minute << 5) | (second / 2u));
}
static uint8_t FatEncodeCreateTimeTenth(const SYS_SYSTEM_TIME* t) {
uint32_t second = t ? t->Second : 0u;
uint32_t ms = t ? t->Millisecond : 0u;
if (second > 59u) second = 59u;
if (ms > 999u) ms = 999u;
uint32_t v = ((second & 1u) * 100u) + (ms / 10u);
if (v > 199u) v = 199u;
return (uint8_t)v;
}
static void FatQueryEncodedTime(FAT32_ENCODED_TIME* out) {
SYS_SYSTEM_TIME now;
memset(&now, 0, sizeof(now));
if (KeQuerySystemTime(&now) != STATUS_SUCCESS) {
now.Year = 1980;
now.Month = 1;
now.Day = 1;
}
out->Date = FatEncodeDate(&now);
out->Time = FatEncodeTime(&now);
out->CreateTimeTenth = FatEncodeCreateTimeTenth(&now);
}
static void FatDecodeDateTime(uint16_t date, uint16_t time, uint8_t createTenth,
SYS_SYSTEM_TIME* out) {
memset(out, 0, sizeof(*out));
uint32_t year = 1980u + ((date >> 9) & 0x7Fu);
uint32_t month = (date >> 5) & 0x0Fu;
uint32_t day = date & 0x1Fu;
uint32_t hour = (time >> 11) & 0x1Fu;
uint32_t minute = (time >> 5) & 0x3Fu;
uint32_t second = (time & 0x1Fu) * 2u;
if (date == 0 || month < 1u || month > 12u) { year = 1980u; month = 1u; day = 1u; }
uint32_t dim = FatDaysInMonth(year, month);
if (day < 1u) day = 1u;
if (day > dim) day = dim;
if (hour > 23u) hour = 23u;
if (minute > 59u) minute = 59u;
if (second > 58u) second = 58u;
if (createTenth >= 100u && second < 59u) second++;
out->Year = (uint16_t)year;
out->Month = (uint8_t)month;
out->Day = (uint8_t)day;
out->Hour = (uint8_t)hour;
out->Minute = (uint8_t)minute;
out->Second = (uint8_t)second;
out->Millisecond = (uint16_t)((createTenth % 100u) * 10u);
out->DayOfWeek = FatDayOfWeek(year, month, day);
out->Flags = SYS_TIME_FLAG_VALID;
out->EpochSeconds = FatCalendarToEpochSeconds(year, month, day, hour, minute, second);
}
static void FatDecodeAccessDate(uint16_t date, SYS_SYSTEM_TIME* out) {
FatDecodeDateTime(date, 0, 0, out);
}
static KSTATUS DirentUpdateMetadata(FAT32_VOL *v, uint64_t lba,
uint32_t offset,
const FAT32_DIRENT_UPDATE* update) {
if (!v || !update || !update->Flags) return STATUS_INVALID_PARAMETER;
uint8_t *sec = (uint8_t *)MmAllocatePool(v->BytesPerSector);
if (!sec) return STATUS_NO_MEMORY;
KSTATUS s = ReadSectors(v, lba, 1, sec);
if (KSUCCESS(s)) {
((DIRENT *)(sec + offset))->FileSize = size;
DIRENT *d = (DIRENT *)(sec + offset);
if (update->Flags & FAT32_DIRENT_UPDATE_SIZE)
d->FileSize = update->Size;
if (update->Flags & FAT32_DIRENT_UPDATE_FIRST_CLUSTER) {
d->FirstClusterHi = (uint16_t)(update->FirstCluster >> 16);
d->FirstClusterLo = (uint16_t)(update->FirstCluster & 0xFFFF);
}
if (update->Flags & FAT32_DIRENT_UPDATE_CREATE_TIME) {
d->CrtTimeTenth = update->Timestamp.CreateTimeTenth;
d->CrtTime = update->Timestamp.Time;
d->CrtDate = update->Timestamp.Date;
}
if (update->Flags & FAT32_DIRENT_UPDATE_WRITE_TIME) {
d->WrtTime = update->Timestamp.Time;
d->WrtDate = update->Timestamp.Date;
}
if (update->Flags & FAT32_DIRENT_UPDATE_ACCESS_DATE)
d->LastAccDate = update->Timestamp.Date;
s = WriteSectors(v, lba, 1, sec);
}
MmFreePool(sec);
return s;
}
static KSTATUS DirentUpdateSize(FAT32_VOL *v, uint64_t lba,
uint32_t offset, uint32_t size) {
FAT32_DIRENT_UPDATE u;
memset(&u, 0, sizeof(u));
FatQueryEncodedTime(&u.Timestamp);
u.Flags = FAT32_DIRENT_UPDATE_SIZE | FAT32_DIRENT_UPDATE_WRITE_TIME;
u.Size = size;
return DirentUpdateMetadata(v, lba, offset, &u);
}
static KSTATUS DirentUpdateFirstCluster(FAT32_VOL *v, uint64_t lba,
uint32_t offset, uint32_t cluster) {
uint8_t *sec = (uint8_t *)MmAllocatePool(v->BytesPerSector);
if (!sec) return STATUS_NO_MEMORY;
KSTATUS s = ReadSectors(v, lba, 1, sec);
if (KSUCCESS(s)) {
DIRENT *d = (DIRENT *)(sec + offset);
d->FirstClusterHi = (uint16_t)(cluster >> 16);
d->FirstClusterLo = (uint16_t)(cluster & 0xFFFF);
s = WriteSectors(v, lba, 1, sec);
}
MmFreePool(sec);
return s;
FAT32_DIRENT_UPDATE u;
memset(&u, 0, sizeof(u));
u.Flags = FAT32_DIRENT_UPDATE_FIRST_CLUSTER;
u.FirstCluster = cluster;
return DirentUpdateMetadata(v, lba, offset, &u);
}
// ---------------------------------------------------------------------------
@@ -467,14 +621,67 @@ static int FatNameIsStructurallyShort83V(SYS_STRING_VIEW name) {
return baseLen >= 1 && baseLen <= 8 && extLen <= 3;
}
// Creation uses LFN when needed for structure, or when lowercase would be lost.
static int FatNameNeedsLfnForCreateV(SYS_STRING_VIEW name) {
if (!FatNameIsStructurallyShort83V(name)) return 1;
for (size_t i = 0; i < name.Length; i++)
static int FatComponentHasLowerV(SYS_STRING_VIEW name, size_t start, size_t end) {
for (size_t i = start; i < end; i++)
if (FatIsLowerChar(name.Data[i])) return 1;
return 0;
}
static int FatComponentHasUpperV(SYS_STRING_VIEW name, size_t start, size_t end) {
for (size_t i = start; i < end; i++)
if (name.Data[i] >= 'A' && name.Data[i] <= 'Z') return 1;
return 0;
}
static void FatSplitShortNameV(SYS_STRING_VIEW name, size_t* baseEnd,
size_t* extStart, size_t* extEnd) {
size_t dot = (size_t)-1;
for (size_t i = 0; i < name.Length; i++)
if (name.Data[i] == '.') dot = i;
if (dot == (size_t)-1) {
*baseEnd = name.Length;
*extStart = name.Length;
*extEnd = name.Length;
} else {
*baseEnd = dot;
*extStart = dot + 1u;
*extEnd = name.Length;
}
}
// Creation uses LFN only when the spelling cannot be represented by a short
// entry, or when mixed-case 8.3 spelling would be lost. Plain lowercase
// 8.3 names are represented with FAT's NT case bits, not VFAT LFN entries.
static int FatNameNeedsLfnForCreateV(SYS_STRING_VIEW name) {
if (!FatNameIsStructurallyShort83V(name)) return 1;
size_t baseEnd, extStart, extEnd;
FatSplitShortNameV(name, &baseEnd, &extStart, &extEnd);
int baseLower = FatComponentHasLowerV(name, 0, baseEnd);
int baseUpper = FatComponentHasUpperV(name, 0, baseEnd);
int extLower = FatComponentHasLowerV(name, extStart, extEnd);
int extUpper = FatComponentHasUpperV(name, extStart, extEnd);
if ((baseLower && baseUpper) || (extLower && extUpper)) return 1;
return 0;
}
static uint8_t FatShortNameCaseFlagsV(SYS_STRING_VIEW name) {
if (!FatNameIsStructurallyShort83V(name)) return 0;
size_t baseEnd, extStart, extEnd;
FatSplitShortNameV(name, &baseEnd, &extStart, &extEnd);
uint8_t flags = 0;
if (FatComponentHasLowerV(name, 0, baseEnd) &&
!FatComponentHasUpperV(name, 0, baseEnd))
flags |= FAT_NTRES_BASE_LOWER;
if (extStart < extEnd &&
FatComponentHasLowerV(name, extStart, extEnd) &&
!FatComponentHasUpperV(name, extStart, extEnd))
flags |= FAT_NTRES_EXT_LOWER;
return flags;
}
static uint8_t LfnChecksum(const char name8[8], const char ext3[3]) {
uint8_t sum = 0;
for (int i = 0; i < 11; i++) {
@@ -1218,9 +1425,17 @@ KSTATUS Fat32Write(IO_FILESYSTEM *fs, void *fileCtx,
MmFreePool(runBuf);
uint64_t newEnd = offset + written;
if (newEnd > f->FileSize) {
f->FileSize = (uint32_t)newEnd;
DirentUpdateSize(v, f->DirentLba, f->DirentOffset, f->FileSize);
if (written > 0) {
FAT32_DIRENT_UPDATE u;
memset(&u, 0, sizeof(u));
FatQueryEncodedTime(&u.Timestamp);
u.Flags = FAT32_DIRENT_UPDATE_WRITE_TIME;
if (newEnd > f->FileSize) {
f->FileSize = (uint32_t)newEnd;
u.Flags |= FAT32_DIRENT_UPDATE_SIZE;
u.Size = f->FileSize;
}
DirentUpdateMetadata(v, f->DirentLba, f->DirentOffset, &u);
}
*bytesWritten = written;
@@ -1316,6 +1531,17 @@ KSTATUS Fat32Create(IO_FILESYSTEM *fs, SYS_STRING_VIEW path, void **fileCtx) {
memcpy(d->Name, shortName, 8);
memcpy(d->Ext, shortExt, 3);
d->Attr = ATTR_ARCHIVE;
d->Reserved = FatShortNameCaseFlagsV(filenameView);
{
FAT32_ENCODED_TIME now;
FatQueryEncodedTime(&now);
d->CrtTimeTenth = now.CreateTimeTenth;
d->CrtTime = now.Time;
d->CrtDate = now.Date;
d->LastAccDate = now.Date;
d->WrtTime = now.Time;
d->WrtDate = now.Date;
}
s = WriteSectors(v, clusterLba, v->SectorsPerCluster, clusterBuf);
MmFreePool(clusterBuf);
@@ -1340,7 +1566,13 @@ KSTATUS Fat32Truncate(IO_FILESYSTEM *fs, void *fileCtx, uint64_t newSize) {
(void)fs;
FAT32_FILE *f = (FAT32_FILE *)fileCtx;
FAT32_VOL *v = f->Vol;
if ((uint32_t)newSize == f->FileSize) return STATUS_SUCCESS;
if ((uint32_t)newSize == f->FileSize) {
FAT32_DIRENT_UPDATE u;
memset(&u, 0, sizeof(u));
FatQueryEncodedTime(&u.Timestamp);
u.Flags = FAT32_DIRENT_UPDATE_WRITE_TIME;
return DirentUpdateMetadata(v, f->DirentLba, f->DirentOffset, &u);
}
if (newSize == 0) {
if (f->StartCluster >= 2) {
@@ -1495,6 +1727,8 @@ KSTATUS Fat32ReadDir(IO_FILESYSTEM *fs, void *dirCtx, KDIR_ENTRY *out) {
if (e->Attr == ATTR_LFN) { LfnAppend(ctx->LfnBuf, (LFN_ENTRY *)e); ctx->HasLfn = 1; continue; }
if (e->Attr & 0x08 && !(e->Attr & ATTR_DIRECTORY)) { ctx->HasLfn = 0; memset(ctx->LfnBuf, 0, sizeof(ctx->LfnBuf)); continue; }
memset(out, 0, sizeof(*out));
if (ctx->HasLfn && ctx->LfnBuf[0]) {
size_t len = strlen(ctx->LfnBuf);
if (len >= KDIR_NAME_MAX) len = KDIR_NAME_MAX - 1;
@@ -1513,7 +1747,11 @@ KSTATUS Fat32ReadDir(IO_FILESYSTEM *fs, void *dirCtx, KDIR_ENTRY *out) {
memcpy(out->Name, name83, len); out->Name[len] = '\0';
}
out->Attr = e->Attr; out->FileSize = e->FileSize;
out->Attr = e->Attr;
out->FileSize = e->FileSize;
FatDecodeDateTime(e->CrtDate, e->CrtTime, e->CrtTimeTenth, &out->CreateTime);
FatDecodeAccessDate(e->LastAccDate, &out->LastAccessTime);
FatDecodeDateTime(e->WrtDate, e->WrtTime, 0, &out->LastWriteTime);
ctx->HasLfn = 0; memset(ctx->LfnBuf, 0, sizeof(ctx->LfnBuf));
return STATUS_SUCCESS;
}
@@ -1993,10 +2231,18 @@ static void Fat32AsyncWriteIrpComplete(IRP* irp, void* completeCtx) {
static void Fat32AsyncWriteSubmitNext(FAT32_ASYNC_RW* ctx) {
if (ctx->Remaining == 0) {
uint64_t newEnd = ctx->Offset + ctx->Done;
if (newEnd > ctx->File->FileSize) {
ctx->File->FileSize = (uint32_t)newEnd;
DirentUpdateSize(ctx->Vol, ctx->File->DirentLba,
ctx->File->DirentOffset, ctx->File->FileSize);
if (ctx->Done > 0) {
FAT32_DIRENT_UPDATE u;
memset(&u, 0, sizeof(u));
FatQueryEncodedTime(&u.Timestamp);
u.Flags = FAT32_DIRENT_UPDATE_WRITE_TIME;
if (newEnd > ctx->File->FileSize) {
ctx->File->FileSize = (uint32_t)newEnd;
u.Flags |= FAT32_DIRENT_UPDATE_SIZE;
u.Size = ctx->File->FileSize;
}
DirentUpdateMetadata(ctx->Vol, ctx->File->DirentLba,
ctx->File->DirentOffset, &u);
}
Fat32AsyncFinish(ctx, STATUS_SUCCESS, ctx->Done);
return;
+1
View File
@@ -14,6 +14,7 @@
#include <kernel/ke_semaphore.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_time.h>
typedef struct FAT32_VOL_S FAT32_VOL;