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
+176
-145
@@ -387,22 +387,26 @@ __declspec(dllexport) KSTATUS IoQueryAsyncFileRequest(IO_ASYNC_FILE_REQUEST_OBJE
|
||||
// Stored as (CurrentDrive, drive-relative path with no trailing backslash).
|
||||
// Exported as native "N:/path" so personalities can round-trip volumes.
|
||||
// ---------------------------------------------------------------------------
|
||||
#define CWD_MAX 512
|
||||
#define CWD_MAX PROCESS_CWD_MAX
|
||||
|
||||
static size_t KiFormatCwd(uint8_t drive, const char* rel, char* buf, size_t size) {
|
||||
if (!buf || size == 0) return 0;
|
||||
typedef struct KRESOLVED_PATH {
|
||||
uint8_t Drive;
|
||||
char Storage[CWD_MAX];
|
||||
SYS_STRING_VIEW Path;
|
||||
} KRESOLVED_PATH;
|
||||
|
||||
static size_t KiFormatCwd(uint8_t drive, SYS_STRING_VIEW rel, char* buf, size_t size) {
|
||||
if (!buf || size == 0 || !SysSvIsValid(rel)) return 0;
|
||||
if (drive > 7) drive = 0;
|
||||
if (!rel) rel = "";
|
||||
|
||||
size_t relLen = strlen(rel);
|
||||
size_t needed = 3 + relLen + 1;
|
||||
size_t needed = 3 + rel.Length + 1;
|
||||
if (needed > size) return needed;
|
||||
|
||||
buf[0] = (char)('0' + drive);
|
||||
buf[1] = ':';
|
||||
buf[2] = '/';
|
||||
memcpy(buf + 3, rel, relLen);
|
||||
buf[3 + relLen] = '\0';
|
||||
if (rel.Length) memcpy(buf + 3, rel.Data, rel.Length);
|
||||
buf[3 + rel.Length] = '\0';
|
||||
return needed;
|
||||
}
|
||||
|
||||
@@ -413,17 +417,57 @@ __declspec(dllexport) KSTATUS IoGetCwd(char* buf, size_t size) {
|
||||
if (!proc) return STATUS_ACCESS_DENIED;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&proc->CwdLock);
|
||||
size_t needed = KiFormatCwd(proc->CurrentDrive, proc->CurrentDirectory, buf, size);
|
||||
size_t needed = KiFormatCwd(proc->CurrentDrive, SysSvFromParts(proc->CurrentDirectory, proc->CurrentDirectoryLength), buf, size);
|
||||
KeReleaseSpinlock(&proc->CwdLock, flags);
|
||||
|
||||
return needed && needed <= size ? STATUS_SUCCESS : STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
// Resolve a possibly-relative path component against the CWD.
|
||||
// Writes the fully-resolved, drive-stripped relative path into 'resolved'
|
||||
// (caller supplies buf of at least CWD_MAX bytes).
|
||||
// Returns the drive index.
|
||||
static uint8_t KiResolvePath(const char* path, char* resolved, size_t resolvedSize) {
|
||||
static int KiSvHasDriveRoot(SYS_STRING_VIEW path) {
|
||||
return path.Length >= 3 &&
|
||||
path.Data[0] >= '0' && path.Data[0] <= '7' &&
|
||||
path.Data[1] == ':' &&
|
||||
(path.Data[2] == '\\' || path.Data[2] == '/');
|
||||
}
|
||||
|
||||
static int KiAppendBytes(char* work, size_t* workLen, size_t cap,
|
||||
const char* data, size_t len) {
|
||||
if (!work || !workLen || (!data && len)) return 0;
|
||||
if (*workLen + len >= cap) return 0;
|
||||
if (len) memcpy(work + *workLen, data, len);
|
||||
*workLen += len;
|
||||
work[*workLen] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int KiAppendComponent(char* work, size_t* workLen, size_t cap,
|
||||
const char* data, size_t len) {
|
||||
if (!work || !workLen || (!data && len)) return 0;
|
||||
if (*workLen && work[*workLen - 1] != '\\' && work[*workLen - 1] != '/') {
|
||||
if (!KiAppendBytes(work, workLen, cap, "\\", 1)) return 0;
|
||||
}
|
||||
return KiAppendBytes(work, workLen, cap, data, len);
|
||||
}
|
||||
|
||||
static void KiPopComponent(char* work, size_t* workLen) {
|
||||
if (!work || !workLen || *workLen == 0) return;
|
||||
size_t i = *workLen;
|
||||
while (i > 0 && work[i - 1] != '\\' && work[i - 1] != '/') i--;
|
||||
if (i > 0) i--;
|
||||
*workLen = i;
|
||||
work[i] = '\0';
|
||||
}
|
||||
|
||||
// Resolve a possibly-relative string view against the CWD.
|
||||
// The returned view is backed by out->Storage and remains valid while 'out' lives.
|
||||
static KSTATUS KiResolvePathV(SYS_STRING_VIEW input, KRESOLVED_PATH* out) {
|
||||
if (!out) return STATUS_INVALID_PARAMETER;
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
if (!SysSvIsValid(input)) return STATUS_INVALID_PARAMETER;
|
||||
if (SysSvContainsByte(input, '\0')) return STATUS_INVALID_PARAMETER;
|
||||
if (input.Length >= CWD_MAX) return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
uint8_t drive = 0;
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (proc) {
|
||||
@@ -432,128 +476,98 @@ static uint8_t KiResolvePath(const char* path, char* resolved, size_t resolvedSi
|
||||
KeReleaseSpinlock(&proc->CwdLock, flags);
|
||||
}
|
||||
|
||||
// Strip explicit drive prefix "N:\" or "N:/".
|
||||
size_t pos = 0;
|
||||
bool fromDriveRoot = false;
|
||||
if (path[0] >= '0' && path[0] <= '7' &&
|
||||
path[1] == ':' && (path[2] == '\\' || path[2] == '/')) {
|
||||
drive = (uint8_t)(path[0] - '0');
|
||||
path = path + 3;
|
||||
if (KiSvHasDriveRoot(input)) {
|
||||
drive = (uint8_t)(input.Data[0] - '0');
|
||||
pos = 3;
|
||||
fromDriveRoot = true;
|
||||
}
|
||||
|
||||
char work[CWD_MAX * 2];
|
||||
size_t workLen = 0;
|
||||
work[0] = '\0';
|
||||
|
||||
// Initialize our working base
|
||||
if (path[0] == '\\' || path[0] == '/' || fromDriveRoot) {
|
||||
// Absolute path: start from the root (empty work buffer)
|
||||
// The segment loop below will automatically skip the leading separators.
|
||||
} else {
|
||||
// Relative path: start from the current process's CWD
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (proc) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&proc->CwdLock);
|
||||
size_t wlen = strlen(proc->CurrentDirectory);
|
||||
if (wlen >= sizeof(work)) wlen = sizeof(work) - 1;
|
||||
memcpy(work, proc->CurrentDirectory, wlen);
|
||||
work[wlen] = '\0';
|
||||
KeReleaseSpinlock(&proc->CwdLock, flags);
|
||||
}
|
||||
bool absolute = fromDriveRoot ||
|
||||
(pos < input.Length && (input.Data[pos] == '\\' || input.Data[pos] == '/'));
|
||||
if (!absolute && proc) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&proc->CwdLock);
|
||||
size_t cwdLen = proc->CurrentDirectoryLength;
|
||||
if (cwdLen >= sizeof(work)) cwdLen = sizeof(work) - 1;
|
||||
memcpy(work, proc->CurrentDirectory, cwdLen);
|
||||
work[cwdLen] = '\0';
|
||||
workLen = cwdLen;
|
||||
KeReleaseSpinlock(&proc->CwdLock, flags);
|
||||
}
|
||||
|
||||
// Segment-by-segment canonicalization
|
||||
const char* p = path;
|
||||
while (*p) {
|
||||
// Skip separators
|
||||
while (*p == '\\' || *p == '/') p++;
|
||||
if (!*p) break;
|
||||
while (pos < input.Length) {
|
||||
while (pos < input.Length && (input.Data[pos] == '\\' || input.Data[pos] == '/')) pos++;
|
||||
if (pos >= input.Length) break;
|
||||
|
||||
// Read next component
|
||||
char comp[256];
|
||||
int clen = 0;
|
||||
while (*p && *p != '\\' && *p != '/' && clen < 255)
|
||||
comp[clen++] = *p++;
|
||||
comp[clen] = '\0';
|
||||
size_t compStart = pos;
|
||||
while (pos < input.Length && input.Data[pos] != '\\' && input.Data[pos] != '/') pos++;
|
||||
size_t compLen = pos - compStart;
|
||||
if (compLen == 0) continue;
|
||||
|
||||
if (clen == 0) continue;
|
||||
|
||||
if (strcmp(comp, ".") == 0) {
|
||||
// Stay in place
|
||||
} else if (strcmp(comp, "..") == 0) {
|
||||
// Remove last component from work
|
||||
int i = (int)strlen(work) - 1;
|
||||
while (i >= 0 && work[i] != '\\' && work[i] != '/') i--;
|
||||
if (i < 0) i = 0;
|
||||
work[i] = '\0';
|
||||
} else {
|
||||
// Append separator + component
|
||||
size_t wl = strlen(work);
|
||||
if (wl > 0 && work[wl-1] != '\\' && work[wl-1] != '/') {
|
||||
if (wl + 1 < sizeof(work)) { work[wl] = '\\'; work[wl+1] = '\0'; }
|
||||
}
|
||||
size_t wl2 = strlen(work);
|
||||
if (wl2 + clen + 1 < sizeof(work)) {
|
||||
memcpy(work + wl2, comp, clen);
|
||||
work[wl2 + clen] = '\0';
|
||||
}
|
||||
if (compLen == 1 && input.Data[compStart] == '.') {
|
||||
continue;
|
||||
}
|
||||
if (compLen == 2 && input.Data[compStart] == '.' && input.Data[compStart + 1] == '.') {
|
||||
KiPopComponent(work, &workLen);
|
||||
continue;
|
||||
}
|
||||
if (compLen >= 256) return STATUS_BUFFER_TOO_SMALL;
|
||||
if (!KiAppendComponent(work, &workLen, sizeof(work), input.Data + compStart, compLen))
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
// Output the final canonicalized, drive-stripped path
|
||||
size_t finalLen = strlen(work);
|
||||
if (finalLen + 1 > resolvedSize) finalLen = resolvedSize - 1;
|
||||
memcpy(resolved, work, finalLen);
|
||||
resolved[finalLen] = '\0';
|
||||
|
||||
return drive;
|
||||
if (workLen + 1 > sizeof(out->Storage)) return STATUS_BUFFER_TOO_SMALL;
|
||||
memcpy(out->Storage, work, workLen);
|
||||
out->Storage[workLen] = '\0';
|
||||
out->Drive = drive;
|
||||
out->Path = SysSvFromParts(out->Storage, workLen);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS IoSetCwd(const char* path) {
|
||||
if (!path) return STATUS_INVALID_PARAMETER;
|
||||
__declspec(dllexport) KSTATUS IoSetCwd(SYS_STRING_VIEW path) {
|
||||
if (path.Length && !path.Data) return STATUS_INVALID_PARAMETER;
|
||||
if (!KeCanWait()) return STATUS_INVALID_IRQL;
|
||||
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (!proc) return STATUS_ACCESS_DENIED;
|
||||
|
||||
// Resolve the new path (this also validates ".." navigation).
|
||||
// Note: KiResolvePath already uses proc->CurrentDirectory internally!
|
||||
char resolved[CWD_MAX];
|
||||
uint8_t drive = KiResolvePath(path, resolved, sizeof(resolved));
|
||||
KRESOLVED_PATH resolved;
|
||||
KSTATUS s = KiResolvePathV(path, &resolved);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
// Validate: try to open the directory to confirm it actually exists on disk
|
||||
IO_FILESYSTEM* fs = gVolumes[drive].Fs;
|
||||
IO_FILESYSTEM* fs = gVolumes[resolved.Drive].Fs;
|
||||
if (!fs) return STATUS_NOT_FOUND;
|
||||
if (!fs->OpenDir) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
void* dirCtx = NULL;
|
||||
KSTATUS s = fs->OpenDir(fs, resolved, &dirCtx);
|
||||
s = fs->OpenDir(fs, resolved.Path, &dirCtx);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
fs->CloseDir(fs, dirCtx);
|
||||
|
||||
// Commit the new CWD to the process block
|
||||
size_t len = strlen(resolved);
|
||||
if (len + 1 > sizeof(proc->CurrentDirectory)) return STATUS_BUFFER_TOO_SMALL;
|
||||
if (resolved.Path.Length + 1 > sizeof(proc->CurrentDirectory)) return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&proc->CwdLock);
|
||||
proc->CurrentDrive = drive;
|
||||
memcpy(proc->CurrentDirectory, resolved, len + 1);
|
||||
proc->CurrentDrive = resolved.Drive;
|
||||
proc->CurrentDirectoryLength = resolved.Path.Length;
|
||||
memcpy(proc->CurrentDirectory, resolved.Path.Data, resolved.Path.Length);
|
||||
proc->CurrentDirectory[resolved.Path.Length] = '\0';
|
||||
|
||||
// Keep the user-visible PEB mirror in sync. The PEB's CWD buffer is a
|
||||
// fixed SYS_CWD_MAX allocation made at process creation, so the pointer
|
||||
// remains stable for personalities that cache SYS_PEB*.
|
||||
if (proc->UserCwdBase && proc->UserCwdSize) {
|
||||
size_t formatted = KiFormatCwd(drive, resolved, (char*)proc->UserCwdBase, proc->UserCwdSize);
|
||||
size_t formatted = KiFormatCwd(resolved.Drive, resolved.Path, (char*)proc->UserCwdBase, proc->UserCwdSize);
|
||||
size_t copyLen = (formatted && formatted <= proc->UserCwdSize) ? formatted - 1 : proc->UserCwdSize - 1;
|
||||
|
||||
SYS_PEB* peb = (SYS_PEB*)proc->UserPebBase;
|
||||
if (peb && peb->Magic == SYS_PEB_MAGIC) {
|
||||
peb->CurrentDirectory = (const char*)proc->UserCwdBase;
|
||||
peb->CurrentDirectoryLength = copyLen;
|
||||
peb->CurrentDirectory = SysSvFromParts((const char*)proc->UserCwdBase, copyLen);
|
||||
}
|
||||
}
|
||||
|
||||
KeReleaseSpinlock(&proc->CwdLock, flags);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -583,18 +597,20 @@ static void KiFileDestroy(OBJECT* obj) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// IoOpenFile
|
||||
// ---------------------------------------------------------------------------
|
||||
__declspec(dllexport) KSTATUS IoOpenFile(const char* path, FILE_OBJECT **out) {
|
||||
if (!path || !out) return STATUS_INVALID_PARAMETER;
|
||||
__declspec(dllexport) KSTATUS IoOpenFile(SYS_STRING_VIEW path, FILE_OBJECT **out) {
|
||||
if ((!path.Data && path.Length) || !out) return STATUS_INVALID_PARAMETER;
|
||||
if (!KeCanWait()) return STATUS_INVALID_IRQL;
|
||||
if (path.Length == 0) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
char relPath[CWD_MAX];
|
||||
uint8_t drive = KiResolvePath(path, relPath, sizeof(relPath));
|
||||
KRESOLVED_PATH resolved;
|
||||
KSTATUS s = KiResolvePathV(path, &resolved);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
IO_FILESYSTEM* fs = gVolumes[drive].Fs;
|
||||
IO_FILESYSTEM* fs = gVolumes[resolved.Drive].Fs;
|
||||
if (!fs) return STATUS_NOT_FOUND;
|
||||
|
||||
void* fileCtx;
|
||||
KSTATUS s = fs->Open(fs, relPath, &fileCtx);
|
||||
s = fs->Open(fs, resolved.Path, &fileCtx);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
FILE_OBJECT* f = (FILE_OBJECT *)ObAllocateObject(ObjectTypeFile /* reuse slot */,
|
||||
@@ -603,6 +619,7 @@ __declspec(dllexport) KSTATUS IoOpenFile(const char* path, FILE_OBJECT **out) {
|
||||
f->Header.Destroy = KiFileDestroy;
|
||||
f->Fs = fs;
|
||||
f->FileCtx = fileCtx;
|
||||
f->Lock = (SPINLOCK)SPINLOCK_INIT;
|
||||
f->Size = fs->GetSize(fs, fileCtx);
|
||||
f->Offset = 0;
|
||||
|
||||
@@ -701,19 +718,20 @@ __declspec(dllexport) KSTATUS IoWriteFile(FILE_OBJECT* file, const void* buf,
|
||||
// ---------------------------------------------------------------------------
|
||||
// IoCreateFile - create a new file and return it open for writing
|
||||
// ---------------------------------------------------------------------------
|
||||
__declspec(dllexport) KSTATUS IoCreateFile(const char* path, FILE_OBJECT** out) {
|
||||
if (!path || !out) return STATUS_INVALID_PARAMETER;
|
||||
__declspec(dllexport) KSTATUS IoCreateFile(SYS_STRING_VIEW path, FILE_OBJECT** out) {
|
||||
if ((!path.Data && path.Length) || !out || path.Length == 0) return STATUS_INVALID_PARAMETER;
|
||||
if (!KeCanWait()) return STATUS_INVALID_IRQL;
|
||||
|
||||
char relPath[CWD_MAX];
|
||||
uint8_t drive = KiResolvePath(path, relPath, sizeof(relPath));
|
||||
KRESOLVED_PATH resolved;
|
||||
KSTATUS s = KiResolvePathV(path, &resolved);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
IO_FILESYSTEM* fs = gVolumes[drive].Fs;
|
||||
IO_FILESYSTEM* fs = gVolumes[resolved.Drive].Fs;
|
||||
if (!fs) return STATUS_NOT_FOUND;
|
||||
if (!fs->Create) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
void* fileCtx;
|
||||
KSTATUS s = fs->Create(fs, relPath, &fileCtx);
|
||||
s = fs->Create(fs, resolved.Path, &fileCtx);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
FILE_OBJECT* f = (FILE_OBJECT*)ObAllocateObject(ObjectTypeFile,
|
||||
@@ -733,63 +751,69 @@ __declspec(dllexport) KSTATUS IoCreateFile(const char* path, FILE_OBJECT** out)
|
||||
// ---------------------------------------------------------------------------
|
||||
// IoDeleteFile - delete a file by path (does not require an open handle)
|
||||
// ---------------------------------------------------------------------------
|
||||
__declspec(dllexport) KSTATUS IoDeleteFile(const char* path) {
|
||||
if (!path) return STATUS_INVALID_PARAMETER;
|
||||
__declspec(dllexport) KSTATUS IoDeleteFile(SYS_STRING_VIEW path) {
|
||||
if ((!path.Data && path.Length) || path.Length == 0) return STATUS_INVALID_PARAMETER;
|
||||
if (!KeCanWait()) return STATUS_INVALID_IRQL;
|
||||
|
||||
char relPath[CWD_MAX];
|
||||
uint8_t drive = KiResolvePath(path, relPath, sizeof(relPath));
|
||||
KRESOLVED_PATH resolved;
|
||||
KSTATUS s = KiResolvePathV(path, &resolved);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
IO_FILESYSTEM* fs = gVolumes[drive].Fs;
|
||||
IO_FILESYSTEM* fs = gVolumes[resolved.Drive].Fs;
|
||||
if (!fs) return STATUS_NOT_FOUND;
|
||||
if (!fs->Delete) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
return fs->Delete(fs, relPath);
|
||||
return fs->Delete(fs, resolved.Path);
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS IoRenameFile(const char* oldPath, const char* newPath) {
|
||||
if (!oldPath || !newPath) return STATUS_INVALID_PARAMETER;
|
||||
__declspec(dllexport) KSTATUS IoRenameFile(SYS_STRING_VIEW oldPath, SYS_STRING_VIEW newPath) {
|
||||
if ((!oldPath.Data && oldPath.Length) || (!newPath.Data && newPath.Length) ||
|
||||
oldPath.Length == 0 || newPath.Length == 0) return STATUS_INVALID_PARAMETER;
|
||||
if (!KeCanWait()) return STATUS_INVALID_IRQL;
|
||||
|
||||
char oldRel[CWD_MAX];
|
||||
char newRel[CWD_MAX];
|
||||
uint8_t oldDrive = KiResolvePath(oldPath, oldRel, sizeof(oldRel));
|
||||
uint8_t newDrive = KiResolvePath(newPath, newRel, sizeof(newRel));
|
||||
if (oldDrive != newDrive) return STATUS_NOT_SUPPORTED;
|
||||
KRESOLVED_PATH oldResolved;
|
||||
KRESOLVED_PATH newResolved;
|
||||
KSTATUS s = KiResolvePathV(oldPath, &oldResolved);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
s = KiResolvePathV(newPath, &newResolved);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
if (oldResolved.Drive != newResolved.Drive) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
IO_FILESYSTEM* fs = gVolumes[oldDrive].Fs;
|
||||
IO_FILESYSTEM* fs = gVolumes[oldResolved.Drive].Fs;
|
||||
if (!fs) return STATUS_NOT_FOUND;
|
||||
if (!fs->Rename) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
return fs->Rename(fs, oldRel, newRel);
|
||||
return fs->Rename(fs, oldResolved.Path, newResolved.Path);
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS IoCreateDir(const char* path) {
|
||||
if (!path) return STATUS_INVALID_PARAMETER;
|
||||
__declspec(dllexport) KSTATUS IoCreateDir(SYS_STRING_VIEW path) {
|
||||
if ((!path.Data && path.Length) || path.Length == 0) return STATUS_INVALID_PARAMETER;
|
||||
if (!KeCanWait()) return STATUS_INVALID_IRQL;
|
||||
|
||||
char relPath[CWD_MAX];
|
||||
uint8_t drive = KiResolvePath(path, relPath, sizeof(relPath));
|
||||
KRESOLVED_PATH resolved;
|
||||
KSTATUS s = KiResolvePathV(path, &resolved);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
IO_FILESYSTEM* fs = gVolumes[drive].Fs;
|
||||
IO_FILESYSTEM* fs = gVolumes[resolved.Drive].Fs;
|
||||
if (!fs) return STATUS_NOT_FOUND;
|
||||
if (!fs->CreateDir) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
return fs->CreateDir(fs, relPath);
|
||||
return fs->CreateDir(fs, resolved.Path);
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS IoRemoveDir(const char* path) {
|
||||
if (!path) return STATUS_INVALID_PARAMETER;
|
||||
__declspec(dllexport) KSTATUS IoRemoveDir(SYS_STRING_VIEW path) {
|
||||
if ((!path.Data && path.Length) || path.Length == 0) return STATUS_INVALID_PARAMETER;
|
||||
if (!KeCanWait()) return STATUS_INVALID_IRQL;
|
||||
|
||||
char relPath[CWD_MAX];
|
||||
uint8_t drive = KiResolvePath(path, relPath, sizeof(relPath));
|
||||
KRESOLVED_PATH resolved;
|
||||
KSTATUS s = KiResolvePathV(path, &resolved);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
IO_FILESYSTEM* fs = gVolumes[drive].Fs;
|
||||
IO_FILESYSTEM* fs = gVolumes[resolved.Drive].Fs;
|
||||
if (!fs) return STATUS_NOT_FOUND;
|
||||
if (!fs->RemoveDir) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
return fs->RemoveDir(fs, relPath);
|
||||
return fs->RemoveDir(fs, resolved.Path);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -840,37 +864,44 @@ static void KiDirDestroy(OBJECT* obj) {
|
||||
if (d->Fs && d->DirCtx) d->Fs->CloseDir(d->Fs, d->DirCtx);
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS IoOpenDir(const char* dirPath, DIR_OBJECT** out) {
|
||||
__declspec(dllexport) KSTATUS IoOpenDir(SYS_STRING_VIEW dirPath, DIR_OBJECT** out) {
|
||||
if (!out) return STATUS_INVALID_PARAMETER;
|
||||
if (dirPath.Length && !dirPath.Data) return STATUS_INVALID_PARAMETER;
|
||||
if (!KeCanWait()) return STATUS_INVALID_IRQL;
|
||||
|
||||
// NULL or empty path means the CWD itself
|
||||
char relPath[CWD_MAX];
|
||||
uint8_t drive;
|
||||
KRESOLVED_PATH resolved;
|
||||
KSTATUS s;
|
||||
|
||||
if (!dirPath || dirPath[0] == '\0') {
|
||||
if (dirPath.Length == 0) {
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (!proc) return STATUS_ACCESS_DENIED;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&proc->CwdLock);
|
||||
memcpy(relPath, proc->CurrentDirectory, strlen(proc->CurrentDirectory) + 1);
|
||||
drive = proc->CurrentDrive;
|
||||
size_t cwdLen = proc->CurrentDirectoryLength;
|
||||
if (cwdLen + 1 > sizeof(resolved.Storage)) {
|
||||
KeReleaseSpinlock(&proc->CwdLock, flags);
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
memcpy(resolved.Storage, proc->CurrentDirectory, cwdLen + 1);
|
||||
resolved.Drive = proc->CurrentDrive;
|
||||
resolved.Path = SysSvFromParts(resolved.Storage, cwdLen);
|
||||
KeReleaseSpinlock(&proc->CwdLock, flags);
|
||||
} else {
|
||||
drive = KiResolvePath(dirPath, relPath, sizeof(relPath));
|
||||
s = KiResolvePathV(dirPath, &resolved);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
}
|
||||
|
||||
IO_FILESYSTEM* fs = gVolumes[drive].Fs;
|
||||
IO_FILESYSTEM* fs = gVolumes[resolved.Drive].Fs;
|
||||
if (!fs) return STATUS_NOT_FOUND;
|
||||
if (!fs->OpenDir) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
void* dirCtx = NULL;
|
||||
KSTATUS s = fs->OpenDir(fs, relPath, &dirCtx);
|
||||
s = fs->OpenDir(fs, resolved.Path, &dirCtx);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
DIR_OBJECT* d = (DIR_OBJECT*)ObAllocateObject(ObjectTypeDir, sizeof(DIR_OBJECT));
|
||||
if (!d) { fs->CloseDir(fs, dirCtx); return STATUS_NO_MEMORY; }
|
||||
|
||||
|
||||
d->Header.Destroy = KiDirDestroy;
|
||||
d->Fs = fs;
|
||||
d->DirCtx = dirCtx;
|
||||
|
||||
Reference in new issue
Block a user