/** * @file dll/dispatch.c * * @copyright 2015 Bill Zissimopoulos */ #include enum { FspFileSystemDispatcherThreadCountMin = 2, }; static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface; FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath, const FSP_FSCTL_VOLUME_PARAMS *VolumeParams, const FSP_FILE_SYSTEM_INTERFACE *Interface, FSP_FILE_SYSTEM **PFileSystem) { NTSTATUS Result; FSP_FILE_SYSTEM *FileSystem; *PFileSystem = 0; if (0 == Interface) Interface = &FspFileSystemNullInterface; FileSystem = MemAlloc(sizeof *FileSystem); if (0 == FileSystem) return STATUS_INSUFFICIENT_RESOURCES; memset(FileSystem, 0, sizeof *FileSystem); Result = FspFsctlCreateVolume(DevicePath, VolumeParams, FileSystem->VolumeName, sizeof FileSystem->VolumeName, &FileSystem->VolumeHandle); if (!NT_SUCCESS(Result)) { MemFree(FileSystem); return Result; } FileSystem->Operations[FspFsctlTransactCreateKind] = FspFileSystemOpCreate; FileSystem->Operations[FspFsctlTransactOverwriteKind] = FspFileSystemOpOverwrite; FileSystem->Operations[FspFsctlTransactCleanupKind] = FspFileSystemOpCleanup; FileSystem->Operations[FspFsctlTransactCloseKind] = FspFileSystemOpClose; FileSystem->Operations[FspFsctlTransactQueryInformationKind] = FspFileSystemOpQueryInformation; FileSystem->Operations[FspFsctlTransactSetInformationKind] = FspFileSystemOpSetInformation; FileSystem->Operations[FspFsctlTransactQueryVolumeInformationKind] = FspFileSystemOpQueryVolumeInformation; FileSystem->Operations[FspFsctlTransactSetVolumeInformationKind] = FspFileSystemOpSetVolumeInformation; // !!!: ... FileSystem->Interface = Interface; *PFileSystem = FileSystem; return STATUS_SUCCESS; } FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem) { CloseHandle(FileSystem->VolumeHandle); MemFree(FileSystem); } static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0) { FSP_FILE_SYSTEM *FileSystem = FileSystem0; NTSTATUS Result; SIZE_T RequestSize; FSP_FSCTL_TRANSACT_REQ *Request = 0; FSP_FSCTL_TRANSACT_RSP *Response = 0; HANDLE DispatcherThread = 0; Request = MemAlloc(FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN); Response = MemAlloc(FSP_FSCTL_TRANSACT_RSP_SIZEMAX); if (0 == Request || 0 == Response) { Result = STATUS_INSUFFICIENT_RESOURCES; goto exit; } if (1 < FileSystem->DispatcherThreadCount) { FileSystem->DispatcherThreadCount--; DispatcherThread = CreateThread(0, 0, FspFileSystemDispatcherThread, FileSystem, 0, 0); if (0 == DispatcherThread) { Result = FspNtStatusFromWin32(GetLastError()); goto exit; } } memset(Response, 0, sizeof *Response); for (;;) { RequestSize = FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN; Result = FspFsctlTransact(FileSystem->VolumeHandle, Response, Response->Size, Request, &RequestSize, FALSE); if (!NT_SUCCESS(Result)) goto exit; memset(Response, 0, sizeof *Response); if (0 == RequestSize) continue; #if 0 FspDebugLog("FspFileSystemDispatcherThread: TID=%ld, Request={Kind=%d, Hint=%p}\n", GetCurrentThreadId(), Request->Kind, (PVOID)Request->Hint); #endif Response->Size = sizeof *Response; Response->Kind = Request->Kind; Response->Hint = Request->Hint; if (FspFsctlTransactKindCount > Request->Kind && 0 != FileSystem->Operations[Request->Kind]) { FspFileSystemEnterOperation(FileSystem, Request, Response); Response->IoStatus.Status = FileSystem->Operations[Request->Kind](FileSystem, Request, Response); FspFileSystemLeaveOperation(FileSystem, Request, Response); } else Response->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; } exit: MemFree(Response); MemFree(Request); FspFileSystemSetDispatcherResult(FileSystem, Result); FspFsctlStop(FileSystem->VolumeHandle); if (0 != DispatcherThread) { WaitForSingleObject(DispatcherThread, INFINITE); CloseHandle(DispatcherThread); } return Result; } FSP_API NTSTATUS FspFileSystemStartDispatcher(FSP_FILE_SYSTEM *FileSystem, ULONG ThreadCount) { if (0 != FileSystem->DispatcherThread) return STATUS_INVALID_PARAMETER; if (0 == ThreadCount) { DWORD_PTR ProcessMask, SystemMask; if (!GetProcessAffinityMask(GetCurrentProcess(), &ProcessMask, &SystemMask)) return FspNtStatusFromWin32(GetLastError()); for (ThreadCount = 0; 0 != ProcessMask; ProcessMask >>= 1) ThreadCount += ProcessMask & 1; } if (ThreadCount < FspFileSystemDispatcherThreadCountMin) ThreadCount = FspFileSystemDispatcherThreadCountMin; FileSystem->DispatcherThreadCount = ThreadCount; FileSystem->DispatcherThread = CreateThread(0, 0, FspFileSystemDispatcherThread, FileSystem, 0, 0); if (0 == FileSystem->DispatcherThread) return FspNtStatusFromWin32(GetLastError()); return STATUS_SUCCESS; } FSP_API VOID FspFileSystemStopDispatcher(FSP_FILE_SYSTEM *FileSystem) { if (0 == FileSystem->DispatcherThread) return; FspFsctlStop(FileSystem->VolumeHandle); WaitForSingleObject(FileSystem->DispatcherThread, INFINITE); CloseHandle(FileSystem->DispatcherThread); }