add system time, clean up pci into pci.sys, clean up syscall names, fix USERAPC1 typo
This commit is contained in:
1 parent
c1a291c4c9
commit
e41bf6e2c0
64 files changed
+4514
-2220
No files matched your search
+274
-28
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in new issue
Block a user