diff --git a/build/VStudio/winfsp_dll.vcxproj b/build/VStudio/winfsp_dll.vcxproj index 58ea242a..fa8884ed 100644 --- a/build/VStudio/winfsp_dll.vcxproj +++ b/build/VStudio/winfsp_dll.vcxproj @@ -24,6 +24,7 @@ + @@ -34,6 +35,7 @@ + @@ -133,6 +135,7 @@ true $(OutDir)$(TargetFileName).map true + ..\..\src\dll\library.def @@ -156,6 +159,7 @@ true $(OutDir)$(TargetFileName).map true + ..\..\src\dll\library.def @@ -182,6 +186,7 @@ true $(OutDir)$(TargetFileName).map true + ..\..\src\dll\library.def @@ -208,6 +213,7 @@ true $(OutDir)$(TargetFileName).map true + ..\..\src\dll\library.def diff --git a/build/VStudio/winfsp_dll.vcxproj.filters b/build/VStudio/winfsp_dll.vcxproj.filters index 7f612bf4..6ae39e5b 100644 --- a/build/VStudio/winfsp_dll.vcxproj.filters +++ b/build/VStudio/winfsp_dll.vcxproj.filters @@ -49,10 +49,16 @@ Source + + Source + Source + + Source + \ No newline at end of file diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index 577dadf1..8017b9bc 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -34,6 +34,8 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid = /* fsctl device codes */ #define FSP_FSCTL_VOLUME_NAME \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'N', METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSP_FSCTL_VOLUME_LIST \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'L', METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSP_FSCTL_TRANSACT \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'T', METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSP_FSCTL_TRANSACT_BATCH \ @@ -405,6 +407,8 @@ FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle, PVOID RequestBuf, SIZE_T *PRequestBufSize, BOOLEAN Batch); FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle); +FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath, + PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize); #endif #ifdef __cplusplus diff --git a/src/dll/fsctl.c b/src/dll/fsctl.c index 7fdf0a96..72fdd48a 100644 --- a/src/dll/fsctl.c +++ b/src/dll/fsctl.c @@ -119,3 +119,58 @@ FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle) return STATUS_SUCCESS; } + +FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath, + PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize) +{ + NTSTATUS Result; + PWSTR DeviceRoot; + SIZE_T DeviceRootSize, DevicePathSize; + WCHAR DevicePathBuf[MAX_PATH], *DevicePathPtr; + HANDLE VolumeHandle = INVALID_HANDLE_VALUE; + DWORD Bytes; + + /* check lengths; everything must fit within MAX_PATH */ + DeviceRoot = L'\\' == DevicePath[0] ? GLOBALROOT : GLOBALROOT "\\Device\\"; + DeviceRootSize = lstrlenW(DeviceRoot) * sizeof(WCHAR); + DevicePathSize = lstrlenW(DevicePath) * sizeof(WCHAR); + if (DeviceRootSize + DevicePathSize + sizeof(WCHAR) > sizeof DevicePathBuf) + return STATUS_INVALID_PARAMETER; + + /* prepare the device path to be opened */ + DevicePathPtr = DevicePathBuf; + memcpy(DevicePathPtr, DeviceRoot, DeviceRootSize); + DevicePathPtr = (PVOID)((PUINT8)DevicePathPtr + DeviceRootSize); + memcpy(DevicePathPtr, DevicePath, DevicePathSize); + DevicePathPtr = (PVOID)((PUINT8)DevicePathPtr + DevicePathSize); + *DevicePathPtr = L'\0'; + + VolumeHandle = CreateFileW(DevicePathBuf, + 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if (INVALID_HANDLE_VALUE == VolumeHandle) + { + Result = FspNtStatusFromWin32(GetLastError()); + if (STATUS_OBJECT_PATH_NOT_FOUND == Result || + STATUS_OBJECT_NAME_NOT_FOUND == Result) + Result = STATUS_NO_SUCH_DEVICE; + goto exit; + } + + if (!DeviceIoControl(VolumeHandle, FSP_FSCTL_VOLUME_LIST, + 0, 0, + VolumeListBuf, (DWORD)*PVolumeListSize, + &Bytes, 0)) + { + Result = FspNtStatusFromWin32(GetLastError()); + goto exit; + } + + *PVolumeListSize = Bytes; + Result = STATUS_SUCCESS; + +exit: + if (INVALID_HANDLE_VALUE != VolumeHandle) + CloseHandle(VolumeHandle); + + return Result; +} diff --git a/src/dll/library.c b/src/dll/library.c index 15675e80..84ae9959 100644 --- a/src/dll/library.c +++ b/src/dll/library.c @@ -6,6 +6,7 @@ #include +HINSTANCE DllInstance; HANDLE ProcessHeap; BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved) @@ -13,6 +14,7 @@ BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved) switch (Reason) { case DLL_PROCESS_ATTACH: + DllInstance = Instance; ProcessHeap = GetProcessHeap(); if (0 == ProcessHeap) return FALSE; @@ -33,3 +35,21 @@ BOOL WINAPI _DllMainCRTStartup(HINSTANCE Instance, DWORD Reason, PVOID Reserved) return DllMain(Instance, Reason, Reserved); } #endif + +HRESULT WINAPI DllRegisterServer(VOID) +{ + NTSTATUS Result; + + Result = FspNpRegister(); + + return NT_SUCCESS(Result) ? S_OK : 0x80040201/*SELFREG_E_CLASS*/; +} + +HRESULT WINAPI DllUnregisterServer(VOID) +{ + NTSTATUS Result; + + Result = FspNpUnregister(); + + return NT_SUCCESS(Result) ? S_OK : 0x80040201/*SELFREG_E_CLASS*/; +} diff --git a/src/dll/library.def b/src/dll/library.def new file mode 100644 index 00000000..b0b591f9 --- /dev/null +++ b/src/dll/library.def @@ -0,0 +1,5 @@ +EXPORTS + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + NPGetCaps PRIVATE + NPGetConnection PRIVATE diff --git a/src/dll/library.h b/src/dll/library.h index b6f32318..21d019e0 100644 --- a/src/dll/library.h +++ b/src/dll/library.h @@ -95,4 +95,7 @@ BOOLEAN RemoveEntryList(PLIST_ENTRY Entry) VOID FspFileSystemInitialize(VOID); VOID FspFileSystemFinalize(VOID); +NTSTATUS FspNpRegister(VOID); +NTSTATUS FspNpUnregister(VOID); + #endif diff --git a/src/dll/np.c b/src/dll/np.c new file mode 100644 index 00000000..f4d1de9f --- /dev/null +++ b/src/dll/np.c @@ -0,0 +1,351 @@ +/** + * @file dll/np.c + * + * @copyright 2015-2016 Bill Zissimopoulos + */ + +#include +#include + +#define FSP_NP_NAME "WinFsp.Np" +#define FSP_NP_DESC "File System Proxy" +#define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */ + +DWORD APIENTRY NPGetCaps(DWORD Index) +{ + switch (Index) + { + case WNNC_ADMIN: + /* + * WNNC_ADM_DIRECTORYNOTIFY + * WNNC_ADM_GETDIRECTORYTYPE + */ + return 0; + case WNNC_CONNECTION: + /* + * WNNC_CON_ADDCONECTION + * WNNC_CON_CANCELCONNECTION + * WNNC_CON_GETCONNECTIONS + * WNNC_CON_ADDCONECTION3 + * WNNC_CON_GETPERFORMANCE + * WNNC_CON_DEFER + */ + return WNNC_CON_GETCONNECTIONS; + case WNNC_DIALOG: + /* + * WNNC_DLG_DEVICEMODE + * WNNC_DLG_FORMATNETNAME + * WNNC_DLG_GETRESOURCEINFORMATION + * WNNC_DLG_GETRESOURCEPARENT + * WNNC_DLG_PERMISSIONEDITOR + * WNNC_DLG_PROPERTYDIALOG + * WNNC_DLG_SEARCHDIALOG + */ + return 0; + case WNNC_ENUMERATION: + /* + * WNNC_ENUM_GLOBAL + * WNNC_ENUM_LOCAL + * WNNC_ENUM_CONTEXT + */ + return 0; + case WNNC_NET_TYPE: + return FSP_NP_TYPE; + case WNNC_SPEC_VERSION: + return WNNC_SPEC_VERSION51; + case WNNC_START: + return 1; + case WNNC_USER: + /* + * WNNC_USR_GETUSER + */ + return 0; + default: + return 0; + } +} + +static NTSTATUS FspNpGetVolumeList( + PWCHAR *PVolumeListBuf, PSIZE_T PVolumeListSize) +{ + NTSTATUS Result; + PWCHAR VolumeListBuf; + SIZE_T VolumeListSize; + + *PVolumeListBuf = 0; + *PVolumeListSize = 0; + + for (VolumeListSize = 1024;; VolumeListSize *= 2) + { + VolumeListBuf = MemAlloc(VolumeListSize); + if (0 == VolumeListBuf) + return STATUS_INSUFFICIENT_RESOURCES; + + Result = FspFsctlGetVolumeList(L"" FSP_FSCTL_NET_DEVICE_NAME, + VolumeListBuf, &VolumeListSize); + if (NT_SUCCESS(Result)) + { + *PVolumeListBuf = VolumeListBuf; + *PVolumeListSize = VolumeListSize; + return Result; + } + + MemFree(VolumeListBuf); + + if (STATUS_BUFFER_TOO_SMALL != Result) + return Result; + } +} + +DWORD APIENTRY NPGetConnection(LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpnBufferLen) +{ + DWORD NpResult; + NTSTATUS Result; + WCHAR LocalNameBuf[3]; + WCHAR VolumeNameBuf[FSP_FSCTL_VOLUME_NAME_SIZEMAX / sizeof(WCHAR)]; + PWCHAR VolumeListBuf = 0, VolumeListBufEnd, VolumeName, P; + SIZE_T VolumeListSize, VolumeNameSize; + ULONG Backslashes; + + if (0 == lpLocalName || + !( + (L'A' <= lpLocalName[0] && lpLocalName[0] <= L'Z') || + (L'a' <= lpLocalName[0] && lpLocalName[0] <= L'z') + ) || + L':' != lpLocalName[1]) + return WN_BAD_LOCALNAME; + + LocalNameBuf[0] = lpLocalName[0]; + LocalNameBuf[1] = L':'; + LocalNameBuf[2] = L'\0'; + + if (0 == QueryDosDeviceW(LocalNameBuf, VolumeNameBuf, sizeof VolumeNameBuf)) + return WN_NOT_CONNECTED; + + Result = FspNpGetVolumeList(&VolumeListBuf, &VolumeListSize); + if (!NT_SUCCESS(Result)) + return WN_OUT_OF_MEMORY; + + NpResult = WN_NOT_CONNECTED; + for (P = VolumeListBuf, VolumeListBufEnd = (PVOID)((PUINT8)P + VolumeListSize), VolumeName = P; + VolumeListBufEnd > P; P++) + { + if (L'\0' == *P) + { + if (0 == lstrcmpW(VolumeNameBuf, VolumeName)) + { + /* + * Looks like this is a WinFsp device. Extract the VolumePrefix from the VolumeName. + * + * The VolumeName will have the following syntax: + * \Device\Volume{GUID}\Server\Share + * + * We want to extract the \Server\Share part. We will simply count backslashes and + * stop at the third one. Since we are about to break this loop, it is ok to mess + * with the loop variables. + */ + + for (Backslashes = 0; VolumeName < P; VolumeName++) + if (L'\\' == *VolumeName) + if (3 == ++Backslashes) + break; + + if (3 == Backslashes) + { + VolumeNameSize = lstrlenW(VolumeName) + 1/* term-0 */; + if (*lpnBufferLen >= 1/* lead-\ */ + VolumeNameSize) + { + *lpRemoteName = L'\\'; + memcpy(lpRemoteName + 1, VolumeName, VolumeNameSize * sizeof(WCHAR)); + NpResult = WN_SUCCESS; + } + else + { + *lpnBufferLen = (DWORD)(1/* lead-\ */ + VolumeNameSize); + NpResult = WN_MORE_DATA; + } + } + + break; + } + else + VolumeName = P + 1; + } + } + + MemFree(VolumeListBuf); + + return NpResult; +} + +NTSTATUS FspNpRegister(VOID) +{ + extern HINSTANCE DllInstance; + WCHAR ProviderPath[MAX_PATH]; + WCHAR RegBuffer[1024]; + PWSTR P, Part; + DWORD RegResult, RegType, RegBufferSize; + HKEY RegKey; + BOOLEAN FoundProvider; + + if (0 == GetModuleFileNameW(DllInstance, ProviderPath, MAX_PATH)) + return FspNtStatusFromWin32(GetLastError()); + + RegResult = RegCreateKeyExW( + HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\" FSP_NP_NAME, + 0, 0, 0, KEY_ALL_ACCESS, 0, &RegKey, 0); + if (ERROR_SUCCESS != RegResult) + return FspNtStatusFromWin32(RegResult); + + RegResult = RegSetValueExW(RegKey, + L"Group", 0, REG_SZ, (PVOID) L"NetworkProvider", sizeof L"NetworkProvider"); + if (ERROR_SUCCESS != RegResult) + goto close_and_exit; + + RegCloseKey(RegKey); + + RegResult = RegCreateKeyExW( + HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\" FSP_NP_NAME "\\NetworkProvider", + 0, 0, 0, KEY_ALL_ACCESS, 0, &RegKey, 0); + if (ERROR_SUCCESS != RegResult) + return FspNtStatusFromWin32(RegResult); + + RegResult = RegSetValueExW(RegKey, + L"Name", 0, REG_SZ, (PVOID) L"" FSP_NP_DESC, sizeof L"" FSP_NP_DESC); + if (ERROR_SUCCESS != RegResult) + goto close_and_exit; + + RegResult = RegSetValueExW(RegKey, + L"ProviderPath", 0, REG_SZ, (PVOID)ProviderPath, (lstrlenW(ProviderPath) + 1) * sizeof(WCHAR)); + if (ERROR_SUCCESS != RegResult) + goto close_and_exit; + + RegCloseKey(RegKey); + + RegResult = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order", + 0, KEY_ALL_ACCESS, &RegKey); + if (ERROR_SUCCESS != RegResult) + return FspNtStatusFromWin32(RegResult); + + RegBufferSize = sizeof RegBuffer - sizeof L"," FSP_NP_NAME; + RegResult = RegQueryValueExW(RegKey, + L"ProviderOrder", 0, &RegType, (PVOID)RegBuffer, &RegBufferSize); + if (ERROR_SUCCESS != RegResult) + goto close_and_exit; + RegBufferSize /= sizeof(WCHAR); + + FoundProvider = FALSE; + RegBuffer[RegBufferSize] = L'\0'; + P = RegBuffer, Part = P; + do + { + if (L',' == *P || '\0' == *P) + { + if (CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, + Part, (int)(P - Part), + L"" FSP_NP_NAME, (int)(sizeof L"" FSP_NP_NAME - sizeof(WCHAR)) / sizeof(WCHAR))) + { + FoundProvider = TRUE; + break; + } + else + Part = P + 1; + } + } while (L'\0' != *P++); + + if (!FoundProvider) + { + P--; + memcpy(P, L"," FSP_NP_NAME, sizeof L"," FSP_NP_NAME); + + RegBufferSize = lstrlenW(RegBuffer); + RegBufferSize++; + + RegResult = RegSetValueExW(RegKey, + L"ProviderOrder", 0, REG_SZ, (PVOID)RegBuffer, RegBufferSize * sizeof(WCHAR)); + if (ERROR_SUCCESS != RegResult) + goto close_and_exit; + } + + RegCloseKey(RegKey); + + return STATUS_SUCCESS; + +close_and_exit: + RegCloseKey(RegKey); + return FspNtStatusFromWin32(RegResult); +} + +NTSTATUS FspNpUnregister(VOID) +{ + WCHAR RegBuffer[1024]; + PWSTR P, Part; + DWORD RegResult, RegType, RegBufferSize; + HKEY RegKey; + BOOLEAN FoundProvider; + + RegResult = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order", + 0, KEY_ALL_ACCESS, &RegKey); + if (ERROR_SUCCESS != RegResult) + return FspNtStatusFromWin32(RegResult); + + RegBufferSize = sizeof RegBuffer - sizeof L"," FSP_NP_NAME; + RegResult = RegQueryValueExW(RegKey, + L"ProviderOrder", 0, &RegType, (PVOID)RegBuffer, &RegBufferSize); + if (ERROR_SUCCESS != RegResult) + goto close_and_exit; + RegBufferSize /= sizeof(WCHAR); + + FoundProvider = FALSE; + RegBuffer[RegBufferSize] = L'\0'; + P = RegBuffer, Part = P; + do + { + if (L',' == *P || '\0' == *P) + { + if (CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, + Part, (int)(P - Part), + L"" FSP_NP_NAME, (int)(sizeof L"" FSP_NP_NAME - sizeof(WCHAR)) / sizeof(WCHAR))) + { + FoundProvider = TRUE; + break; + } + else + Part = P + 1; + } + } while (L'\0' != *P++); + + if (FoundProvider) + { + if (L',' == *P) + P++; + + RtlMoveMemory(Part, P, (lstrlenW(P) + 1) * sizeof(WCHAR)); + + RegBufferSize = lstrlenW(RegBuffer); + while (0 < RegBufferSize && ',' == RegBuffer[RegBufferSize - 1]) + RegBufferSize--; + RegBuffer[RegBufferSize] = L'\0'; + RegBufferSize++; + + RegResult = RegSetValueExW(RegKey, + L"ProviderOrder", 0, REG_SZ, (PVOID)RegBuffer, RegBufferSize * sizeof(WCHAR)); + if (ERROR_SUCCESS != RegResult) + goto close_and_exit; + } + + RegCloseKey(RegKey); + + RegResult = RegDeleteTreeW( + HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\" FSP_NP_NAME); + if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult) + return FspNtStatusFromWin32(RegResult); + + return STATUS_SUCCESS; + +close_and_exit: + RegCloseKey(RegKey); + return FspNtStatusFromWin32(RegResult); +} diff --git a/src/sys/driver.h b/src/sys/driver.h index e9cab75c..6fa026b9 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -853,6 +853,8 @@ NTSTATUS FspVolumeRedirQueryPathEx( PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeGetName( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +NTSTATUS FspVolumeGetNameList( + PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeTransact( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeStop( diff --git a/src/sys/fsctl.c b/src/sys/fsctl.c index b7832449..cbd2a90a 100644 --- a/src/sys/fsctl.c +++ b/src/sys/fsctl.c @@ -35,6 +35,9 @@ static NTSTATUS FspFsctlFileSystemControl( if (0 != IrpSp->FileObject->FsContext2) Result = FspVolumeGetName(DeviceObject, Irp, IrpSp); break; + case FSP_FSCTL_VOLUME_LIST: + Result = FspVolumeGetNameList(DeviceObject, Irp, IrpSp); + break; case FSP_FSCTL_TRANSACT: case FSP_FSCTL_TRANSACT_BATCH: if (0 != IrpSp->FileObject->FsContext2) diff --git a/src/sys/volume.c b/src/sys/volume.c index f7bbdbf2..1ce7a5f2 100644 --- a/src/sys/volume.c +++ b/src/sys/volume.c @@ -24,6 +24,10 @@ NTSTATUS FspVolumeRedirQueryPathEx( PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeGetName( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +NTSTATUS FspVolumeGetNameList( + PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspVolumeGetNameListNoLock( + PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeTransact( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeStop( @@ -42,6 +46,8 @@ NTSTATUS FspVolumeWork( // ! #pragma alloc_text(PAGE, FspVolumeMountNoLock) #pragma alloc_text(PAGE, FspVolumeRedirQueryPathEx) #pragma alloc_text(PAGE, FspVolumeGetName) +#pragma alloc_text(PAGE, FspVolumeGetNameList) +#pragma alloc_text(PAGE, FspVolumeGetNameListNoLock) #pragma alloc_text(PAGE, FspVolumeTransact) #pragma alloc_text(PAGE, FspVolumeStop) #pragma alloc_text(PAGE, FspVolumeWork) @@ -60,6 +66,8 @@ typedef struct NTSTATUS FspVolumeCreate( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { + PAGED_CODE(); + NTSTATUS Result; FspDeviceGlobalLock(); Result = FspVolumeCreateNoLock(FsctlDeviceObject, Irp, IrpSp); @@ -259,6 +267,8 @@ static VOID FspVolumeCreateRegisterMup(PVOID Context) VOID FspVolumeDelete( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { + // !PAGED_CODE(); + FspDeviceGlobalLock(); FspVolumeDeleteNoLock(FsctlDeviceObject, Irp, IrpSp); FspDeviceGlobalUnlock(); @@ -381,6 +391,8 @@ static VOID FspVolumeDeleteDelayed(PVOID Context) NTSTATUS FspVolumeMount( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { + // !PAGED_CODE(); + NTSTATUS Result; FspDeviceGlobalLock(); Result = FspVolumeMountNoLock(FsctlDeviceObject, Irp, IrpSp); @@ -532,6 +544,85 @@ NTSTATUS FspVolumeGetName( return STATUS_SUCCESS; } +NTSTATUS FspVolumeGetNameList( + PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result; + FspDeviceGlobalLock(); + Result = FspVolumeGetNameListNoLock(FsctlDeviceObject, Irp, IrpSp); + FspDeviceGlobalUnlock(); + return Result; +} + +static NTSTATUS FspVolumeGetNameListNoLock( + PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + ASSERT(IRP_MJ_FILE_SYSTEM_CONTROL == IrpSp->MajorFunction); + ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction); + ASSERT(FSP_FSCTL_VOLUME_LIST == IrpSp->Parameters.FileSystemControl.FsControlCode); + + NTSTATUS Result; + ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; + PVOID SystemBuffer = Irp->AssociatedIrp.SystemBuffer; + PDEVICE_OBJECT *DeviceObjects = 0; + ULONG DeviceObjectCount = 0; + PDEVICE_OBJECT FsvolDeviceObject; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension; + UNICODE_STRING VolumeList; + USHORT Length; + + if (65535/*USHRT_MAX*/ < OutputBufferLength) + return STATUS_INVALID_PARAMETER; + + Result = FspDeviceCopyList(&DeviceObjects, &DeviceObjectCount); + if (!NT_SUCCESS(Result)) + return Result; + + Result = STATUS_SUCCESS; + RtlInitEmptyUnicodeString(&VolumeList, SystemBuffer, (USHORT)OutputBufferLength); + for (ULONG i = 0; NT_SUCCESS(Result) && DeviceObjectCount > i; i++) + if (FspDeviceReference(DeviceObjects[i])) + { + if (FspFsvolDeviceExtensionKind == FspDeviceExtension(DeviceObjects[i])->Kind) + { + FsvolDeviceObject = DeviceObjects[i]; + FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + if (FsvolDeviceExtension->FsctlDeviceObject == FsctlDeviceObject && + !FspIoqStopped(FsvolDeviceExtension->Ioq)) + { + Length = + FsvolDeviceExtension->VolumeName.Length + + FsvolDeviceExtension->VolumePrefix.Length + + sizeof(WCHAR); + + if (VolumeList.Length + Length <= VolumeList.MaximumLength) + { + RtlAppendUnicodeStringToString(&VolumeList, &FsvolDeviceExtension->VolumeName); + if (FILE_DEVICE_NETWORK_FILE_SYSTEM == FsctlDeviceObject->DeviceType) + RtlAppendUnicodeStringToString(&VolumeList, &FsvolDeviceExtension->VolumePrefix); + VolumeList.Buffer[VolumeList.Length / sizeof(WCHAR)] = L'\0'; + VolumeList.Length += sizeof(WCHAR); + } + else + { + VolumeList.Length = 0; + Result = STATUS_BUFFER_TOO_SMALL; + } + } + } + FspDeviceDereference(DeviceObjects[i]); + } + + FspDeviceDeleteList(DeviceObjects, DeviceObjectCount); + + Irp->IoStatus.Information = VolumeList.Length; + return Result; +} + NTSTATUS FspVolumeTransact( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) {