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:
1 parent
603fbdfab1
commit
e1248f4afe
43 files changed
+2892
-1857
No files matched your search
+248
-144
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user