refactor syscall ABI and FAT32 driver to use request structs and string views natively, enforce handle access rights on object lookup, add scheduler statistics tracking, fix KiSchedule to prevent 50% idle throttling on CPU-bound threads, better document x64 initial user stack alignment, fix process teardown to properly signal exit events and manage thread counts, optimize doom file I/O with a custom handle struct to internally track position and size, add SubsystemData to TEB for generic thread-local state, apply PAGE_NX to non-executable PE sections in the loader, update native apps, tests, and shells to match new APIs, update kernel32 directory retrieval.

This commit is contained in:
maksw committed 2026-05-26 14:46:49 +02:00
1 parent 603fbdfab1
commit e1248f4afe
43 files changed
+2892 -1857

No files matched your search

+248 -144
View File
@@ -425,26 +425,6 @@ static KSTATUS DirentUpdateFirstCluster(FAT32_VOL *v, uint64_t lba,
// ---------------------------------------------------------------------------
// 8.3 name matching / assembly
// ---------------------------------------------------------------------------
static int MatchName83(const char *dirName, const char *dirExt,
const char *want) {
char buf[13]; int n = 0;
for (int i = 0; i < 8 && dirName[i] != ' '; i++)
buf[n++] = (char)(dirName[i] >= 'A' && dirName[i] <= 'Z' ? dirName[i]+32 : dirName[i]);
if (dirExt[0] != ' ') {
buf[n++] = '.';
for (int i = 0; i < 3 && dirExt[i] != ' '; i++)
buf[n++] = (char)(dirExt[i] >= 'A' && dirExt[i] <= 'Z' ? dirExt[i]+32 : dirExt[i]);
}
buf[n] = '\0';
const char *p = buf;
while (*want && *p) {
char a = *p++, b = *want++;
if (a >= 'A' && a <= 'Z') a += 32;
if (b >= 'A' && b <= 'Z') b += 32;
if (a != b) return 0;
}
return *want == '\0' && *p == '\0';
}
static int MatchRaw83(const char dirName[8], const char dirExt[3],
const char wantName[8], const char wantExt[3]) {
@@ -452,34 +432,35 @@ static int MatchRaw83(const char dirName[8], const char dirExt[3],
memcmp(dirExt, wantExt, 3) == 0;
}
static void Make83Name(const char *src, char name8[8], char ext3[3]) {
memset(name8, ' ', 8); memset(ext3, ' ', 3);
static char FatUpperChar(char c);
static int FatIsLowerChar(char c);
static int FatIsValidShortChar(char c);
// A leading dot is not a FAT 8.3 extension separator. The old version
// turned ".doomrc" into an invalid empty-base short name with extension
// "DOO", making .doomrc, .doom and .doo all alias the same entry. Treat
// leading-dot names as a basename here; the create path will usually emit
// a VFAT long-name entry for them anyway.
const char *base = src;
const char *dot = NULL;
if (src && src[0] == '.' && src[1]) {
base = src + 1;
static void Make83NameV(SYS_STRING_VIEW src, char name8[8], char ext3[3]) {
memset(name8, ' ', 8);
memset(ext3, ' ', 3);
if (!SysSvIsValid(src) || src.Length == 0) return;
size_t baseStart = 0;
size_t dot = (size_t)-1;
if (src.Data[0] == '.' && src.Length > 1) {
baseStart = 1;
} else {
for (const char *p = src; p && *p; p++) if (*p == '.') dot = p;
for (size_t i = 0; i < src.Length; i++)
if (src.Data[i] == '.') dot = i;
}
size_t end = (dot != (size_t)-1) ? dot : src.Length;
int ni = 0;
const char *end = dot ? dot : base + strlen(base);
for (const char *p = base; p < end && ni < 8; p++) {
char c = *p;
if (c >= 'a' && c <= 'z') c -= 32;
for (size_t i = baseStart; i < end && ni < 8; i++) {
char c = FatUpperChar(src.Data[i]);
name8[ni++] = c;
}
if (dot) {
if (dot != (size_t)-1) {
int ei = 0;
for (const char *p = dot + 1; *p && ei < 3; p++) {
char c = *p;
if (c >= 'a' && c <= 'z') c -= 32;
for (size_t i = dot + 1; i < src.Length && ei < 3; i++) {
char c = FatUpperChar(src.Data[i]);
ext3[ei++] = c;
}
}
@@ -515,30 +496,31 @@ static int FatIsValidShortChar(char c) {
// True when the user spelling can refer to a normal FAT 8.3 entry. This is
// intentionally structural and case-insensitive: "doom1.wad" must still open
// an existing short entry named DOOM1.WAD. Leading-dot names are not 8.3.
static int FatNameIsStructurallyShort83(const char *name) {
if (!name || !name[0]) return 0;
if (name[0] == '.') return 0;
static int FatNameIsStructurallyShort83V(SYS_STRING_VIEW name) {
if (!SysSvIsValid(name) || name.Length == 0) return 0;
if (name.Data[0] == '.') return 0;
const char *dot = NULL;
for (const char *p = name; *p; p++) {
if (*p == '.') {
if (dot) return 0; // multiple dots need LFN
dot = p;
} else if (!FatIsValidShortChar(*p)) {
size_t dot = (size_t)-1;
for (size_t i = 0; i < name.Length; i++) {
char c = name.Data[i];
if (c == '.') {
if (dot != (size_t)-1) return 0;
dot = i;
} else if (!FatIsValidShortChar(c)) {
return 0;
}
}
size_t baseLen = dot ? (size_t)(dot - name) : strlen(name);
size_t extLen = dot ? strlen(dot + 1) : 0;
size_t baseLen = (dot != (size_t)-1) ? dot : name.Length;
size_t extLen = (dot != (size_t)-1) ? (name.Length - dot - 1) : 0;
return baseLen >= 1 && baseLen <= 8 && extLen <= 3;
}
// Creation uses LFN when needed for structure, or when lowercase would be lost.
static int FatNameNeedsLfnForCreate(const char *name) {
if (!FatNameIsStructurallyShort83(name)) return 1;
for (const char *p = name; *p; p++)
if (FatIsLowerChar(*p)) return 1;
static int FatNameNeedsLfnForCreateV(SYS_STRING_VIEW name) {
if (!FatNameIsStructurallyShort83V(name)) return 1;
for (size_t i = 0; i < name.Length; i++)
if (FatIsLowerChar(name.Data[i])) return 1;
return 0;
}
@@ -624,33 +606,35 @@ static void FatAliasAppendChar(char *dst, int *len, int maxLen, char c) {
if (*len < maxLen) dst[(*len)++] = c;
}
static void BuildAliasStemExt(const char *src, char stem[9], char ext3[3]) {
static void BuildAliasStemExtV(SYS_STRING_VIEW src, char stem[9], char ext3[3]) {
memset(stem, 0, 9);
memset(ext3, ' ', 3);
if (!SysSvIsValid(src)) return;
const char *base = src;
const char *dot = NULL;
if (src[0] == '.' && src[1]) {
size_t baseStart = 0;
size_t dot = (size_t)-1;
if (src.Length > 1 && src.Data[0] == '.') {
// Hidden/Unix-style names like .doomrc become alias stem DOOMRC.
base = src + 1;
baseStart = 1;
} else {
for (const char *p = src; *p; p++) if (*p == '.') dot = p;
for (size_t i = 0; i < src.Length; i++)
if (src.Data[i] == '.') dot = i;
}
int slen = 0;
const char *end = dot ? dot : src + strlen(src);
for (const char *p = base; p < end && *p; p++)
FatAliasAppendChar(stem, &slen, 8, *p);
size_t end = (dot != (size_t)-1) ? dot : src.Length;
for (size_t i = baseStart; i < end; i++)
FatAliasAppendChar(stem, &slen, 8, src.Data[i]);
if (slen == 0) {
memcpy(stem, "FILE", 4);
slen = 4;
}
stem[slen] = '\0';
if (dot && dot[1]) {
if (dot != (size_t)-1 && dot + 1 < src.Length) {
int ei = 0;
for (const char *p = dot + 1; *p && ei < 3; p++) {
char c = FatUpperChar(*p);
for (size_t i = dot + 1; i < src.Length && ei < 3; i++) {
char c = FatUpperChar(src.Data[i]);
if (!FatIsValidShortChar(c)) continue;
ext3[ei++] = c;
}
@@ -683,11 +667,11 @@ static void MakeAliasAttempt(const char stem[9], const char extIn[3],
memcpy(name8 + keep, suffix, suffixLen);
}
static int MakeUniqueShortAlias(FAT32_VOL *v, uint32_t dirCluster,
const char *longName,
char name8[8], char ext3[3]) {
static int MakeUniqueShortAliasV(FAT32_VOL *v, uint32_t dirCluster,
SYS_STRING_VIEW longName,
char name8[8], char ext3[3]) {
char stem[9], extCandidate[3];
BuildAliasStemExt(longName, stem, extCandidate);
BuildAliasStemExtV(longName, stem, extCandidate);
for (uint32_t attempt = 1; attempt < 1000000; attempt++) {
MakeAliasAttempt(stem, extCandidate, attempt, name8, ext3);
@@ -696,12 +680,25 @@ static int MakeUniqueShortAlias(FAT32_VOL *v, uint32_t dirCluster,
return 0;
}
static KSTATUS DeleteLegacyBrokenDotAlias(FAT32_VOL *v, uint32_t dirCluster,
const char *longName) {
if (!longName || longName[0] != '.' || !longName[1]) return STATUS_SUCCESS;
static void MakeLegacyBrokenDot83V(SYS_STRING_VIEW src, char name8[8], char ext3[3]) {
// This exactly models the pre-fix bug for ".doomrc": empty name + "DOO".
memset(name8, ' ', 8);
memset(ext3, ' ', 3);
if (!SysSvIsValid(src)) return;
size_t dot = (size_t)-1;
for (size_t i = 0; i < src.Length; i++) if (src.Data[i] == '.') dot = i;
if (dot == (size_t)-1) return;
int ei = 0;
for (size_t i = dot + 1; i < src.Length && ei < 3; i++)
ext3[ei++] = FatUpperChar(src.Data[i]);
}
static KSTATUS DeleteLegacyBrokenDotAliasV(FAT32_VOL *v, uint32_t dirCluster,
SYS_STRING_VIEW longName) {
if (!SysSvIsValid(longName) || longName.Length < 2 || longName.Data[0] != '.') return STATUS_SUCCESS;
char badName[8], badExt[3];
MakeLegacyBrokenDot83(longName, badName, badExt);
MakeLegacyBrokenDot83V(longName, badName, badExt);
uint8_t *clusterBuf = (uint8_t *)MmAllocatePool(v->BytesPerCluster);
if (!clusterBuf) return STATUS_NO_MEMORY;
@@ -754,29 +751,71 @@ static void LfnAppend(char *lfn, const LFN_ENTRY *e) {
}
}
static int LfnMatch(const char *lfn, const char *want) {
while (*lfn && *want) {
char a = *lfn++, b = *want++;
// ---------------------------------------------------------------------------
// Directory search and view-native path traversal
// ---------------------------------------------------------------------------
static int Fat32IsPathSep(char c) {
return c == '\\' || c == '/';
}
static int Fat32NameViewIsValid(SYS_STRING_VIEW name) {
if (!SysSvIsValid(name)) return 0;
if (name.Length == 0 || name.Length >= MAX_LFN) return 0;
for (size_t i = 0; i < name.Length; i++) {
char c = name.Data[i];
if (c == '\0' || Fat32IsPathSep(c)) return 0;
}
return 1;
}
static int LfnMatchV(const char *lfn, SYS_STRING_VIEW want) {
if (!lfn || !SysSvIsValid(want)) return 0;
size_t i = 0;
while (lfn[i] && i < want.Length) {
char a = lfn[i], b = want.Data[i];
if (a >= 'A' && a <= 'Z') a += 32;
if (b >= 'A' && b <= 'Z') b += 32;
if (a != b) return 0;
i++;
}
return lfn[i] == '\0' && i == want.Length;
}
static int MatchName83V(const char *dirName, const char *dirExt,
SYS_STRING_VIEW want) {
char buf[13];
int n = 0;
for (int i = 0; i < 8 && dirName[i] != ' '; i++)
buf[n++] = (char)(dirName[i] >= 'A' && dirName[i] <= 'Z' ? dirName[i]+32 : dirName[i]);
if (dirExt[0] != ' ') {
buf[n++] = '.';
for (int i = 0; i < 3 && dirExt[i] != ' '; i++)
buf[n++] = (char)(dirExt[i] >= 'A' && dirExt[i] <= 'Z' ? dirExt[i]+32 : dirExt[i]);
}
if ((size_t)n != want.Length) return 0;
for (int i = 0; i < n; i++) {
char a = buf[i], b = want.Data[i];
if (a >= 'A' && a <= 'Z') a += 32;
if (b >= 'A' && b <= 'Z') b += 32;
if (a != b) return 0;
}
return *lfn == '\0' && *want == '\0';
return 1;
}
// ---------------------------------------------------------------------------
// Directory search
// ---------------------------------------------------------------------------
static int SearchDir(FAT32_VOL *v, uint32_t dirCluster, const char *name,
uint32_t *outCluster, uint32_t *outSize, uint8_t *outAttr,
uint64_t *outDirentLba, uint32_t *outDirentOffset) {
static int SearchDirV(FAT32_VOL *v, uint32_t dirCluster, SYS_STRING_VIEW name,
uint32_t *outCluster, uint32_t *outSize, uint8_t *outAttr,
uint64_t *outDirentLba, uint32_t *outDirentOffset) {
if (!Fat32NameViewIsValid(name)) return 0;
uint8_t *clusterBuf = (uint8_t *)MmAllocatePool(v->BytesPerCluster);
if (!clusterBuf) return 0;
char lfn[MAX_LFN]; int hasLfn = 0; memset(lfn, 0, sizeof(lfn));
char wantName83[8], wantExt83[3];
int allowShortMatch = FatNameIsStructurallyShort83(name);
Make83Name(name, wantName83, wantExt83);
int allowShortMatch = FatNameIsStructurallyShort83V(name);
Make83NameV(name, wantName83, wantExt83);
uint32_t cluster = dirCluster;
while (cluster >= 2 && cluster < FAT32_EOC) {
@@ -792,9 +831,9 @@ static int SearchDir(FAT32_VOL *v, uint32_t dirCluster, const char *name,
if (dir[i].Attr == ATTR_LFN) { LfnAppend(lfn, (LFN_ENTRY *)&dir[i]); hasLfn = 1; continue; }
int match = 0;
if (hasLfn && lfn[0]) match = LfnMatch(lfn, name);
if (hasLfn && lfn[0]) match = LfnMatchV(lfn, name);
if (!match && allowShortMatch)
match = MatchName83(dir[i].Name, dir[i].Ext, name);
match = MatchName83V(dir[i].Name, dir[i].Ext, name);
if (!match && allowShortMatch)
match = MatchRaw83(dir[i].Name, dir[i].Ext, wantName83, wantExt83);
hasLfn = 0; memset(lfn, 0, sizeof(lfn));
@@ -819,58 +858,92 @@ done:
return 0;
}
// ---------------------------------------------------------------------------
// Path traversal
// ---------------------------------------------------------------------------
static KSTATUS Fat32LookupPath(FAT32_VOL *v, const char *path,
uint32_t *outCluster, uint32_t *outSize,
uint64_t *outDirentLba, uint32_t *outDirentOffset) {
static int Fat32PathNextComponent(SYS_STRING_VIEW path, size_t* cursor,
SYS_STRING_VIEW* component) {
if (!cursor || !component || !SysSvIsValid(path)) return 0;
size_t pos = *cursor;
while (pos < path.Length && Fat32IsPathSep(path.Data[pos])) pos++;
if (pos >= path.Length) {
*cursor = pos;
*component = SYS_SV_NULL;
return 0;
}
size_t start = pos;
while (pos < path.Length && !Fat32IsPathSep(path.Data[pos])) pos++;
*cursor = pos;
*component = SysSvFromParts(path.Data + start, pos - start);
return 1;
}
static KSTATUS Fat32LookupPathV(FAT32_VOL *v, SYS_STRING_VIEW path,
uint32_t *outCluster, uint32_t *outSize,
uint64_t *outDirentLba, uint32_t *outDirentOffset) {
if (!v || !outCluster || !outSize || !SysSvIsValid(path))
return STATUS_INVALID_PARAMETER;
if (SysSvContainsByte(path, '\0'))
return STATUS_INVALID_PARAMETER;
uint32_t cluster = v->RootCluster, size = 0;
uint8_t attr = ATTR_DIRECTORY;
if (outDirentLba) *outDirentLba = 0;
if (outDirentOffset) *outDirentOffset = 0;
char component[256]; const char *p = path;
while (*p) {
while (*p == '\\' || *p == '/') p++;
if (!*p) break;
int len = 0;
while (*p && *p != '\\' && *p != '/' && len < 255) component[len++] = *p++;
component[len] = '\0';
if (!len) break;
size_t cursor = 0;
SYS_STRING_VIEW component;
while (Fat32PathNextComponent(path, &cursor, &component)) {
if (component.Length >= MAX_LFN) return STATUS_BUFFER_TOO_SMALL;
if (!Fat32NameViewIsValid(component)) return STATUS_INVALID_PARAMETER;
if (!(attr & ATTR_DIRECTORY)) return STATUS_NOT_FOUND;
uint32_t childCluster, childSize; uint8_t childAttr;
uint64_t childLba = 0; uint32_t childOffset = 0;
if (!SearchDir(v, cluster, component, &childCluster, &childSize,
&childAttr, &childLba, &childOffset))
if (!SearchDirV(v, cluster, component, &childCluster, &childSize,
&childAttr, &childLba, &childOffset))
return STATUS_NOT_FOUND;
cluster = childCluster; size = childSize; attr = childAttr;
if (outDirentLba) *outDirentLba = childLba;
if (outDirentOffset) *outDirentOffset = childOffset;
}
*outCluster = cluster; *outSize = size;
*outCluster = cluster;
*outSize = size;
return STATUS_SUCCESS;
}
static KSTATUS Traverse(FAT32_VOL *v, const char *path,
static KSTATUS TraverseV(FAT32_VOL *v, SYS_STRING_VIEW path,
uint32_t *outCluster, uint32_t *outSize) {
return Fat32LookupPath(v, path, outCluster, outSize, NULL, NULL);
return Fat32LookupPathV(v, path, outCluster, outSize, NULL, NULL);
}
// ---------------------------------------------------------------------------
// Path helpers for Fat32Create
// ---------------------------------------------------------------------------
static void SplitPath(const char *path, char parent[256], char name[256]) {
const char *last = NULL;
for (const char *p = path; *p; p++) if (*p == '\\' || *p == '/') last = p;
if (!last) { parent[0] = '\0'; strncpy(name, path, 255); name[255] = '\0'; }
else {
size_t len = (size_t)(last - path); if (len > 255) len = 255;
memcpy(parent, path, len); parent[len] = '\0';
strncpy(name, last+1, 255); name[255] = '\0';
static KSTATUS SplitPathV(SYS_STRING_VIEW path, SYS_STRING_VIEW* parent,
SYS_STRING_VIEW* name) {
if (!parent || !name || !SysSvIsValid(path)) return STATUS_INVALID_PARAMETER;
*parent = SYS_SV_NULL;
*name = SYS_SV_NULL;
while (path.Length && Fat32IsPathSep(path.Data[path.Length - 1]))
path.Length--;
if (path.Length == 0) return STATUS_INVALID_PARAMETER;
if (SysSvContainsByte(path, '\0')) return STATUS_INVALID_PARAMETER;
size_t lastSep = (size_t)-1;
for (size_t i = 0; i < path.Length; i++) {
if (Fat32IsPathSep(path.Data[i])) lastSep = i;
}
if (lastSep == (size_t)-1) {
*parent = SYS_SV_NULL;
*name = path;
} else {
*parent = SysSvFromParts(path.Data, lastSep);
*name = SysSvFromParts(path.Data + lastSep + 1, path.Length - lastSep - 1);
}
if (!Fat32NameViewIsValid(*name)) return STATUS_INVALID_PARAMETER;
return STATUS_SUCCESS;
}
// ---------------------------------------------------------------------------
@@ -969,11 +1042,15 @@ static int FindFreeDirentRun(FAT32_VOL *v, uint32_t dirCluster, uint32_t needed,
// ---------------------------------------------------------------------------
// Open / Close
// ---------------------------------------------------------------------------
static KSTATUS Fat32Open(IO_FILESYSTEM *fs, const char *path, void **fileCtx) {
static KSTATUS Fat32Open(IO_FILESYSTEM *fs, SYS_STRING_VIEW path, void **fileCtx) {
if (!fs || !fileCtx || !SysSvIsValid(path) || path.Length == 0)
return STATUS_INVALID_PARAMETER;
FAT32_VOL *v = (FAT32_VOL *)fs->DriverCtx;
uint32_t cluster, size; uint64_t direntLba; uint32_t direntOffset;
KSTATUS s = Fat32LookupPath(v, path, &cluster, &size, &direntLba, &direntOffset);
KSTATUS s = Fat32LookupPathV(v, path, &cluster, &size, &direntLba, &direntOffset);
if (!KSUCCESS(s)) return s;
FAT32_FILE *f = (FAT32_FILE *)MmAllocatePool(sizeof(FAT32_FILE));
if (!f) return STATUS_NO_MEMORY;
f->StartCluster = cluster; f->FileSize = size; f->Vol = v;
@@ -1013,11 +1090,19 @@ static KSTATUS Fat32Read(IO_FILESYSTEM *fs, void *fileCtx,
FAT32_FILE *f = (FAT32_FILE *)fileCtx;
FAT32_VOL *v = f->Vol;
if (offset >= f->FileSize || size == 0) return STATUS_SUCCESS;
if (offset + size > f->FileSize) size = (size_t)(f->FileSize - offset);
if (size > (size_t)(f->FileSize - offset)) size = (size_t)(f->FileSize - offset);
size_t wanted = size;
// Single allocation for the largest possible coalesced run.
uint8_t *runBuf = (uint8_t *)MmAllocatePool(MAX_RUN_SECTORS * 512u);
// Allocate only as much bounce space as this read can actually use.
// The old code allocated 64 KiB and could read a 64 KiB contiguous run even
// for tiny random reads; Doom does lots of seek/read pairs for small lumps.
uint32_t initialOffsetInCluster = (uint32_t)(offset % v->BytesPerCluster);
uint64_t initialBytesCovered = (uint64_t)initialOffsetInCluster + (uint64_t)size;
uint32_t maxUsefulSectors = (uint32_t)((initialBytesCovered + 511u) / 512u);
if (maxUsefulSectors < v->SectorsPerCluster) maxUsefulSectors = v->SectorsPerCluster;
if (maxUsefulSectors > MAX_RUN_SECTORS) maxUsefulSectors = MAX_RUN_SECTORS;
uint8_t *runBuf = (uint8_t *)MmAllocatePool((size_t)maxUsefulSectors * 512u);
if (!runBuf) return STATUS_NO_MEMORY;
size_t totalRead = 0;
@@ -1031,13 +1116,21 @@ static KSTATUS Fat32Read(IO_FILESYSTEM *fs, void *fileCtx,
cluster = FatEntry(v, cluster);
while (size > 0 && cluster >= 2 && cluster < FAT32_EOC) {
// Build the longest physically-contiguous run we can.
// Build the longest physically-contiguous run that can contribute to
// this caller's remaining read. Do not prefetch an unrelated 64 KiB run
// for a tiny random read.
uint64_t bytesCovered = (uint64_t)offsetInCluster + (uint64_t)size;
uint32_t usefulSectors = (uint32_t)((bytesCovered + 511u) / 512u);
if (usefulSectors < v->SectorsPerCluster) usefulSectors = v->SectorsPerCluster;
if (usefulSectors > MAX_RUN_SECTORS) usefulSectors = MAX_RUN_SECTORS;
if (usefulSectors > maxUsefulSectors) usefulSectors = maxUsefulSectors;
uint32_t runStart = cluster;
uint32_t runSectors = v->SectorsPerCluster;
uint32_t next = FatEntry(v, cluster);
while (next == cluster + 1 && next < FAT32_EOC
&& runSectors + v->SectorsPerCluster <= MAX_RUN_SECTORS) {
&& runSectors + v->SectorsPerCluster <= usefulSectors) {
cluster = next;
next = FatEntry(v, cluster);
runSectors += v->SectorsPerCluster;
@@ -1188,21 +1281,25 @@ static KSTATUS Fat32Write(IO_FILESYSTEM *fs, void *fileCtx,
// ---------------------------------------------------------------------------
static KSTATUS Fat32Truncate(IO_FILESYSTEM *fs, void *fileCtx, uint64_t newSize);
static KSTATUS Fat32Create(IO_FILESYSTEM *fs, const char *path, void **fileCtx) {
static KSTATUS Fat32Create(IO_FILESYSTEM *fs, SYS_STRING_VIEW path, void **fileCtx) {
if (!fs || !fileCtx || !SysSvIsValid(path) || path.Length == 0)
return STATUS_INVALID_PARAMETER;
FAT32_VOL *v = (FAT32_VOL *)fs->DriverCtx;
char parentPath[256], filename[256];
SplitPath(path, parentPath, filename);
if (!filename[0]) return STATUS_INVALID_PARAMETER;
SYS_STRING_VIEW parentPath;
SYS_STRING_VIEW filenameView;
KSTATUS s = SplitPathV(path, &parentPath, &filenameView);
if (!KSUCCESS(s)) return s;
uint32_t parentCluster, parentSize;
KSTATUS s = Traverse(v, parentPath, &parentCluster, &parentSize);
s = TraverseV(v, parentPath, &parentCluster, &parentSize);
if (!KSUCCESS(s)) return s;
{
uint32_t ec, es; uint8_t ea;
uint64_t existingLba = 0; uint32_t existingOffset = 0;
if (SearchDir(v, parentCluster, filename, &ec, &es, &ea,
&existingLba, &existingOffset)) {
if (SearchDirV(v, parentCluster, filenameView, &ec, &es, &ea,
&existingLba, &existingOffset)) {
if (ea & ATTR_DIRECTORY)
return STATUS_OBJECT_NAME_COLLISION;
@@ -1224,18 +1321,18 @@ static KSTATUS Fat32Create(IO_FILESYSTEM *fs, const char *path, void **fileCtx)
}
}
int useLfn = FatNameNeedsLfnForCreate(filename);
int useLfn = FatNameNeedsLfnForCreateV(filenameView);
char shortName[8], shortExt[3];
if (useLfn) {
s = DeleteLegacyBrokenDotAlias(v, parentCluster, filename);
s = DeleteLegacyBrokenDotAliasV(v, parentCluster, filenameView);
if (!KSUCCESS(s)) return s;
if (!MakeUniqueShortAlias(v, parentCluster, filename, shortName, shortExt))
if (!MakeUniqueShortAliasV(v, parentCluster, filenameView, shortName, shortExt))
return STATUS_OBJECT_NAME_COLLISION;
} else {
Make83Name(filename, shortName, shortExt);
Make83NameV(filenameView, shortName, shortExt);
}
size_t nameLen = strlen(filename);
size_t nameLen = filenameView.Length;
if (nameLen == 0 || nameLen >= MAX_LFN) return STATUS_INVALID_PARAMETER;
uint32_t lfnCount = useLfn ? (uint32_t)((nameLen + 12u) / 13u) : 0;
uint32_t neededEntries = lfnCount + 1u;
@@ -1258,7 +1355,7 @@ static KSTATUS Fat32Create(IO_FILESYSTEM *fs, const char *path, void **fileCtx)
uint8_t checksum = LfnChecksum(shortName, shortExt);
for (uint32_t slot = 0; slot < lfnCount; slot++) {
uint32_t ordinal = lfnCount - slot;
BuildLfnEntry((LFN_ENTRY *)&dir[firstIndex + slot], filename,
BuildLfnEntry((LFN_ENTRY *)&dir[firstIndex + slot], filenameView.Data,
nameLen, ordinal, lfnCount, checksum);
}
}
@@ -1348,10 +1445,13 @@ update_size:
// ---------------------------------------------------------------------------
// Delete
// ---------------------------------------------------------------------------
static KSTATUS Fat32Delete(IO_FILESYSTEM *fs, const char *path) {
static KSTATUS Fat32Delete(IO_FILESYSTEM *fs, SYS_STRING_VIEW path) {
if (!fs || !SysSvIsValid(path) || path.Length == 0)
return STATUS_INVALID_PARAMETER;
FAT32_VOL *v = (FAT32_VOL *)fs->DriverCtx;
uint32_t cluster, size; uint64_t direntLba; uint32_t direntOffset;
KSTATUS s = Fat32LookupPath(v, path, &cluster, &size, &direntLba, &direntOffset);
KSTATUS s = Fat32LookupPathV(v, path, &cluster, &size, &direntLba, &direntOffset);
if (!KSUCCESS(s)) return s;
if (!direntLba) return STATUS_ACCESS_DENIED;
@@ -1389,13 +1489,17 @@ typedef struct {
uint8_t *ClusterBuf; // allocated once in OpenDir, freed in CloseDir
} FAT32_DIR_CTX;
static KSTATUS Fat32OpenDir(IO_FILESYSTEM *fs, const char *dirPath, void **dirCtx) {
static KSTATUS Fat32OpenDir(IO_FILESYSTEM *fs, SYS_STRING_VIEW dirPath, void **dirCtx) {
if (!fs || !dirCtx || !SysSvIsValid(dirPath))
return STATUS_INVALID_PARAMETER;
FAT32_VOL *v = (FAT32_VOL *)fs->DriverCtx;
uint32_t cluster;
if (!dirPath || dirPath[0] == '\0') {
if (dirPath.Length == 0) {
cluster = v->RootCluster;
} else {
uint32_t size; KSTATUS s = Traverse(v, dirPath, &cluster, &size);
uint32_t size;
KSTATUS s = TraverseV(v, dirPath, &cluster, &size);
if (!KSUCCESS(s)) return s;
}