/** * @file dll/fs.c * * @copyright 2015-2019 Bill Zissimopoulos */ /* * This file is part of WinFsp. * * You can redistribute it and/or modify it under the terms of the GNU * General Public License version 3 as published by the Free Software * Foundation. * * Licensees holding a valid commercial license may use this software * in accordance with the commercial license agreement provided in * conjunction with the software. The terms and conditions of any such * commercial license agreement shall govern, supersede, and render * ineffective any application of the GPLv3 license to this software, * notwithstanding of any reference thereto in the software or * associated repository. */ #include enum { FspFileSystemDispatcherThreadCountMin = 2, FspFileSystemDispatcherDefaultThreadCountMin = 4, FspFileSystemDispatcherDefaultThreadCountMax = 16, }; static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface; static INIT_ONCE FspFileSystemInitOnce = INIT_ONCE_STATIC_INIT; static DWORD FspFileSystemTlsKey = TLS_OUT_OF_INDEXES; static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)( PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes); static NTSTATUS (NTAPI *FspNtMakeTemporaryObject)( HANDLE Handle); static NTSTATUS (NTAPI *FspNtClose)( HANDLE Handle); static BOOL WINAPI FspFileSystemInitialize( PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) { HANDLE Handle; FspFileSystemTlsKey = TlsAlloc(); Handle = GetModuleHandleW(L"ntdll.dll"); if (0 != Handle) { FspNtOpenSymbolicLinkObject = (PVOID)GetProcAddress(Handle, "NtOpenSymbolicLinkObject"); FspNtMakeTemporaryObject = (PVOID)GetProcAddress(Handle, "NtMakeTemporaryObject"); FspNtClose = (PVOID)GetProcAddress(Handle, "NtClose"); if (0 == FspNtOpenSymbolicLinkObject || 0 == FspNtMakeTemporaryObject || 0 == FspNtClose) { FspNtOpenSymbolicLinkObject = 0; FspNtMakeTemporaryObject = 0; FspNtClose = 0; } } return TRUE; } VOID FspFileSystemFinalize(BOOLEAN Dynamic) { /* * This function is called during DLL_PROCESS_DETACH. We must therefore keep * finalization tasks to a minimum. * * We must free our TLS key (if any). We only do so if the library * is being explicitly unloaded (rather than the process exiting). */ if (Dynamic && TLS_OUT_OF_INDEXES != FspFileSystemTlsKey) TlsFree(FspFileSystemTlsKey); } FSP_API NTSTATUS FspFileSystemPreflight(PWSTR DevicePath, PWSTR MountPoint) { NTSTATUS Result; WCHAR TargetPath[MAX_PATH]; HANDLE DirHandle; Result = FspFsctlPreflight(DevicePath); if (!NT_SUCCESS(Result)) return Result; if (0 == MountPoint) Result = STATUS_SUCCESS; else { if (FspPathIsDrive(MountPoint)) Result = QueryDosDeviceW(MountPoint, TargetPath, MAX_PATH) ? STATUS_OBJECT_NAME_COLLISION : STATUS_SUCCESS; else { DirHandle = CreateFileW(MountPoint, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); if (INVALID_HANDLE_VALUE != DirHandle) { CloseHandle(DirHandle); Result = STATUS_OBJECT_NAME_COLLISION; } else if (ERROR_FILE_NOT_FOUND != GetLastError()) Result = STATUS_OBJECT_NAME_INVALID; else Result = STATUS_SUCCESS; } } return Result; } 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 (VolumeParams->UmFileContextIsUserContext2 && VolumeParams->UmFileContextIsFullContext) return STATUS_INVALID_PARAMETER; if (0 == Interface) Interface = &FspFileSystemNullInterface; InitOnceExecuteOnce(&FspFileSystemInitOnce, FspFileSystemInitialize, 0, 0); if (TLS_OUT_OF_INDEXES == FspFileSystemTlsKey) return STATUS_INSUFFICIENT_RESOURCES; 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[FspFsctlTransactReadKind] = FspFileSystemOpRead; FileSystem->Operations[FspFsctlTransactWriteKind] = FspFileSystemOpWrite; FileSystem->Operations[FspFsctlTransactQueryInformationKind] = FspFileSystemOpQueryInformation; FileSystem->Operations[FspFsctlTransactSetInformationKind] = FspFileSystemOpSetInformation; FileSystem->Operations[FspFsctlTransactQueryEaKind] = FspFileSystemOpQueryEa; FileSystem->Operations[FspFsctlTransactSetEaKind] = FspFileSystemOpSetEa; FileSystem->Operations[FspFsctlTransactFlushBuffersKind] = FspFileSystemOpFlushBuffers; FileSystem->Operations[FspFsctlTransactQueryVolumeInformationKind] = FspFileSystemOpQueryVolumeInformation; FileSystem->Operations[FspFsctlTransactSetVolumeInformationKind] = FspFileSystemOpSetVolumeInformation; FileSystem->Operations[FspFsctlTransactQueryDirectoryKind] = FspFileSystemOpQueryDirectory; FileSystem->Operations[FspFsctlTransactFileSystemControlKind] = FspFileSystemOpFileSystemControl; FileSystem->Operations[FspFsctlTransactDeviceControlKind] = FspFileSystemOpDeviceControl; FileSystem->Operations[FspFsctlTransactQuerySecurityKind] = FspFileSystemOpQuerySecurity; FileSystem->Operations[FspFsctlTransactSetSecurityKind] = FspFileSystemOpSetSecurity; FileSystem->Operations[FspFsctlTransactQueryStreamInformationKind] = FspFileSystemOpQueryStreamInformation; FileSystem->Interface = Interface; FileSystem->OpGuardStrategy = FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE; InitializeSRWLock(&FileSystem->OpGuardLock); FileSystem->EnterOperation = FspFileSystemOpEnter; FileSystem->LeaveOperation = FspFileSystemOpLeave; FileSystem->UmFileContextIsUserContext2 = !!VolumeParams->UmFileContextIsUserContext2; FileSystem->UmFileContextIsFullContext = !!VolumeParams->UmFileContextIsFullContext; *PFileSystem = FileSystem; return STATUS_SUCCESS; } FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem) { FspFileSystemRemoveMountPoint(FileSystem); CloseHandle(FileSystem->VolumeHandle); MemFree(FileSystem); } static NTSTATUS FspFileSystemLauncherDefineDosDevice( WCHAR Sign, PWSTR MountPoint, PWSTR VolumeName) { if (2 != lstrlenW(MountPoint) || FSP_FSCTL_VOLUME_NAME_SIZEMAX / sizeof(WCHAR) <= lstrlenW(VolumeName)) return STATUS_INVALID_PARAMETER; WCHAR Argv0[4]; PWSTR Argv[2]; NTSTATUS Result; ULONG ErrorCode; Argv0[0] = Sign; Argv0[1] = MountPoint[0]; Argv0[2] = MountPoint[1]; Argv0[3] = L'\0'; Argv[0] = Argv0; Argv[1] = VolumeName; Result = FspLaunchCallLauncherPipe(FspLaunchCmdDefineDosDevice, 2, Argv, 0, 0, 0, &ErrorCode); return !NT_SUCCESS(Result) ? Result : FspNtStatusFromWin32(ErrorCode); } static NTSTATUS FspFileSystemSetMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName, PHANDLE PMountHandle) { NTSTATUS Result; BOOLEAN IsLocalSystem, IsServiceContext; *PMountHandle = 0; Result = FspServiceContextCheck(0, &IsLocalSystem); IsServiceContext = NT_SUCCESS(Result) && !IsLocalSystem; if (IsServiceContext) { /* * If the current process is in the service context but not LocalSystem, * ask the launcher to DefineDosDevice for us. This is because the launcher * runs in the LocalSystem context and can create global drives. * * In this case the launcher will also add DELETE access to the drive symlink * for us, so that we can make it temporary below. */ Result = FspFileSystemLauncherDefineDosDevice(L'+', MountPoint, VolumeName); if (!NT_SUCCESS(Result)) return Result; } else { if (!DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, VolumeName)) return FspNtStatusFromWin32(GetLastError()); } if (0 != FspNtOpenSymbolicLinkObject) { WCHAR SymlinkBuf[6]; UNICODE_STRING Symlink; OBJECT_ATTRIBUTES Obja; memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf); SymlinkBuf[4] = MountPoint[0]; Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf; Symlink.Buffer = SymlinkBuf; memset(&Obja, 0, sizeof Obja); Obja.Length = sizeof Obja; Obja.ObjectName = &Symlink; Obja.Attributes = OBJ_CASE_INSENSITIVE; Result = FspNtOpenSymbolicLinkObject(PMountHandle, DELETE, &Obja); if (NT_SUCCESS(Result)) { Result = FspNtMakeTemporaryObject(*PMountHandle); if (!NT_SUCCESS(Result)) { FspNtClose(*PMountHandle); *PMountHandle = 0; } } } /* HACK: * * Handles do not use the low 2 bits (unless they are console handles). * Abuse this fact to remember that we are running in the service context. */ *PMountHandle = (HANDLE)(UINT_PTR)((DWORD)(UINT_PTR)*PMountHandle | IsServiceContext); return STATUS_SUCCESS; } static NTSTATUS FspFileSystemSetMountPoint_Directory(PWSTR MountPoint, PWSTR VolumeName, PSECURITY_DESCRIPTOR SecurityDescriptor, PHANDLE PMountHandle) { NTSTATUS Result; SECURITY_ATTRIBUTES SecurityAttributes; HANDLE MountHandle = INVALID_HANDLE_VALUE; DWORD Backslashes, Bytes; USHORT VolumeNameLength, BackslashLength, ReparseDataLength; PREPARSE_DATA_BUFFER ReparseData = 0; PWSTR P, PathBuffer; *PMountHandle = 0; /* * Windows does not allow mount points (junctions) to point to network file systems. * * Count how many backslashes our VolumeName has. If it is 3 or more this is a network * file system. Preemptively return STATUS_NETWORK_ACCESS_DENIED. */ for (P = VolumeName, Backslashes = 0; *P; P++) if (L'\\' == *P) if (3 == ++Backslashes) { Result = STATUS_NETWORK_ACCESS_DENIED; goto exit; } memset(&SecurityAttributes, 0, sizeof SecurityAttributes); SecurityAttributes.nLength = sizeof SecurityAttributes; SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor; MountHandle = CreateFileW(MountPoint, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &SecurityAttributes, CREATE_NEW, FILE_ATTRIBUTE_DIRECTORY | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE, 0); if (INVALID_HANDLE_VALUE == MountHandle) { Result = FspNtStatusFromWin32(GetLastError()); goto exit; } VolumeNameLength = (USHORT)lstrlenW(VolumeName); BackslashLength = 0 == VolumeNameLength || L'\\' != VolumeName[VolumeNameLength - 1]; VolumeNameLength *= sizeof(WCHAR); BackslashLength *= sizeof(WCHAR); ReparseDataLength = (USHORT)( FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) - FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer)) + 2 * (VolumeNameLength + BackslashLength + sizeof(WCHAR)); ReparseData = MemAlloc(REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataLength); if (0 == ReparseData) { Result = STATUS_INSUFFICIENT_RESOURCES; goto exit; } ReparseData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; ReparseData->ReparseDataLength = ReparseDataLength; ReparseData->Reserved = 0; ReparseData->MountPointReparseBuffer.SubstituteNameOffset = 0; ReparseData->MountPointReparseBuffer.SubstituteNameLength = VolumeNameLength + BackslashLength; ReparseData->MountPointReparseBuffer.PrintNameOffset = ReparseData->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR); ReparseData->MountPointReparseBuffer.PrintNameLength = VolumeNameLength + BackslashLength; PathBuffer = ReparseData->MountPointReparseBuffer.PathBuffer; memcpy(PathBuffer, VolumeName, VolumeNameLength); if (BackslashLength) PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\'; PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0'; PathBuffer = ReparseData->MountPointReparseBuffer.PathBuffer + (ReparseData->MountPointReparseBuffer.PrintNameOffset) / sizeof(WCHAR); memcpy(PathBuffer, VolumeName, VolumeNameLength); if (BackslashLength) PathBuffer[VolumeNameLength / sizeof(WCHAR)] = L'\\'; PathBuffer[(VolumeNameLength + BackslashLength) / sizeof(WCHAR)] = L'\0'; if (!DeviceIoControl(MountHandle, FSCTL_SET_REPARSE_POINT, ReparseData, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseData->ReparseDataLength, 0, 0, &Bytes, 0)) { Result = FspNtStatusFromWin32(GetLastError()); goto exit; } *PMountHandle = MountHandle; Result = STATUS_SUCCESS; exit: if (!NT_SUCCESS(Result) && INVALID_HANDLE_VALUE != MountHandle) CloseHandle(MountHandle); MemFree(ReparseData); return Result; } FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint) { return FspFileSystemSetMountPointEx(FileSystem, MountPoint, 0); } FSP_API NTSTATUS FspFileSystemSetMountPointEx(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint, PSECURITY_DESCRIPTOR SecurityDescriptor) { if (0 != FileSystem->MountPoint) return STATUS_INVALID_PARAMETER; NTSTATUS Result; HANDLE MountHandle = 0; if (0 == MountPoint) { DWORD Drives; WCHAR Drive; MountPoint = MemAlloc(3 * sizeof(WCHAR)); if (0 == MountPoint) return STATUS_INSUFFICIENT_RESOURCES; MountPoint[1] = L':'; MountPoint[2] = L'\0'; Drives = GetLogicalDrives(); if (0 != Drives) { for (Drive = 'Z'; 'D' <= Drive; Drive--) if (0 == (Drives & (1 << (Drive - 'A')))) { MountPoint[0] = Drive; Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName, &MountHandle); if (NT_SUCCESS(Result)) goto exit; } Result = STATUS_NO_SUCH_DEVICE; } else Result = FspNtStatusFromWin32(GetLastError()); } else { PWSTR P; ULONG L; L = (ULONG)((lstrlenW(MountPoint) + 1) * sizeof(WCHAR)); P = MemAlloc(L); if (0 == P) return STATUS_INSUFFICIENT_RESOURCES; memcpy(P, MountPoint, L); MountPoint = P; if (FspPathIsDrive(MountPoint)) Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName, &MountHandle); else Result = FspFileSystemSetMountPoint_Directory(MountPoint, FileSystem->VolumeName, SecurityDescriptor, &MountHandle); } exit: if (NT_SUCCESS(Result)) { FileSystem->MountPoint = MountPoint; FileSystem->MountHandle = MountHandle; } else MemFree(MountPoint); return Result; } static VOID FspFileSystemRemoveMountPoint_Drive(PWSTR MountPoint, PWSTR VolumeName, HANDLE MountHandle) { BOOLEAN IsServiceContext = 0 != ((DWORD)(UINT_PTR)MountHandle & 1); MountHandle = (HANDLE)(UINT_PTR)((DWORD)(UINT_PTR)MountHandle & ~1); if (IsServiceContext) /* * If the current process is in the service context but not LocalSystem, * ask the launcher to DefineDosDevice for us. This is because the launcher * runs in the LocalSystem context and can remove global drives. */ FspFileSystemLauncherDefineDosDevice(L'-', MountPoint, VolumeName); else DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, MountPoint, VolumeName); if (0 != MountHandle) FspNtClose(MountHandle); } static VOID FspFileSystemRemoveMountPoint_Directory(HANDLE MountHandle) { /* directory is marked DELETE_ON_CLOSE */ CloseHandle(MountHandle); } FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem) { if (0 == FileSystem->MountPoint) return; if (FspPathIsDrive(FileSystem->MountPoint)) FspFileSystemRemoveMountPoint_Drive(FileSystem->MountPoint, FileSystem->VolumeName, FileSystem->MountHandle); else FspFileSystemRemoveMountPoint_Directory(FileSystem->MountHandle); MemFree(FileSystem->MountPoint); FileSystem->MountPoint = 0; FileSystem->MountHandle = 0; } static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0) { FSP_FILE_SYSTEM *FileSystem = FileSystem0; NTSTATUS Result; SIZE_T RequestSize, ResponseSize; FSP_FSCTL_TRANSACT_REQ *Request = 0; FSP_FSCTL_TRANSACT_RSP *Response = 0; FSP_FILE_SYSTEM_OPERATION_CONTEXT OperationContext; 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; } } OperationContext.Request = Request; OperationContext.Response = Response; TlsSetValue(FspFileSystemTlsKey, &OperationContext); 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 (FileSystem->DebugLog) { if (FspFsctlTransactKindCount <= Request->Kind || (FileSystem->DebugLog & (1 << Request->Kind))) FspDebugLogRequest(Request); } Response->Size = sizeof *Response; Response->Kind = Request->Kind; Response->Hint = Request->Hint; if (FspFsctlTransactKindCount > Request->Kind && 0 != FileSystem->Operations[Request->Kind]) { Response->IoStatus.Status = FspFileSystemEnterOperation(FileSystem, Request, Response); if (NT_SUCCESS(Response->IoStatus.Status)) { Response->IoStatus.Status = FileSystem->Operations[Request->Kind](FileSystem, Request, Response); FspFileSystemLeaveOperation(FileSystem, Request, Response); } } else Response->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; if (FileSystem->DebugLog) { if (FspFsctlTransactKindCount <= Response->Kind || (FileSystem->DebugLog & (1 << Response->Kind))) FspDebugLogResponse(Response); } ResponseSize = FSP_FSCTL_DEFAULT_ALIGN_UP(Response->Size); if (FSP_FSCTL_TRANSACT_RSP_SIZEMAX < ResponseSize/* should NOT happen */) { memset(Response, 0, sizeof *Response); Response->Size = sizeof *Response; Response->Kind = Request->Kind; Response->Hint = Request->Hint; Response->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; } else if (STATUS_PENDING == Response->IoStatus.Status) memset(Response, 0, sizeof *Response); else { memset((PUINT8)Response + Response->Size, 0, ResponseSize - Response->Size); Response->Size = (UINT16)ResponseSize; } } exit: TlsSetValue(FspFileSystemTlsKey, 0); 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 < FspFileSystemDispatcherDefaultThreadCountMin) ThreadCount = FspFileSystemDispatcherDefaultThreadCountMin; else if (ThreadCount > FspFileSystemDispatcherDefaultThreadCountMax) ThreadCount = FspFileSystemDispatcherDefaultThreadCountMax; } 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); FileSystem->DispatcherThread = 0; } FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem, FSP_FSCTL_TRANSACT_RSP *Response) { NTSTATUS Result; if (FileSystem->DebugLog) { if (FspFsctlTransactKindCount <= Response->Kind || (FileSystem->DebugLog & (1 << Response->Kind))) FspDebugLogResponse(Response); } Result = FspFsctlTransact(FileSystem->VolumeHandle, Response, Response->Size, 0, 0, FALSE); if (!NT_SUCCESS(Result)) { FspFileSystemSetDispatcherResult(FileSystem, Result); FspFsctlStop(FileSystem->VolumeHandle); } } FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID) { return (FSP_FILE_SYSTEM_OPERATION_CONTEXT *)TlsGetValue(FspFileSystemTlsKey); } /* * Out-of-Line */ FSP_API PWSTR FspFileSystemMountPointF(FSP_FILE_SYSTEM *FileSystem) { return FspFileSystemMountPoint(FileSystem); } FSP_API NTSTATUS FspFileSystemEnterOperationF(FSP_FILE_SYSTEM *FileSystem, FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response) { return FspFileSystemEnterOperation(FileSystem, Request, Response); } FSP_API NTSTATUS FspFileSystemLeaveOperationF(FSP_FILE_SYSTEM *FileSystem, FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response) { return FspFileSystemLeaveOperation(FileSystem, Request, Response); } FSP_API VOID FspFileSystemSetOperationGuardF(FSP_FILE_SYSTEM *FileSystem, FSP_FILE_SYSTEM_OPERATION_GUARD *EnterOperation, FSP_FILE_SYSTEM_OPERATION_GUARD *LeaveOperation) { FspFileSystemSetOperationGuard(FileSystem, EnterOperation, LeaveOperation); } FSP_API VOID FspFileSystemSetOperationGuardStrategyF(FSP_FILE_SYSTEM *FileSystem, FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy) { FspFileSystemSetOperationGuardStrategy(FileSystem, GuardStrategy); } FSP_API VOID FspFileSystemSetOperationF(FSP_FILE_SYSTEM *FileSystem, ULONG Index, FSP_FILE_SYSTEM_OPERATION *Operation) { FspFileSystemSetOperation(FileSystem, Index, Operation); } FSP_API VOID FspFileSystemGetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem, NTSTATUS *PDispatcherResult) { FspFileSystemGetDispatcherResult(FileSystem, PDispatcherResult); } FSP_API VOID FspFileSystemSetDispatcherResultF(FSP_FILE_SYSTEM *FileSystem, NTSTATUS DispatcherResult) { FspFileSystemSetDispatcherResult(FileSystem, DispatcherResult); } FSP_API VOID FspFileSystemSetDebugLogF(FSP_FILE_SYSTEM *FileSystem, UINT32 DebugLog) { FspFileSystemSetDebugLog(FileSystem, DebugLog); } FSP_API BOOLEAN FspFileSystemIsOperationCaseSensitiveF(VOID) { return FspFileSystemIsOperationCaseSensitive(); } FSP_API UINT32 FspFileSystemOperationProcessIdF(VOID) { return FspFileSystemOperationProcessId(); }