redo boot around an explicit system volume and fixed kernel/HAL images, redo volumes and filesystem paths around capabilities instead of drive numbers and kernel CWD state, add a capability/security model with derived and revocable handles and security contexts, add port IPC and rssrv to manage the userspace resource namespace and publish the system volume, move process, dll and path loading to userspace and add process builder syscalls, init now supervises rssrv and the session process, redo the syscall ABI around request structs and four arguments, add a volume manager and proper partition arrival/removal handling so FAT and NTFS mount dynamically, clean up the HAL/DDK boundary so drivers don't depend on HAL internals, save fpu state properly now, the serial driver doesn't hang on a missing port, fix AHCI startup races, fix timeout accounting, fix shared mmap writeback, more smoke tests
This commit is contained in:
1 parent
4add6789ba
commit
f882d339fb
232 files changed
+20934
-8898
No files matched your search
+352
-562
File diff suppressed because it is too large.
Load diff
+23
-21
@@ -21,25 +21,27 @@
|
||||
|
||||
typedef struct FAT_VOL_S FAT_VOL;
|
||||
|
||||
KSTATUS FatOpen(IO_FILESYSTEM *fs, SYS_STRING_VIEW path, void **fileCtx);
|
||||
KSTATUS FatFlush(IO_FILESYSTEM *fs, void *fileCtx);
|
||||
void FatClose(IO_FILESYSTEM *fs, void *fileCtx);
|
||||
KSTATUS FatRead(IO_FILESYSTEM *fs, void *fileCtx, uint64_t offset, void *buf, size_t size, size_t *bytesRead);
|
||||
KSTATUS FatWrite(IO_FILESYSTEM *fs, void *fileCtx, uint64_t offset, const void *buf, size_t size, size_t *bytesWritten);
|
||||
KSTATUS FatReadAsync(IO_FILESYSTEM *fs, void *fileCtx, uint64_t offset, void *buf, size_t size, IO_FS_ASYNC_COMPLETE complete, void *completeContext);
|
||||
KSTATUS FatWriteAsync(IO_FILESYSTEM *fs, void *fileCtx, uint64_t offset, const void *buf, size_t size, IO_FS_ASYNC_COMPLETE complete, void *completeContext);
|
||||
KSTATUS FatCreate(IO_FILESYSTEM *fs, SYS_STRING_VIEW path, void **fileCtx);
|
||||
KSTATUS FatCreateDir(IO_FILESYSTEM *fs, SYS_STRING_VIEW path);
|
||||
KSTATUS FatRemoveDir(IO_FILESYSTEM *fs, SYS_STRING_VIEW path);
|
||||
KSTATUS FatDelete(IO_FILESYSTEM *fs, SYS_STRING_VIEW path);
|
||||
KSTATUS FatTruncate(IO_FILESYSTEM *fs, void *fileCtx, uint64_t newSize, uint32_t fileFlags);
|
||||
uint64_t FatGetSize(IO_FILESYSTEM *fs, void *fileCtx);
|
||||
KSTATUS FatQueryInfo(IO_FILESYSTEM *fs, void *fileCtx, SYS_FILE_STAT *out);
|
||||
KSTATUS FatStat(IO_FILESYSTEM *fs, SYS_STRING_VIEW path, SYS_FILE_STAT *out);
|
||||
KSTATUS FatQueryIdentity(IO_FILESYSTEM *fs, void *fileCtx, IO_FILE_IDENTITY *out);
|
||||
KSTATUS FatOpenDir(IO_FILESYSTEM *fs, SYS_STRING_VIEW dirPath, void **dirCtx);
|
||||
KSTATUS FatReadDir(IO_FILESYSTEM *fs, void *dirCtx, KDIR_ENTRY *out);
|
||||
void FatCloseDir(IO_FILESYSTEM *fs, void *dirCtx);
|
||||
void FatQueryStats(IO_FILESYSTEM *fs, IO_FILESYSTEM_STATS *out);
|
||||
KSTATUS FatOpen(IO_VOLUME_PROVIDER* fs, SYS_STRING_VIEW path, void** fileCtx);
|
||||
KSTATUS FatFlush(IO_VOLUME_PROVIDER* fs, void* fileCtx);
|
||||
void FatClose(IO_VOLUME_PROVIDER* fs, void* fileCtx);
|
||||
KSTATUS FatRead(IO_VOLUME_PROVIDER* fs, void* fileCtx, uint64_t offset, void* buf, size_t size, size_t* bytesRead);
|
||||
KSTATUS FatWrite(IO_VOLUME_PROVIDER* fs, void* fileCtx, uint64_t offset, const void* buf, size_t size, size_t* bytesWritten);
|
||||
KSTATUS FatReadAsync(IO_VOLUME_PROVIDER* fs, void* fileCtx, uint64_t offset, void* buf, size_t size, IO_FS_ASYNC_COMPLETE complete, void* completeContext);
|
||||
KSTATUS FatWriteAsync(IO_VOLUME_PROVIDER* fs, void* fileCtx, uint64_t offset, const void* buf, size_t size, IO_FS_ASYNC_COMPLETE complete, void* completeContext);
|
||||
KSTATUS FatCreate(IO_VOLUME_PROVIDER* fs, SYS_STRING_VIEW path, void** fileCtx);
|
||||
KSTATUS FatCreateDir(IO_VOLUME_PROVIDER* fs, SYS_STRING_VIEW path);
|
||||
KSTATUS FatRemoveDir(IO_VOLUME_PROVIDER* fs, SYS_STRING_VIEW path);
|
||||
KSTATUS FatDelete(IO_VOLUME_PROVIDER* fs, SYS_STRING_VIEW path);
|
||||
KSTATUS FatTruncate(IO_VOLUME_PROVIDER* fs, void* fileCtx, uint64_t newSize, uint32_t fileFlags);
|
||||
uint64_t FatGetSize(IO_VOLUME_PROVIDER* fs, void* fileCtx);
|
||||
KSTATUS FatQueryInfo(IO_VOLUME_PROVIDER* fs, void* fileCtx, SYS_FILE_STAT* out);
|
||||
KSTATUS FatStat(IO_VOLUME_PROVIDER* fs, SYS_STRING_VIEW path, SYS_FILE_STAT* out);
|
||||
KSTATUS FatQueryIdentity(IO_VOLUME_PROVIDER* fs, void* fileCtx, IO_FILE_IDENTITY* out);
|
||||
KSTATUS FatOpenDir(IO_VOLUME_PROVIDER* fs, SYS_STRING_VIEW dirPath, void** dirCtx);
|
||||
KSTATUS FatReadDir(IO_VOLUME_PROVIDER* fs, void* dirCtx, KDIR_ENTRY* out);
|
||||
void FatCloseDir(IO_VOLUME_PROVIDER* fs, void* dirCtx);
|
||||
void FatQueryStats(IO_VOLUME_PROVIDER* fs, IO_FILESYSTEM_STATS* out);
|
||||
|
||||
void FatInitVtable(IO_FILESYSTEM* fs, FAT_VOL* vol);
|
||||
void FatInitProvider(IO_VOLUME_PROVIDER* provider, FAT_VOL* vol);
|
||||
void FatVolumeDead(IO_VOLUME_PROVIDER* provider, IO_VOLUME_REMOVAL_REASON reason);
|
||||
void FatDestroyVolumeProvider(IO_VOLUME_PROVIDER* provider);
|
||||
@@ -63,39 +63,6 @@ typedef struct {
|
||||
uint16_t Name3[2];
|
||||
} LFN_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
uint32_t Data1;
|
||||
uint16_t Data2;
|
||||
uint16_t Data3;
|
||||
uint8_t Data4[8];
|
||||
} EFI_GUID;
|
||||
|
||||
typedef struct {
|
||||
char Signature[8];
|
||||
uint32_t Revision;
|
||||
uint32_t HeaderSize;
|
||||
uint32_t HeaderCRC32;
|
||||
uint32_t Reserved;
|
||||
uint64_t MyLBA;
|
||||
uint64_t AlternateLBA;
|
||||
uint64_t FirstUsableLBA;
|
||||
uint64_t LastUsableLBA;
|
||||
EFI_GUID DiskGUID;
|
||||
uint64_t PartitionEntryLBA;
|
||||
uint32_t NumberOfPartitionEntries;
|
||||
uint32_t SizeOfPartitionEntry;
|
||||
uint32_t PartitionEntryArrayCRC32;
|
||||
} GPT_HEADER;
|
||||
|
||||
typedef struct {
|
||||
EFI_GUID PartitionTypeGUID;
|
||||
EFI_GUID UniquePartitionGUID;
|
||||
uint64_t StartingLBA;
|
||||
uint64_t EndingLBA;
|
||||
uint64_t Attributes;
|
||||
uint16_t PartitionName[36];
|
||||
} GPT_ENTRY;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#define ATTR_VOLUME_ID 0x08
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "fat.h"
|
||||
|
||||
// Initializes vtable.
|
||||
void FatInitVtable(IO_FILESYSTEM* fs, FAT_VOL* vol) {
|
||||
// Initializes the FAT volume provider dispatch.
|
||||
void FatInitProvider(IO_VOLUME_PROVIDER* fs, FAT_VOL* vol) {
|
||||
memset(fs, 0, sizeof(*fs));
|
||||
fs->Open = FatOpen;
|
||||
fs->Read = FatRead;
|
||||
@@ -21,9 +21,11 @@ void FatInitVtable(IO_FILESYSTEM* fs, FAT_VOL* vol) {
|
||||
fs->QueryIdentity = FatQueryIdentity;
|
||||
fs->Flush = FatFlush;
|
||||
fs->Close = FatClose;
|
||||
fs->DriverCtx = vol;
|
||||
fs->Context = vol;
|
||||
fs->OpenDir = FatOpenDir;
|
||||
fs->ReadDir = FatReadDir;
|
||||
fs->CloseDir = FatCloseDir;
|
||||
fs->QueryStats = FatQueryStats;
|
||||
fs->VolumeDead = FatVolumeDead;
|
||||
fs->Destroy = FatDestroyVolumeProvider;
|
||||
}
|
||||
+195
-298
@@ -1,6 +1,6 @@
|
||||
// Native read-only NTFS filesystem driver for NTLite.
|
||||
// Portions are based on ntfs-efi by Mark Harmstone (2023), GPLv2-or-later.
|
||||
// The port removes UEFI protocol/header dependencies and targets NTLite's IO_FILESYSTEM ABI.
|
||||
// The port removes UEFI protocol/header dependencies and targets NTLite's IO_VOLUME_PROVIDER ABI.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
@@ -13,9 +13,8 @@
|
||||
#include <ntlite/ddk/debug.h>
|
||||
#include <ntlite/ddk/list.h>
|
||||
#include <ntlite/ddk/sync.h>
|
||||
#include <ntlite/ddk/mutex.h>
|
||||
|
||||
#define NTFS_MAX_VOLUMES 8u
|
||||
#define NTFS_MAX_PARTITIONS_PER_DISK 32u
|
||||
#define NTFS_SECTOR_SIZE 512u
|
||||
#define NTFS_FS_NAME "NTFS "
|
||||
#define NTFS_UPCASE_TABLE_CHARS 0x10000u
|
||||
@@ -203,48 +202,6 @@ typedef struct NTFS_FILE_NAME_ATTR {
|
||||
uint16_t FileName[1];
|
||||
} NTFS_FILE_NAME_ATTR;
|
||||
|
||||
typedef struct NTFS_GPT_GUID {
|
||||
uint32_t Data1;
|
||||
uint16_t Data2;
|
||||
uint16_t Data3;
|
||||
uint8_t Data4[8];
|
||||
} NTFS_GPT_GUID;
|
||||
|
||||
typedef struct NTFS_GPT_HEADER {
|
||||
char Signature[8];
|
||||
uint32_t Revision;
|
||||
uint32_t HeaderSize;
|
||||
uint32_t HeaderCRC32;
|
||||
uint32_t Reserved;
|
||||
uint64_t MyLBA;
|
||||
uint64_t AlternateLBA;
|
||||
uint64_t FirstUsableLBA;
|
||||
uint64_t LastUsableLBA;
|
||||
NTFS_GPT_GUID DiskGUID;
|
||||
uint64_t PartitionEntryLBA;
|
||||
uint32_t NumberOfPartitionEntries;
|
||||
uint32_t SizeOfPartitionEntry;
|
||||
uint32_t PartitionEntryArrayCRC32;
|
||||
} NTFS_GPT_HEADER;
|
||||
|
||||
typedef struct NTFS_GPT_ENTRY {
|
||||
NTFS_GPT_GUID PartitionTypeGUID;
|
||||
NTFS_GPT_GUID UniquePartitionGUID;
|
||||
uint64_t StartingLBA;
|
||||
uint64_t EndingLBA;
|
||||
uint64_t Attributes;
|
||||
uint16_t PartitionName[36];
|
||||
} NTFS_GPT_ENTRY;
|
||||
|
||||
typedef struct NTFS_MBR_PARTITION {
|
||||
uint8_t BootIndicator;
|
||||
uint8_t StartingChs[3];
|
||||
uint8_t OsType;
|
||||
uint8_t EndingChs[3];
|
||||
uint32_t StartingLba;
|
||||
uint32_t SizeInLba;
|
||||
} NTFS_MBR_PARTITION;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct NTFS_RUN {
|
||||
@@ -257,7 +214,6 @@ typedef struct NTFS_RUN {
|
||||
|
||||
typedef struct NTFS_VOLUME {
|
||||
uint8_t DriveIndex;
|
||||
uint8_t VolumeIndex;
|
||||
uint64_t PartitionLba;
|
||||
uint64_t PartitionSize;
|
||||
uint64_t SerialNumber;
|
||||
@@ -269,6 +225,8 @@ typedef struct NTFS_VOLUME {
|
||||
uint64_t FileRecordSize;
|
||||
LIST_ENTRY MftRuns;
|
||||
uint16_t* Upcase;
|
||||
IO_VOLUME* Volume; // Active mount-list reference.
|
||||
LIST_ENTRY MountLink;
|
||||
} NTFS_VOLUME;
|
||||
|
||||
typedef struct NTFS_FILE {
|
||||
@@ -306,11 +264,6 @@ typedef struct NTFS_DIR_CTX {
|
||||
uint32_t Position;
|
||||
} NTFS_DIR_CTX;
|
||||
|
||||
typedef struct NTFS_PARTITION_CANDIDATE {
|
||||
uint64_t StartLba;
|
||||
uint64_t SectorCount;
|
||||
} NTFS_PARTITION_CANDIDATE;
|
||||
|
||||
typedef struct NTFS_ATTR_VIEW {
|
||||
const NTFS_ATTRIBUTE_RECORD_HEADER* Attr;
|
||||
const uint8_t* ResidentData;
|
||||
@@ -332,13 +285,11 @@ typedef struct NTFS_COLLECT_CTX {
|
||||
bool HideNtfsMetadata;
|
||||
} NTFS_COLLECT_CTX;
|
||||
|
||||
static NTFS_VOLUME gVolumes[NTFS_MAX_VOLUMES];
|
||||
static IO_FILESYSTEM gFilesystems[NTFS_MAX_VOLUMES];
|
||||
static bool gVolumeMounted[NTFS_MAX_VOLUMES];
|
||||
static bool gVolumeBusy[NTFS_MAX_VOLUMES];
|
||||
static bool gDiskScanned[NTFS_MAX_VOLUMES];
|
||||
static SPINLOCK gNtfsMountLock = SPINLOCK_INIT;
|
||||
static LIST_ENTRY gNtfsMounts;
|
||||
static uint32_t gMountedCount;
|
||||
static MUTEX gNtfsMountMutex;
|
||||
static SPINLOCK gNtfsMountMutexInitLock = SPINLOCK_INIT;
|
||||
static int gNtfsMountMutexReady;
|
||||
|
||||
static uint64_t NtfsAlignUp(uint64_t value, uint64_t alignment) {
|
||||
if (alignment == 0) return value;
|
||||
@@ -937,7 +888,6 @@ static void NtfsFillStat(NTFS_FILE* file, SYS_FILE_STAT* out) {
|
||||
out->Attributes = NtfsSysAttrsFromNtfs(file->Attributes, file->IsDirectory);
|
||||
out->LinkCount = 1;
|
||||
out->FileSize = file->Size;
|
||||
out->VolumeId = file->Vol->SerialNumber;
|
||||
out->FileId = file->Inode;
|
||||
NtfsWinTimeToSystemTime(file->StandardInfo.CreationTime, &out->CreationTime);
|
||||
NtfsWinTimeToSystemTime(file->StandardInfo.LastAccessTime, &out->LastAccessTime);
|
||||
@@ -1139,9 +1089,9 @@ static bool NtfsCollectEntryCallback(const NTFS_FILE_NAME_ATTR* fn, uint64_t ino
|
||||
return true;
|
||||
}
|
||||
|
||||
static KSTATUS NtfsOpen(IO_FILESYSTEM* fs, SYS_STRING_VIEW path, void** fileCtx) {
|
||||
static KSTATUS NtfsOpen(IO_VOLUME_PROVIDER* fs, SYS_STRING_VIEW path, void** fileCtx) {
|
||||
if (!fs || !fileCtx || !SysSvIsValid(path)) return NTLSTATUS_INVALID_PARAMETER;
|
||||
NTFS_VOLUME* vol = (NTFS_VOLUME*)fs->DriverCtx;
|
||||
NTFS_VOLUME* vol = (NTFS_VOLUME*)fs->Context;
|
||||
if (!vol) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
uint64_t inode;
|
||||
@@ -1156,7 +1106,7 @@ static KSTATUS NtfsOpen(IO_FILESYSTEM* fs, SYS_STRING_VIEW path, void** fileCtx)
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void NtfsClose(IO_FILESYSTEM* fs, void* fileCtx) {
|
||||
static void NtfsClose(IO_VOLUME_PROVIDER* fs, void* fileCtx) {
|
||||
(void)fs;
|
||||
NTFS_FILE* file = (NTFS_FILE*)fileCtx;
|
||||
if (!file) return;
|
||||
@@ -1164,46 +1114,46 @@ static void NtfsClose(IO_FILESYSTEM* fs, void* fileCtx) {
|
||||
MmFreePool(file);
|
||||
}
|
||||
|
||||
static KSTATUS NtfsRead(IO_FILESYSTEM* fs, void* fileCtx, uint64_t offset, void* buf, size_t size, size_t* bytesRead) {
|
||||
static KSTATUS NtfsRead(IO_VOLUME_PROVIDER* fs, void* fileCtx, uint64_t offset, void* buf, size_t size, size_t* bytesRead) {
|
||||
(void)fs;
|
||||
return NtfsReadFileData((NTFS_FILE*)fileCtx, offset, buf, size, bytesRead);
|
||||
}
|
||||
|
||||
static KSTATUS NtfsWrite(IO_FILESYSTEM* fs, void* fileCtx, uint64_t offset, const void* buf, size_t size, size_t* bytesWritten) {
|
||||
static KSTATUS NtfsWrite(IO_VOLUME_PROVIDER* fs, void* fileCtx, uint64_t offset, const void* buf, size_t size, size_t* bytesWritten) {
|
||||
(void)fs; (void)fileCtx; (void)offset; (void)buf; (void)size;
|
||||
if (bytesWritten) *bytesWritten = 0;
|
||||
return NTLSTATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static KSTATUS NtfsCreate(IO_FILESYSTEM* fs, SYS_STRING_VIEW path, void** fileCtx) {
|
||||
static KSTATUS NtfsCreate(IO_VOLUME_PROVIDER* fs, SYS_STRING_VIEW path, void** fileCtx) {
|
||||
(void)fs; (void)path; (void)fileCtx;
|
||||
return NTLSTATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static KSTATUS NtfsDelete(IO_FILESYSTEM* fs, SYS_STRING_VIEW path) {
|
||||
static KSTATUS NtfsDelete(IO_VOLUME_PROVIDER* fs, SYS_STRING_VIEW path) {
|
||||
(void)fs; (void)path;
|
||||
return NTLSTATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static KSTATUS NtfsTruncate(IO_FILESYSTEM* fs, void* fileCtx, uint64_t newSize, uint32_t fileFlags) {
|
||||
static KSTATUS NtfsTruncate(IO_VOLUME_PROVIDER* fs, void* fileCtx, uint64_t newSize, uint32_t fileFlags) {
|
||||
(void)fs; (void)fileCtx; (void)newSize; (void)fileFlags;
|
||||
return NTLSTATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static uint64_t NtfsGetSize(IO_FILESYSTEM* fs, void* fileCtx) {
|
||||
static uint64_t NtfsGetSize(IO_VOLUME_PROVIDER* fs, void* fileCtx) {
|
||||
(void)fs;
|
||||
NTFS_FILE* file = (NTFS_FILE*)fileCtx;
|
||||
return file ? file->Size : 0;
|
||||
}
|
||||
|
||||
static KSTATUS NtfsQueryInfo(IO_FILESYSTEM* fs, void* fileCtx, SYS_FILE_STAT* out) {
|
||||
static KSTATUS NtfsQueryInfo(IO_VOLUME_PROVIDER* fs, void* fileCtx, SYS_FILE_STAT* out) {
|
||||
(void)fs;
|
||||
if (!fileCtx || !out) return NTLSTATUS_INVALID_PARAMETER;
|
||||
NtfsFillStat((NTFS_FILE*)fileCtx, out);
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static KSTATUS NtfsStat(IO_FILESYSTEM* fs, SYS_STRING_VIEW path, SYS_FILE_STAT* out) {
|
||||
static KSTATUS NtfsStat(IO_VOLUME_PROVIDER* fs, SYS_STRING_VIEW path, SYS_FILE_STAT* out) {
|
||||
if (!fs || !out || !SysSvIsValid(path)) return NTLSTATUS_INVALID_PARAMETER;
|
||||
void* ctx = NULL;
|
||||
KSTATUS s = NtfsOpen(fs, path, &ctx);
|
||||
@@ -1213,27 +1163,27 @@ static KSTATUS NtfsStat(IO_FILESYSTEM* fs, SYS_STRING_VIEW path, SYS_FILE_STAT*
|
||||
return s;
|
||||
}
|
||||
|
||||
static KSTATUS NtfsQueryIdentity(IO_FILESYSTEM* fs, void* fileCtx, IO_FILE_IDENTITY* out) {
|
||||
static KSTATUS NtfsQueryIdentity(IO_VOLUME_PROVIDER* fs, void* fileCtx, IO_FILE_IDENTITY* out) {
|
||||
(void)fs;
|
||||
if (!fileCtx || !out) return NTLSTATUS_INVALID_PARAMETER;
|
||||
NTFS_FILE* file = (NTFS_FILE*)fileCtx;
|
||||
out->VolumeId = file->Vol->SerialNumber;
|
||||
out->FileId = file->Inode;
|
||||
out->Generation = (uint64_t)file->StandardInfo.LastWriteTime ^ ((uint64_t)file->StandardInfo.ChangeTime << 1u);
|
||||
out->Size = file->Size;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static KSTATUS NtfsOpenDir(IO_FILESYSTEM* fs, SYS_STRING_VIEW dirPath, void** dirCtx) {
|
||||
static KSTATUS NtfsOpenDir(IO_VOLUME_PROVIDER* fs, SYS_STRING_VIEW dirPath, void** dirCtx) {
|
||||
if (!fs || !dirCtx || !SysSvIsValid(dirPath)) return NTLSTATUS_INVALID_PARAMETER;
|
||||
NTFS_VOLUME* vol = (NTFS_VOLUME*)fs->DriverCtx;
|
||||
NTFS_VOLUME* vol = (NTFS_VOLUME*)fs->Context;
|
||||
if (!vol) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
uint64_t inode;
|
||||
KSTATUS s = NtfsLookupPath(vol, dirPath, &inode);
|
||||
if (!KSUCCESS(s)) {
|
||||
NtfsTrace("NTFS: opendir: lookup failed drive=%u pathLen=%llu st=0x%x\n",
|
||||
vol->VolumeIndex, (unsigned long long)dirPath.Length, s);
|
||||
NtfsTrace("NTFS: opendir: lookup failed disk=%u lba=%llu pathLen=%llu st=0x%x\n",
|
||||
vol->DriveIndex, (unsigned long long)vol->PartitionLba,
|
||||
(unsigned long long)dirPath.Length, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -1295,7 +1245,7 @@ static KSTATUS NtfsOpenDir(IO_FILESYSTEM* fs, SYS_STRING_VIEW dirPath, void** di
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static KSTATUS NtfsReadDir(IO_FILESYSTEM* fs, void* dirCtx, KDIR_ENTRY* out) {
|
||||
static KSTATUS NtfsReadDir(IO_VOLUME_PROVIDER* fs, void* dirCtx, KDIR_ENTRY* out) {
|
||||
(void)fs;
|
||||
if (!dirCtx || !out) return NTLSTATUS_INVALID_PARAMETER;
|
||||
NTFS_DIR_CTX* ctx = (NTFS_DIR_CTX*)dirCtx;
|
||||
@@ -1311,7 +1261,7 @@ static KSTATUS NtfsReadDir(IO_FILESYSTEM* fs, void* dirCtx, KDIR_ENTRY* out) {
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void NtfsCloseDir(IO_FILESYSTEM* fs, void* dirCtx) {
|
||||
static void NtfsCloseDir(IO_VOLUME_PROVIDER* fs, void* dirCtx) {
|
||||
(void)fs;
|
||||
NTFS_DIR_CTX* ctx = (NTFS_DIR_CTX*)dirCtx;
|
||||
if (!ctx) return;
|
||||
@@ -1319,12 +1269,15 @@ static void NtfsCloseDir(IO_FILESYSTEM* fs, void* dirCtx) {
|
||||
MmFreePool(ctx);
|
||||
}
|
||||
|
||||
static void NtfsQueryStats(IO_FILESYSTEM* fs, IO_FILESYSTEM_STATS* out) {
|
||||
static void NtfsQueryStats(IO_VOLUME_PROVIDER* fs, IO_FILESYSTEM_STATS* out) {
|
||||
(void)fs;
|
||||
if (out) memset(out, 0, sizeof(*out));
|
||||
}
|
||||
|
||||
static void NtfsInitVtable(IO_FILESYSTEM* fs, NTFS_VOLUME* vol) {
|
||||
static void NtfsVolumeDead(IO_VOLUME_PROVIDER* provider, IO_VOLUME_REMOVAL_REASON reason);
|
||||
static void NtfsDestroyVolumeProvider(IO_VOLUME_PROVIDER* provider);
|
||||
|
||||
static void NtfsInitProvider(IO_VOLUME_PROVIDER* fs, NTFS_VOLUME* vol) {
|
||||
memset(fs, 0, sizeof(*fs));
|
||||
fs->Open = NtfsOpen;
|
||||
fs->Read = NtfsRead;
|
||||
@@ -1338,15 +1291,12 @@ static void NtfsInitVtable(IO_FILESYSTEM* fs, NTFS_VOLUME* vol) {
|
||||
fs->QueryIdentity = NtfsQueryIdentity;
|
||||
fs->Close = NtfsClose;
|
||||
fs->QueryStats = NtfsQueryStats;
|
||||
fs->DriverCtx = vol;
|
||||
fs->Context = vol;
|
||||
fs->OpenDir = NtfsOpenDir;
|
||||
fs->ReadDir = NtfsReadDir;
|
||||
fs->CloseDir = NtfsCloseDir;
|
||||
}
|
||||
|
||||
static bool NtfsGuidIsZero(const NTFS_GPT_GUID* guid) {
|
||||
static const NTFS_GPT_GUID zeroGuid = {0};
|
||||
return memcmp(guid, &zeroGuid, sizeof(*guid)) == 0;
|
||||
fs->VolumeDead = NtfsVolumeDead;
|
||||
fs->Destroy = NtfsDestroyVolumeProvider;
|
||||
}
|
||||
|
||||
static bool NtfsIsValidBootSector(const NTFS_BOOT_SECTOR* bs) {
|
||||
@@ -1425,6 +1375,22 @@ static void NtfsCleanupVolume(NTFS_VOLUME* vol) {
|
||||
}
|
||||
}
|
||||
|
||||
// Provider death blocks new I/O in the I/O core; NTFS state is retained for safe close teardown.
|
||||
static void NtfsVolumeDead(IO_VOLUME_PROVIDER* provider, IO_VOLUME_REMOVAL_REASON reason) {
|
||||
(void)provider;
|
||||
(void)reason;
|
||||
}
|
||||
|
||||
// Releases one dynamically allocated NTFS mount after every volume reference has drained.
|
||||
static void NtfsDestroyVolumeProvider(IO_VOLUME_PROVIDER* provider) {
|
||||
if (!provider || !provider->Context)
|
||||
return;
|
||||
NTFS_VOLUME* volume = (NTFS_VOLUME*)provider->Context;
|
||||
NtfsCleanupVolume(volume);
|
||||
memset(volume, 0, sizeof(*volume));
|
||||
MmFreePool(volume);
|
||||
}
|
||||
|
||||
static void NtfsTryLoadUpcase(NTFS_VOLUME* vol) {
|
||||
NTFS_FILE upcase;
|
||||
if (!KSUCCESS(NtfsLoadFile(vol, NTFS_UPCASE_INODE, &upcase))) return;
|
||||
@@ -1443,6 +1409,7 @@ static KSTATUS NtfsProbeAndPrepareVolume(NTFS_VOLUME* vol, uint8_t disk, uint64_
|
||||
vol->PartitionSize = sectors;
|
||||
vol->BytesPerSector = NTFS_SECTOR_SIZE;
|
||||
NtfsInitRunList(&vol->MftRuns);
|
||||
LIST_INIT(&vol->MountLink);
|
||||
|
||||
uint8_t sector[NTFS_SECTOR_SIZE];
|
||||
memset(sector, 0, sizeof(sector));
|
||||
@@ -1472,252 +1439,182 @@ static KSTATUS NtfsProbeAndPrepareVolume(NTFS_VOLUME* vol, uint8_t disk, uint64_
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t NtfsEnumerateDiskPartitions(uint8_t disk, NTFS_PARTITION_CANDIDATE* parts, uint32_t maxParts, bool* mediaReadable) {
|
||||
if (mediaReadable) *mediaReadable = false;
|
||||
if (!parts || maxParts == 0) return 0;
|
||||
uint8_t sector[NTFS_SECTOR_SIZE];
|
||||
NTFS_VOLUME raw;
|
||||
memset(&raw, 0, sizeof(raw));
|
||||
raw.DriveIndex = disk;
|
||||
raw.PartitionLba = 0;
|
||||
raw.PartitionSize = IoDiskSectorCount(disk);
|
||||
raw.BytesPerSector = NTFS_SECTOR_SIZE;
|
||||
NtfsInitRunList(&raw.MftRuns);
|
||||
// Initializes the dynamic NTFS mount-list mutex without allocating kernel objects.
|
||||
static void NtfsMountEnsureMutex(void) {
|
||||
if (gNtfsMountMutexReady)
|
||||
return;
|
||||
|
||||
if (!KSUCCESS(NtfsReadSectors(&raw, 0, 1, sector))) return 0;
|
||||
if (mediaReadable) *mediaReadable = true;
|
||||
|
||||
uint32_t count = 0;
|
||||
NTFS_BOOT_SECTOR* vbr = (NTFS_BOOT_SECTOR*)sector;
|
||||
if (NtfsIsValidBootSector(vbr)) {
|
||||
parts[count].StartLba = 0;
|
||||
parts[count].SectorCount = vbr->TotalSectors;
|
||||
count++;
|
||||
if (count >= maxParts) return count;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNtfsMountMutexInitLock);
|
||||
if (!gNtfsMountMutexReady) {
|
||||
memset(&gNtfsMountMutex, 0, sizeof(gNtfsMountMutex));
|
||||
ObInitializeObjectHeader(&gNtfsMountMutex.Header, ObjectTypeMutex);
|
||||
gNtfsMountMutex.Lock = (SPINLOCK)SPINLOCK_INIT;
|
||||
gNtfsMountMutex.Owner = (THREAD*)0;
|
||||
LIST_INIT(&gNtfsMountMutex.WaitList);
|
||||
LIST_INIT(&gNtfsMountMutex.OwnerLink);
|
||||
gNtfsMountMutex.DonationClass = KeSchedulingNormal;
|
||||
gNtfsMountMutex.DonationPriority = PriorityLow;
|
||||
gNtfsMountMutex.HasDonation = 0;
|
||||
gNtfsMountMutex.Abandoned = 0;
|
||||
gNtfsMountMutexReady = 1;
|
||||
}
|
||||
|
||||
if (sector[510] != 0x55u || sector[511] != 0xaau) return count;
|
||||
|
||||
NTFS_MBR_PARTITION* mbr = (NTFS_MBR_PARTITION*)(sector + 446u);
|
||||
bool protectiveMbr = false;
|
||||
for (uint32_t i = 0; i < 4u; i++) if (mbr[i].OsType == 0xeeu) protectiveMbr = true;
|
||||
|
||||
if (protectiveMbr) {
|
||||
uint8_t gptSector[NTFS_SECTOR_SIZE];
|
||||
if (!KSUCCESS(NtfsReadSectors(&raw, 1, 1, gptSector))) return count;
|
||||
NTFS_GPT_HEADER* hdr = (NTFS_GPT_HEADER*)gptSector;
|
||||
if (memcmp(hdr->Signature, "EFI PART", 8) != 0 || hdr->SizeOfPartitionEntry < sizeof(NTFS_GPT_ENTRY)) return count;
|
||||
uint32_t entries = hdr->NumberOfPartitionEntries;
|
||||
if (entries > 256u) entries = 256u;
|
||||
uint32_t entrySize = hdr->SizeOfPartitionEntry;
|
||||
uint8_t entrySector[NTFS_SECTOR_SIZE];
|
||||
for (uint32_t i = 0; i < entries && count < maxParts; i++) {
|
||||
uint64_t byteOff = (uint64_t)i * entrySize;
|
||||
uint64_t lba = hdr->PartitionEntryLBA + byteOff / NTFS_SECTOR_SIZE;
|
||||
uint32_t inSector = (uint32_t)(byteOff % NTFS_SECTOR_SIZE);
|
||||
if (inSector + sizeof(NTFS_GPT_ENTRY) > NTFS_SECTOR_SIZE) continue;
|
||||
if (!KSUCCESS(NtfsReadSectors(&raw, lba, 1, entrySector))) break;
|
||||
NTFS_GPT_ENTRY* e = (NTFS_GPT_ENTRY*)(entrySector + inSector);
|
||||
if (NtfsGuidIsZero(&e->PartitionTypeGUID)) continue;
|
||||
if (e->EndingLBA < e->StartingLBA) continue;
|
||||
parts[count].StartLba = e->StartingLBA;
|
||||
parts[count].SectorCount = e->EndingLBA - e->StartingLBA + 1ull;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 4u && count < maxParts; i++) {
|
||||
if (mbr[i].OsType == 0 || mbr[i].SizeInLba == 0) continue;
|
||||
parts[count].StartLba = mbr[i].StartingLba;
|
||||
parts[count].SectorCount = mbr[i].SizeInLba;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
KeReleaseSpinlock(&gNtfsMountMutexInitLock, flags);
|
||||
}
|
||||
|
||||
static int NtfsReserveFreeVolumeIndex(void) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNtfsMountLock);
|
||||
for (uint8_t i = 0; i < NTFS_MAX_VOLUMES; i++) {
|
||||
if (!gVolumeMounted[i] && !gVolumeBusy[i] && !IoFilesystemPresent(i)) {
|
||||
gVolumeBusy[i] = true;
|
||||
KeReleaseSpinlock(&gNtfsMountLock, flags);
|
||||
return (int)i;
|
||||
// Returns one active NTFS mount for an exact partition extent while the mount mutex is held.
|
||||
static NTFS_VOLUME* NtfsFindMountLocked(const IO_PARTITION_INFO* partition) {
|
||||
if (!partition)
|
||||
return (NTFS_VOLUME*)0;
|
||||
for (LIST_ENTRY* entry = gNtfsMounts.Fwd; entry != &gNtfsMounts; entry = entry->Fwd) {
|
||||
NTFS_VOLUME* volume = CONTAINING_RECORD(entry, NTFS_VOLUME, MountLink);
|
||||
if (volume->DriveIndex == partition->DiskIndex &&
|
||||
volume->PartitionLba == partition->StartLba) {
|
||||
return volume;
|
||||
}
|
||||
}
|
||||
KeReleaseSpinlock(&gNtfsMountLock, flags);
|
||||
return -1;
|
||||
return (NTFS_VOLUME*)0;
|
||||
}
|
||||
|
||||
static void NtfsReleaseReservedVolumeIndex(uint8_t volumeIndex) {
|
||||
if (volumeIndex >= NTFS_MAX_VOLUMES) return;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNtfsMountLock);
|
||||
gVolumeBusy[volumeIndex] = false;
|
||||
KeReleaseSpinlock(&gNtfsMountLock, flags);
|
||||
}
|
||||
// Probes one I/O-core partition extent and mounts it only when its VBR is valid NTFS.
|
||||
static bool NtfsTryMountPartition(const IO_PARTITION_INFO* partition) {
|
||||
if (!partition || partition->SectorCount == 0 || !IoDiskDevicePresent(partition->DiskIndex))
|
||||
return false;
|
||||
|
||||
static bool NtfsBeginDiskScan(uint8_t disk) {
|
||||
if (disk >= NTFS_MAX_VOLUMES) return false;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNtfsMountLock);
|
||||
if (gDiskScanned[disk]) {
|
||||
KeReleaseSpinlock(&gNtfsMountLock, flags);
|
||||
NtfsMountEnsureMutex();
|
||||
if (!KE_MUTEX_ACQUIRE_SUCCEEDED(KeAcquireMutex(&gNtfsMountMutex, KE_WAIT_INFINITE)))
|
||||
return false;
|
||||
|
||||
if (NtfsFindMountLocked(partition)) {
|
||||
KeReleaseMutex(&gNtfsMountMutex);
|
||||
return false;
|
||||
}
|
||||
gDiskScanned[disk] = true;
|
||||
KeReleaseSpinlock(&gNtfsMountLock, flags);
|
||||
|
||||
NTFS_VOLUME* mount = (NTFS_VOLUME*)MmAllocatePool(sizeof(NTFS_VOLUME));
|
||||
if (!mount) {
|
||||
KeReleaseMutex(&gNtfsMountMutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
KSTATUS status = NtfsProbeAndPrepareVolume(mount,
|
||||
partition->DiskIndex,
|
||||
partition->StartLba,
|
||||
partition->SectorCount);
|
||||
if (!KSUCCESS(status)) {
|
||||
NtfsCleanupVolume(mount);
|
||||
MmFreePool(mount);
|
||||
KeReleaseMutex(&gNtfsMountMutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
IO_VOLUME_PROVIDER provider;
|
||||
NtfsInitProvider(&provider, mount);
|
||||
IO_VOLUME_SOURCE params;
|
||||
params.Type = IoVolumeSourcePartition;
|
||||
params.DiskIndex = partition->DiskIndex;
|
||||
memset(params.Reserved, 0, sizeof(params.Reserved));
|
||||
params.StartLba = partition->StartLba;
|
||||
params.SectorCount = mount->PartitionSize;
|
||||
|
||||
IO_VOLUME* volume = (IO_VOLUME*)0;
|
||||
status = IoCreateVolume(&provider, ¶ms, &volume);
|
||||
if (!KSUCCESS(status)) {
|
||||
if (volume) {
|
||||
(void)IoRemoveVolume(volume, IoVolumeUnmounted);
|
||||
IoReleaseVolume(volume);
|
||||
} else {
|
||||
NtfsCleanupVolume(mount);
|
||||
MmFreePool(mount);
|
||||
}
|
||||
DbgPrint("NTFS: disk=%u lba=%llu mount failed status=0x%x\n",
|
||||
partition->DiskIndex, (unsigned long long)partition->StartLba, status);
|
||||
KeReleaseMutex(&gNtfsMountMutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Retain the IoCreateVolume caller reference while this provider remains on the active mount list.
|
||||
mount->Volume = volume;
|
||||
ListInsertTail(&gNtfsMounts, &mount->MountLink);
|
||||
gMountedCount++;
|
||||
uint32_t mountedCount = gMountedCount;
|
||||
uint32_t instanceId = IoGetVolumeInstanceId(volume);
|
||||
uint64_t recordSize = mount->FileRecordSize;
|
||||
|
||||
DbgPrint("NTFS: disk=%u lba=%llu mounted volume=%u (mft_record=%llu); total=%u\n",
|
||||
partition->DiskIndex, (unsigned long long)partition->StartLba,
|
||||
instanceId, (unsigned long long)recordSize, mountedCount);
|
||||
KeReleaseMutex(&gNtfsMountMutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void NtfsEndDiskScan(uint8_t disk, bool completed) {
|
||||
if (disk >= NTFS_MAX_VOLUMES) return;
|
||||
if (completed) return;
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNtfsMountLock);
|
||||
gDiskScanned[disk] = false;
|
||||
KeReleaseSpinlock(&gNtfsMountLock, flags);
|
||||
// Unmounts one exact dynamic NTFS provider instance when its backing partition disappears.
|
||||
static void NtfsUnmountPartition(const IO_PARTITION_INFO* partition, IO_PARTITION_CHANGE change) {
|
||||
if (!partition)
|
||||
return;
|
||||
|
||||
NtfsMountEnsureMutex();
|
||||
if (!KE_MUTEX_ACQUIRE_SUCCEEDED(KeAcquireMutex(&gNtfsMountMutex, KE_WAIT_INFINITE)))
|
||||
return;
|
||||
|
||||
NTFS_VOLUME* mount = NtfsFindMountLocked(partition);
|
||||
if (!mount) {
|
||||
KeReleaseMutex(&gNtfsMountMutex);
|
||||
return;
|
||||
}
|
||||
|
||||
IO_VOLUME* volume = mount->Volume;
|
||||
uint32_t instanceId = IoGetVolumeInstanceId(volume);
|
||||
ListRemove(&mount->MountLink);
|
||||
mount->Volume = (IO_VOLUME*)0;
|
||||
if (gMountedCount)
|
||||
gMountedCount--;
|
||||
uint32_t mountedCount = gMountedCount;
|
||||
KeReleaseMutex(&gNtfsMountMutex);
|
||||
|
||||
(void)IoRemoveVolume(volume, IoVolumeBackingRemoved);
|
||||
IoReleaseVolume(volume); // Drop the active mount-list reference.
|
||||
DbgPrint("NTFS: disk=%u lba=%llu %s; unmounted volume=%u; total=%u\n",
|
||||
partition->DiskIndex, (unsigned long long)partition->StartLba,
|
||||
change == IoPartitionSurpriseRemoved ? "surprise removed" : "removed",
|
||||
instanceId, mountedCount);
|
||||
}
|
||||
|
||||
static uint32_t NtfsTryMountDisk(uint8_t disk) {
|
||||
if (disk >= NTFS_MAX_VOLUMES) return 0;
|
||||
if (!IoDiskDevicePresent(disk)) return 0;
|
||||
if (!NtfsBeginDiskScan(disk)) return 0;
|
||||
|
||||
bool scanCompleted = false;
|
||||
bool mediaReadable = false;
|
||||
NTFS_PARTITION_CANDIDATE parts[NTFS_MAX_PARTITIONS_PER_DISK];
|
||||
uint32_t partCount = NtfsEnumerateDiskPartitions(disk, parts, NTFS_MAX_PARTITIONS_PER_DISK, &mediaReadable);
|
||||
if (!mediaReadable) {
|
||||
DbgPrint("NTFS: disk %u: media probe deferred; sector 0 unreadable\n", disk);
|
||||
NtfsEndDiskScan(disk, false);
|
||||
return 0;
|
||||
}
|
||||
scanCompleted = true;
|
||||
|
||||
uint32_t mounted = 0;
|
||||
for (uint32_t p = 0; p < partCount; p++) {
|
||||
int freeVolume = NtfsReserveFreeVolumeIndex();
|
||||
if (freeVolume < 0) break;
|
||||
uint8_t volumeIndex = (uint8_t)freeVolume;
|
||||
KSTATUS s = NtfsProbeAndPrepareVolume(&gVolumes[volumeIndex], disk, parts[p].StartLba, parts[p].SectorCount);
|
||||
if (!KSUCCESS(s)) {
|
||||
NtfsCleanupVolume(&gVolumes[volumeIndex]);
|
||||
memset(&gVolumes[volumeIndex], 0, sizeof(gVolumes[volumeIndex]));
|
||||
NtfsReleaseReservedVolumeIndex(volumeIndex);
|
||||
continue;
|
||||
}
|
||||
gVolumes[volumeIndex].VolumeIndex = volumeIndex;
|
||||
|
||||
NtfsInitVtable(&gFilesystems[volumeIndex], &gVolumes[volumeIndex]);
|
||||
IO_VOLUME_PARAMS params;
|
||||
params.DiskIndex = disk;
|
||||
params.PartitionLba = parts[p].StartLba;
|
||||
params.PartitionSize = gVolumes[volumeIndex].PartitionSize;
|
||||
s = IoRegisterFilesystem(volumeIndex, &gFilesystems[volumeIndex], ¶ms);
|
||||
if (KSUCCESS(s)) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNtfsMountLock);
|
||||
gVolumeMounted[volumeIndex] = true;
|
||||
gVolumeBusy[volumeIndex] = false;
|
||||
gMountedCount++;
|
||||
KeReleaseSpinlock(&gNtfsMountLock, flags);
|
||||
mounted++;
|
||||
DbgPrint("NTFS: disk %u part %u mounted as drive %u (lba=%llu mft_record=%llu).\n",
|
||||
disk, p, volumeIndex,
|
||||
(unsigned long long)parts[p].StartLba,
|
||||
(unsigned long long)gVolumes[volumeIndex].FileRecordSize);
|
||||
} else {
|
||||
NtfsCleanupVolume(&gVolumes[volumeIndex]);
|
||||
memset(&gVolumes[volumeIndex], 0, sizeof(gVolumes[volumeIndex]));
|
||||
memset(&gFilesystems[volumeIndex], 0, sizeof(gFilesystems[volumeIndex]));
|
||||
NtfsReleaseReservedVolumeIndex(volumeIndex);
|
||||
DbgPrint("NTFS: disk %u part %u mount failed status=0x%x.\n", disk, p, s);
|
||||
}
|
||||
}
|
||||
NtfsEndDiskScan(disk, scanCompleted);
|
||||
if (partCount && !mounted && gMountedCount >= NTFS_MAX_VOLUMES)
|
||||
DbgPrint("NTFS: disk %u: volume table full\n", disk);
|
||||
return mounted;
|
||||
}
|
||||
|
||||
static void NtfsUnmountDisk(uint8_t diskIndex, IO_DEVICE_CHANGE change) {
|
||||
uint32_t removed = 0;
|
||||
for (uint8_t i = 0; i < NTFS_MAX_VOLUMES; i++) {
|
||||
if (!gVolumeMounted[i] || gVolumes[i].DriveIndex != diskIndex) continue;
|
||||
(void)IoUnregisterFilesystem(i);
|
||||
NtfsCleanupVolume(&gVolumes[i]);
|
||||
memset(&gVolumes[i], 0, sizeof(gVolumes[i]));
|
||||
memset(&gFilesystems[i], 0, sizeof(gFilesystems[i]));
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNtfsMountLock);
|
||||
gVolumeMounted[i] = false;
|
||||
gVolumeBusy[i] = false;
|
||||
if (gMountedCount) gMountedCount--;
|
||||
KeReleaseSpinlock(&gNtfsMountLock, flags);
|
||||
removed++;
|
||||
}
|
||||
if (diskIndex < NTFS_MAX_VOLUMES) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNtfsMountLock);
|
||||
gDiskScanned[diskIndex] = false;
|
||||
KeReleaseSpinlock(&gNtfsMountLock, flags);
|
||||
}
|
||||
if (removed) {
|
||||
DbgPrint("NTFS: disk %u %s; unmounted %u volume(s); total=%u\n",
|
||||
diskIndex,
|
||||
change == IoDeviceSurpriseRemoved ? "surprise removed" : "removed",
|
||||
removed,
|
||||
gMountedCount);
|
||||
}
|
||||
}
|
||||
|
||||
static void NtfsDiskArrival(uint8_t driveIndex, DEVICE_OBJECT* device, void* context) {
|
||||
(void)device;
|
||||
(void)context;
|
||||
uint32_t mounted = NtfsTryMountDisk(driveIndex);
|
||||
if (mounted) DbgPrint("NTFS: hotplug scan mounted %u new volume(s); total=%u\n", mounted, gMountedCount);
|
||||
}
|
||||
|
||||
static void NtfsDiskChange(uint8_t driveIndex, DEVICE_OBJECT* device, IO_DEVICE_CHANGE change, void* context) {
|
||||
(void)device;
|
||||
// Receives immutable partition extents from the I/O core; NTFS never parses partition tables.
|
||||
static void NtfsPartitionChange(const IO_PARTITION_INFO* partition,
|
||||
IO_PARTITION_CHANGE change,
|
||||
void* context) {
|
||||
(void)context;
|
||||
switch (change) {
|
||||
case IoDeviceArrived:
|
||||
NtfsDiskArrival(driveIndex, device, context);
|
||||
case IoPartitionArrived:
|
||||
(void)NtfsTryMountPartition(partition);
|
||||
break;
|
||||
case IoDeviceSurpriseRemoved:
|
||||
case IoDeviceRemoved:
|
||||
NtfsUnmountDisk(driveIndex, change);
|
||||
case IoPartitionSurpriseRemoved:
|
||||
case IoPartitionRemoved:
|
||||
NtfsUnmountPartition(partition, change);
|
||||
break;
|
||||
case IoDeviceQueryRemove:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Initializes NTFS and subscribes to the authoritative kernel partition stream.
|
||||
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
|
||||
DbgPrint("NTFS: Init\n");
|
||||
if (!ddk) return NTLSTATUS_INVALID_PARAMETER;
|
||||
if (!ddk)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
(void)init;
|
||||
memset(gVolumes, 0, sizeof(gVolumes));
|
||||
memset(gFilesystems, 0, sizeof(gFilesystems));
|
||||
memset(gVolumeMounted, 0, sizeof(gVolumeMounted));
|
||||
memset(gVolumeBusy, 0, sizeof(gVolumeBusy));
|
||||
memset(gDiskScanned, 0, sizeof(gDiskScanned));
|
||||
|
||||
LIST_INIT(&gNtfsMounts);
|
||||
gMountedCount = 0;
|
||||
NtfsMountEnsureMutex();
|
||||
|
||||
KSTATUS cbStatus = IoRegisterDiskChangeCallback(NtfsDiskChange, (void*)0);
|
||||
bool callbackRegistered = KSUCCESS(cbStatus);
|
||||
if (!callbackRegistered)
|
||||
DbgPrint("NTFS: disk-change callback registration failed st=0x%x\n", cbStatus);
|
||||
|
||||
KSTATUS enumStatus = IoEnumerateDiskDevices(NtfsDiskArrival, (void*)0);
|
||||
if (!KSUCCESS(enumStatus))
|
||||
DbgPrint("NTFS: initial disk enumeration failed st=0x%x\n", enumStatus);
|
||||
|
||||
if (!gMountedCount && !callbackRegistered) {
|
||||
DbgPrint("NTFS: no mountable NTFS volumes found and disk-change callback unavailable.\n");
|
||||
return cbStatus;
|
||||
KSTATUS status = IoRegisterPartitionChangeCallback(NtfsPartitionChange, NULL);
|
||||
if (!KSUCCESS(status)) {
|
||||
DbgPrint("NTFS: partition callback registration failed status=0x%x\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!gMountedCount)
|
||||
DbgPrint("NTFS: no mountable NTFS volumes found; driver resident for disk changes.\n");
|
||||
|
||||
DbgPrint("NTFS: no mountable NTFS partitions found; driver resident for partition changes.\n");
|
||||
DbgPrint("NTFS: Init complete; mounted %u volume(s).\n", gMountedCount);
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
Reference in new issue
Block a user