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)
{