diff --git a/build/VStudio/winfsp_dll.vcxproj b/build/VStudio/winfsp_dll.vcxproj
index 01207f5b..aa32d799 100644
--- a/build/VStudio/winfsp_dll.vcxproj
+++ b/build/VStudio/winfsp_dll.vcxproj
@@ -51,6 +51,7 @@
+
diff --git a/build/VStudio/winfsp_dll.vcxproj.filters b/build/VStudio/winfsp_dll.vcxproj.filters
index cac6502a..a1788ed2 100644
--- a/build/VStudio/winfsp_dll.vcxproj.filters
+++ b/build/VStudio/winfsp_dll.vcxproj.filters
@@ -160,6 +160,9 @@
Source\ku
+
+ Source
+
diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h
index 0aedf2b3..45f1e40d 100644
--- a/inc/winfsp/fsctl.h
+++ b/inc/winfsp/fsctl.h
@@ -610,6 +610,20 @@ FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle);
FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath,
PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize);
FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath);
+
+typedef struct
+{
+ /* in */
+ HANDLE VolumeHandle; /* volume handle returned by FspFsctlCreateVolume */
+ PWSTR VolumeName; /* volume name returned by FspFsctlCreateVolume */
+ PSECURITY_DESCRIPTOR Security; /* optional: security descriptor for directories */
+ UINT64 Reserved; /* reserved for future use */
+ /* in/out */
+ PWSTR MountPoint; /* FspMountSet sets drive in buffer when passed "*:" */
+ HANDLE MountHandle; /* FspMountSet sets, FspMountRemove uses */
+} FSP_MOUNT_DESC;
+FSP_API NTSTATUS FspMountSet(FSP_MOUNT_DESC *Desc);
+FSP_API NTSTATUS FspMountRemove(FSP_MOUNT_DESC *Desc);
#endif
#ifdef __cplusplus
diff --git a/src/dll/fs.c b/src/dll/fs.c
index fb23f25e..18ba35a3 100644
--- a/src/dll/fs.c
+++ b/src/dll/fs.c
@@ -32,35 +32,11 @@ 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;
}
@@ -198,420 +174,6 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem)
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 FspFileSystemMountmgrControl(ULONG IoControlCode,
- PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, PULONG POutputBufferLength)
-{
- HANDLE MgrHandle = INVALID_HANDLE_VALUE;
- DWORD Bytes = 0;
- NTSTATUS Result;
-
- if (0 == POutputBufferLength)
- POutputBufferLength = &Bytes;
-
- MgrHandle = CreateFileW(L"\\\\.\\MountPointManager",
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- 0,
- OPEN_EXISTING,
- 0,
- 0);
- if (INVALID_HANDLE_VALUE == MgrHandle)
- {
- Result = FspNtStatusFromWin32(GetLastError());
- goto exit;
- }
-
- if (!DeviceIoControl(MgrHandle,
- IoControlCode,
- InputBuffer, InputBufferLength, OutputBuffer, *POutputBufferLength,
- &Bytes, 0))
- {
- Result = FspNtStatusFromWin32(GetLastError());
- goto exit;
- }
-
- *POutputBufferLength = Bytes;
- Result = STATUS_SUCCESS;
-
-exit:
- if (INVALID_HANDLE_VALUE != MgrHandle)
- CloseHandle(MgrHandle);
-
- return Result;
-}
-
-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;
-}
-
-static NTSTATUS FspFileSystemSetMountPoint_Mountmgr(PWSTR MountPoint, PWSTR VolumeName,
- HANDLE VolumeHandle)
-{
- /* only support drives for now! (format: \\.\X:) */
- if (L'\0' != MountPoint[6])
- return STATUS_INVALID_PARAMETER;
-
- /* mountmgr.h */
- typedef enum
- {
- Disabled = 0,
- Enabled,
- } MOUNTMGR_AUTO_MOUNT_STATE;
- typedef struct
- {
- MOUNTMGR_AUTO_MOUNT_STATE CurrentState;
- } MOUNTMGR_QUERY_AUTO_MOUNT;
- typedef struct
- {
- MOUNTMGR_AUTO_MOUNT_STATE NewState;
- } MOUNTMGR_SET_AUTO_MOUNT;
- typedef struct
- {
- USHORT DeviceNameLength;
- WCHAR DeviceName[1];
- } MOUNTMGR_TARGET_NAME;
- typedef struct
- {
- USHORT SymbolicLinkNameOffset;
- USHORT SymbolicLinkNameLength;
- USHORT DeviceNameOffset;
- USHORT DeviceNameLength;
- } MOUNTMGR_CREATE_POINT_INPUT;
-
- GUID UniqueId;
- MOUNTMGR_QUERY_AUTO_MOUNT QueryAutoMount;
- MOUNTMGR_SET_AUTO_MOUNT SetAutoMount;
- MOUNTMGR_TARGET_NAME *TargetName = 0;
- MOUNTMGR_CREATE_POINT_INPUT *CreatePointInput = 0;
- ULONG VolumeNameSize, QueryAutoMountSize, TargetNameSize, CreatePointInputSize;
- HKEY RegKey;
- LONG RegResult;
- WCHAR RegValueName[MAX_PATH];
- UINT8 RegValueData[sizeof UniqueId];
- DWORD RegValueNameSize, RegValueDataSize;
- DWORD RegType;
- NTSTATUS Result;
-
- /* transform our volume into one that can be used by the MountManager */
- Result = FspFsctlMakeMountdev(VolumeHandle, FALSE, &UniqueId);
- if (!NT_SUCCESS(Result))
- goto exit;
-
- VolumeNameSize = lstrlenW(VolumeName) * sizeof(WCHAR);
- QueryAutoMountSize = sizeof QueryAutoMount;
- TargetNameSize = FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + VolumeNameSize;
- CreatePointInputSize = sizeof *CreatePointInput +
- sizeof L"\\DosDevices\\X:" - sizeof(WCHAR) + VolumeNameSize;
-
- TargetName = MemAlloc(TargetNameSize);
- if (0 == TargetName)
- {
- Result = STATUS_INSUFFICIENT_RESOURCES;
- goto exit;
- }
-
- CreatePointInput = MemAlloc(CreatePointInputSize);
- if (0 == CreatePointInput)
- {
- Result = STATUS_INSUFFICIENT_RESOURCES;
- goto exit;
- }
-
- /* query the current AutoMount value and save it */
- Result = FspFileSystemMountmgrControl(
- CTL_CODE('m', 15, METHOD_BUFFERED, FILE_ANY_ACCESS),
- /* IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT */
- 0, 0, &QueryAutoMount, &QueryAutoMountSize);
- if (!NT_SUCCESS(Result))
- goto exit;
-
- /* disable AutoMount */
- SetAutoMount.NewState = 0;
- Result = FspFileSystemMountmgrControl(
- CTL_CODE('m', 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
- /* IOCTL_MOUNTMGR_SET_AUTO_MOUNT */
- &SetAutoMount, sizeof SetAutoMount, 0, 0);
- if (!NT_SUCCESS(Result))
- goto exit;
-
- /* announce volume arrival */
- memset(TargetName, 0, sizeof *TargetName);
- TargetName->DeviceNameLength = (USHORT)VolumeNameSize;
- memcpy(TargetName->DeviceName,
- VolumeName, TargetName->DeviceNameLength);
- Result = FspFileSystemMountmgrControl(
- CTL_CODE('m', 11, METHOD_BUFFERED, FILE_READ_ACCESS),
- /* IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION */
- TargetName, TargetNameSize, 0, 0);
- if (!NT_SUCCESS(Result))
- goto exit;
-
- /* reset the AutoMount value to the saved one */
- SetAutoMount.NewState = QueryAutoMount.CurrentState;
- FspFileSystemMountmgrControl(
- CTL_CODE('m', 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
- /* IOCTL_MOUNTMGR_SET_AUTO_MOUNT */
- &SetAutoMount, sizeof SetAutoMount, 0, 0);
-#if 0
- if (!NT_SUCCESS(Result))
- goto exit;
-#endif
-
- /* create mount point */
- memset(CreatePointInput, 0, sizeof *CreatePointInput);
- CreatePointInput->SymbolicLinkNameOffset = sizeof *CreatePointInput;
- CreatePointInput->SymbolicLinkNameLength = sizeof L"\\DosDevices\\X:" - sizeof(WCHAR);
- CreatePointInput->DeviceNameOffset =
- CreatePointInput->SymbolicLinkNameOffset + CreatePointInput->SymbolicLinkNameLength;
- CreatePointInput->DeviceNameLength = (USHORT)VolumeNameSize;
- memcpy((PUINT8)CreatePointInput + CreatePointInput->SymbolicLinkNameOffset,
- L"\\DosDevices\\X:", CreatePointInput->SymbolicLinkNameLength);
- ((PWCHAR)((PUINT8)CreatePointInput + CreatePointInput->SymbolicLinkNameOffset))[12] =
- MountPoint[4] & ~0x20;
- /* convert to uppercase */
- memcpy((PUINT8)CreatePointInput + CreatePointInput->DeviceNameOffset,
- VolumeName, CreatePointInput->DeviceNameLength);
- Result = FspFileSystemMountmgrControl(
- CTL_CODE('m', 0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
- /* IOCTL_MOUNTMGR_CREATE_POINT */
- CreatePointInput, CreatePointInputSize, 0, 0);
- if (!NT_SUCCESS(Result))
- goto exit;
-
- /* HACK: delete the MountManager registry entries */
- RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\MountedDevices",
- 0, KEY_READ | KEY_WRITE, &RegKey);
- if (ERROR_SUCCESS == RegResult)
- {
- for (DWORD I = 0;; I++)
- {
- RegValueNameSize = MAX_PATH;
- RegValueDataSize = sizeof RegValueData;
- RegResult = RegEnumValueW(RegKey,
- I, RegValueName, &RegValueNameSize, 0, &RegType, RegValueData, &RegValueDataSize);
- if (ERROR_NO_MORE_ITEMS == RegResult)
- break;
- else if (ERROR_SUCCESS != RegResult)
- continue;
-
- if (REG_BINARY == RegType &&
- sizeof RegValueData == RegValueDataSize &&
- InlineIsEqualGUID((GUID *)&RegValueData, &UniqueId))
- {
- RegResult = RegDeleteValueW(RegKey, RegValueName);
- if (ERROR_SUCCESS == RegResult)
- /* reset index after modifying key; only safe way to use RegEnumValueW with modifications */
- I = -1;
- }
- }
-
- RegCloseKey(RegKey);
- }
-
- Result = STATUS_SUCCESS;
-
-exit:
- MemFree(CreatePointInput);
- MemFree(TargetName);
-
- return Result;
-}
-
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint)
{
return FspFileSystemSetMountPointEx(FileSystem, MountPoint, 0);
@@ -623,175 +185,55 @@ FSP_API NTSTATUS FspFileSystemSetMountPointEx(FSP_FILE_SYSTEM *FileSystem, PWSTR
if (0 != FileSystem->MountPoint)
return STATUS_INVALID_PARAMETER;
+ FSP_MOUNT_DESC Desc;
+ int Size;
NTSTATUS Result;
- HANDLE MountHandle = 0;
+
+ memset(&Desc, 0, sizeof Desc);
+ Desc.VolumeHandle = FileSystem->VolumeHandle;
+ Desc.VolumeName = FileSystem->VolumeName;
+ Desc.Security = SecurityDescriptor;
if (0 == MountPoint)
+ MountPoint = L"*:";
+
+ Size = (lstrlenW(MountPoint) + 1) * sizeof(WCHAR);
+ Desc.MountPoint = MemAlloc(Size);
+ if (0 == Desc.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());
+ Result = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit;
}
- else
- {
- PWSTR P;
- ULONG L;
+ memcpy(Desc.MountPoint, MountPoint, Size);
- L = (ULONG)((lstrlenW(MountPoint) + 1) * sizeof(WCHAR));
-
- P = MemAlloc(L);
- if (0 == P)
- return STATUS_INSUFFICIENT_RESOURCES;
- memcpy(P, MountPoint, L);
- MountPoint = P;
-
- if (FspPathIsMountmgrMountPoint(MountPoint))
- Result = FspFileSystemSetMountPoint_Mountmgr(MountPoint, FileSystem->VolumeName,
- FileSystem->VolumeHandle);
- else if (FspPathIsDrive(MountPoint))
- Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
- &MountHandle);
- else
- Result = FspFileSystemSetMountPoint_Directory(MountPoint, FileSystem->VolumeName,
- SecurityDescriptor, &MountHandle);
- }
+ Result = FspMountSet(&Desc);
exit:
if (NT_SUCCESS(Result))
{
- FileSystem->MountPoint = MountPoint;
- FileSystem->MountHandle = MountHandle;
+ FileSystem->MountPoint = Desc.MountPoint;
+ FileSystem->MountHandle = Desc.MountHandle;
}
else
- MemFree(MountPoint);
+ MemFree(Desc.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);
-}
-
-static VOID FspFileSystemRemoveMountPoint_Mountmgr(PWSTR MountPoint)
-{
- /* mountmgr.h */
- typedef struct
- {
- ULONG SymbolicLinkNameOffset;
- USHORT SymbolicLinkNameLength;
- USHORT Reserved1;
- ULONG UniqueIdOffset;
- USHORT UniqueIdLength;
- USHORT Reserved2;
- ULONG DeviceNameOffset;
- USHORT DeviceNameLength;
- USHORT Reserved3;
- } MOUNTMGR_MOUNT_POINT;
- typedef struct
- {
- ULONG Size;
- ULONG NumberOfMountPoints;
- MOUNTMGR_MOUNT_POINT MountPoints[1];
- } MOUNTMGR_MOUNT_POINTS;
-
- MOUNTMGR_MOUNT_POINT *Input = 0;
- MOUNTMGR_MOUNT_POINTS *Output = 0;
- ULONG InputSize, OutputSize;
- NTSTATUS Result;
-
- InputSize = sizeof *Input + sizeof L"\\DosDevices\\X:" - sizeof(WCHAR);
- OutputSize = 4096;
-
- Input = MemAlloc(InputSize);
- if (0 == Input)
- {
- Result = STATUS_INSUFFICIENT_RESOURCES;
- goto exit;
- }
-
- Output = MemAlloc(OutputSize);
- if (0 == Output)
- {
- Result = STATUS_INSUFFICIENT_RESOURCES;
- goto exit;
- }
-
- memset(Input, 0, sizeof *Input);
- Input->SymbolicLinkNameOffset = sizeof *Input;
- Input->SymbolicLinkNameLength = sizeof L"\\DosDevices\\X:" - sizeof(WCHAR);
- memcpy((PUINT8)Input + Input->SymbolicLinkNameOffset,
- L"\\DosDevices\\X:", Input->SymbolicLinkNameLength);
- ((PWCHAR)((PUINT8)Input + Input->SymbolicLinkNameOffset))[12] = MountPoint[4] & ~0x20;
- /* convert to uppercase */
- Result = FspFileSystemMountmgrControl(
- CTL_CODE('m', 1, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
- /* IOCTL_MOUNTMGR_DELETE_POINTS */
- Input, InputSize, Output, &OutputSize);
- if (!NT_SUCCESS(Result))
- goto exit;
-
- Result = STATUS_SUCCESS;
-
-exit:
- MemFree(Output);
- MemFree(Input);
-}
-
FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
{
if (0 == FileSystem->MountPoint)
return;
- if (FspPathIsMountmgrMountPoint(FileSystem->MountPoint))
- FspFileSystemRemoveMountPoint_Mountmgr(FileSystem->MountPoint);
- else if (FspPathIsDrive(FileSystem->MountPoint))
- FspFileSystemRemoveMountPoint_Drive(FileSystem->MountPoint, FileSystem->VolumeName,
- FileSystem->MountHandle);
- else
- FspFileSystemRemoveMountPoint_Directory(FileSystem->MountHandle);
+ FSP_MOUNT_DESC Desc;
+
+ memset(&Desc, 0, sizeof Desc);
+ Desc.VolumeHandle = FileSystem->VolumeHandle;
+ Desc.VolumeName = FileSystem->VolumeName;
+ Desc.MountPoint = FileSystem->MountPoint;
+ Desc.MountHandle = FileSystem->MountHandle;
+
+ FspMountRemove(&Desc);
MemFree(FileSystem->MountPoint);
FileSystem->MountPoint = 0;
diff --git a/src/dll/mount.c b/src/dll/mount.c
new file mode 100644
index 00000000..72d92ad1
--- /dev/null
+++ b/src/dll/mount.c
@@ -0,0 +1,612 @@
+/**
+ * @file dll/mount.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
+
+static INIT_ONCE FspMountInitOnce = INIT_ONCE_STATIC_INIT;
+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 FspMountInitialize(
+ PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
+{
+ HANDLE Handle;
+
+ 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;
+}
+
+static NTSTATUS FspMountmgrControl(ULONG IoControlCode,
+ PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, PULONG POutputBufferLength)
+{
+ HANDLE MgrHandle = INVALID_HANDLE_VALUE;
+ DWORD Bytes = 0;
+ NTSTATUS Result;
+
+ if (0 == POutputBufferLength)
+ POutputBufferLength = &Bytes;
+
+ MgrHandle = CreateFileW(L"\\\\.\\MountPointManager",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0,
+ OPEN_EXISTING,
+ 0,
+ 0);
+ if (INVALID_HANDLE_VALUE == MgrHandle)
+ {
+ Result = FspNtStatusFromWin32(GetLastError());
+ goto exit;
+ }
+
+ if (!DeviceIoControl(MgrHandle,
+ IoControlCode,
+ InputBuffer, InputBufferLength, OutputBuffer, *POutputBufferLength,
+ &Bytes, 0))
+ {
+ Result = FspNtStatusFromWin32(GetLastError());
+ goto exit;
+ }
+
+ *POutputBufferLength = Bytes;
+ Result = STATUS_SUCCESS;
+
+exit:
+ if (INVALID_HANDLE_VALUE != MgrHandle)
+ CloseHandle(MgrHandle);
+
+ return Result;
+}
+
+static NTSTATUS FspMountSet_Mountmgr(HANDLE VolumeHandle, PWSTR VolumeName, PWSTR MountPoint)
+{
+ /* only support drives for now! (format: \\.\X:) */
+ if (L'\0' != MountPoint[6])
+ return STATUS_INVALID_PARAMETER;
+
+ /* mountmgr.h */
+ typedef enum
+ {
+ Disabled = 0,
+ Enabled,
+ } MOUNTMGR_AUTO_MOUNT_STATE;
+ typedef struct
+ {
+ MOUNTMGR_AUTO_MOUNT_STATE CurrentState;
+ } MOUNTMGR_QUERY_AUTO_MOUNT;
+ typedef struct
+ {
+ MOUNTMGR_AUTO_MOUNT_STATE NewState;
+ } MOUNTMGR_SET_AUTO_MOUNT;
+ typedef struct
+ {
+ USHORT DeviceNameLength;
+ WCHAR DeviceName[1];
+ } MOUNTMGR_TARGET_NAME;
+ typedef struct
+ {
+ USHORT SymbolicLinkNameOffset;
+ USHORT SymbolicLinkNameLength;
+ USHORT DeviceNameOffset;
+ USHORT DeviceNameLength;
+ } MOUNTMGR_CREATE_POINT_INPUT;
+
+ GUID UniqueId;
+ MOUNTMGR_QUERY_AUTO_MOUNT QueryAutoMount;
+ MOUNTMGR_SET_AUTO_MOUNT SetAutoMount;
+ MOUNTMGR_TARGET_NAME *TargetName = 0;
+ MOUNTMGR_CREATE_POINT_INPUT *CreatePointInput = 0;
+ ULONG VolumeNameSize, QueryAutoMountSize, TargetNameSize, CreatePointInputSize;
+ HKEY RegKey;
+ LONG RegResult;
+ WCHAR RegValueName[MAX_PATH];
+ UINT8 RegValueData[sizeof UniqueId];
+ DWORD RegValueNameSize, RegValueDataSize;
+ DWORD RegType;
+ NTSTATUS Result;
+
+ /* transform our volume into one that can be used by the MountManager */
+ Result = FspFsctlMakeMountdev(VolumeHandle, FALSE, &UniqueId);
+ if (!NT_SUCCESS(Result))
+ goto exit;
+
+ VolumeNameSize = lstrlenW(VolumeName) * sizeof(WCHAR);
+ QueryAutoMountSize = sizeof QueryAutoMount;
+ TargetNameSize = FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + VolumeNameSize;
+ CreatePointInputSize = sizeof *CreatePointInput +
+ sizeof L"\\DosDevices\\X:" - sizeof(WCHAR) + VolumeNameSize;
+
+ TargetName = MemAlloc(TargetNameSize);
+ if (0 == TargetName)
+ {
+ Result = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit;
+ }
+
+ CreatePointInput = MemAlloc(CreatePointInputSize);
+ if (0 == CreatePointInput)
+ {
+ Result = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit;
+ }
+
+ /* query the current AutoMount value and save it */
+ Result = FspMountmgrControl(
+ CTL_CODE('m', 15, METHOD_BUFFERED, FILE_ANY_ACCESS),
+ /* IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT */
+ 0, 0, &QueryAutoMount, &QueryAutoMountSize);
+ if (!NT_SUCCESS(Result))
+ goto exit;
+
+ /* disable AutoMount */
+ SetAutoMount.NewState = 0;
+ Result = FspMountmgrControl(
+ CTL_CODE('m', 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
+ /* IOCTL_MOUNTMGR_SET_AUTO_MOUNT */
+ &SetAutoMount, sizeof SetAutoMount, 0, 0);
+ if (!NT_SUCCESS(Result))
+ goto exit;
+
+ /* announce volume arrival */
+ memset(TargetName, 0, sizeof *TargetName);
+ TargetName->DeviceNameLength = (USHORT)VolumeNameSize;
+ memcpy(TargetName->DeviceName,
+ VolumeName, TargetName->DeviceNameLength);
+ Result = FspMountmgrControl(
+ CTL_CODE('m', 11, METHOD_BUFFERED, FILE_READ_ACCESS),
+ /* IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION */
+ TargetName, TargetNameSize, 0, 0);
+ if (!NT_SUCCESS(Result))
+ goto exit;
+
+ /* reset the AutoMount value to the saved one */
+ SetAutoMount.NewState = QueryAutoMount.CurrentState;
+ FspMountmgrControl(
+ CTL_CODE('m', 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
+ /* IOCTL_MOUNTMGR_SET_AUTO_MOUNT */
+ &SetAutoMount, sizeof SetAutoMount, 0, 0);
+#if 0
+ if (!NT_SUCCESS(Result))
+ goto exit;
+#endif
+
+ /* create mount point */
+ memset(CreatePointInput, 0, sizeof *CreatePointInput);
+ CreatePointInput->SymbolicLinkNameOffset = sizeof *CreatePointInput;
+ CreatePointInput->SymbolicLinkNameLength = sizeof L"\\DosDevices\\X:" - sizeof(WCHAR);
+ CreatePointInput->DeviceNameOffset =
+ CreatePointInput->SymbolicLinkNameOffset + CreatePointInput->SymbolicLinkNameLength;
+ CreatePointInput->DeviceNameLength = (USHORT)VolumeNameSize;
+ memcpy((PUINT8)CreatePointInput + CreatePointInput->SymbolicLinkNameOffset,
+ L"\\DosDevices\\X:", CreatePointInput->SymbolicLinkNameLength);
+ ((PWCHAR)((PUINT8)CreatePointInput + CreatePointInput->SymbolicLinkNameOffset))[12] =
+ MountPoint[4] & ~0x20;
+ /* convert to uppercase */
+ memcpy((PUINT8)CreatePointInput + CreatePointInput->DeviceNameOffset,
+ VolumeName, CreatePointInput->DeviceNameLength);
+ Result = FspMountmgrControl(
+ CTL_CODE('m', 0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
+ /* IOCTL_MOUNTMGR_CREATE_POINT */
+ CreatePointInput, CreatePointInputSize, 0, 0);
+ if (!NT_SUCCESS(Result))
+ goto exit;
+
+ /* HACK: delete the MountManager registry entries */
+ RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\MountedDevices",
+ 0, KEY_READ | KEY_WRITE, &RegKey);
+ if (ERROR_SUCCESS == RegResult)
+ {
+ for (DWORD I = 0;; I++)
+ {
+ RegValueNameSize = MAX_PATH;
+ RegValueDataSize = sizeof RegValueData;
+ RegResult = RegEnumValueW(RegKey,
+ I, RegValueName, &RegValueNameSize, 0, &RegType, RegValueData, &RegValueDataSize);
+ if (ERROR_NO_MORE_ITEMS == RegResult)
+ break;
+ else if (ERROR_SUCCESS != RegResult)
+ continue;
+
+ if (REG_BINARY == RegType &&
+ sizeof RegValueData == RegValueDataSize &&
+ InlineIsEqualGUID((GUID *)&RegValueData, &UniqueId))
+ {
+ RegResult = RegDeleteValueW(RegKey, RegValueName);
+ if (ERROR_SUCCESS == RegResult)
+ /* reset index after modifying key; only safe way to use RegEnumValueW with modifications */
+ I = -1;
+ }
+ }
+
+ RegCloseKey(RegKey);
+ }
+
+ Result = STATUS_SUCCESS;
+
+exit:
+ MemFree(CreatePointInput);
+ MemFree(TargetName);
+
+ return Result;
+}
+
+static NTSTATUS FspMountRemove_Mountmgr(PWSTR MountPoint)
+{
+ /* mountmgr.h */
+ typedef struct
+ {
+ ULONG SymbolicLinkNameOffset;
+ USHORT SymbolicLinkNameLength;
+ USHORT Reserved1;
+ ULONG UniqueIdOffset;
+ USHORT UniqueIdLength;
+ USHORT Reserved2;
+ ULONG DeviceNameOffset;
+ USHORT DeviceNameLength;
+ USHORT Reserved3;
+ } MOUNTMGR_MOUNT_POINT;
+ typedef struct
+ {
+ ULONG Size;
+ ULONG NumberOfMountPoints;
+ MOUNTMGR_MOUNT_POINT MountPoints[1];
+ } MOUNTMGR_MOUNT_POINTS;
+
+ MOUNTMGR_MOUNT_POINT *Input = 0;
+ MOUNTMGR_MOUNT_POINTS *Output = 0;
+ ULONG InputSize, OutputSize;
+ NTSTATUS Result;
+
+ InputSize = sizeof *Input + sizeof L"\\DosDevices\\X:" - sizeof(WCHAR);
+ OutputSize = 4096;
+
+ Input = MemAlloc(InputSize);
+ if (0 == Input)
+ {
+ Result = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit;
+ }
+
+ Output = MemAlloc(OutputSize);
+ if (0 == Output)
+ {
+ Result = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit;
+ }
+
+ memset(Input, 0, sizeof *Input);
+ Input->SymbolicLinkNameOffset = sizeof *Input;
+ Input->SymbolicLinkNameLength = sizeof L"\\DosDevices\\X:" - sizeof(WCHAR);
+ memcpy((PUINT8)Input + Input->SymbolicLinkNameOffset,
+ L"\\DosDevices\\X:", Input->SymbolicLinkNameLength);
+ ((PWCHAR)((PUINT8)Input + Input->SymbolicLinkNameOffset))[12] = MountPoint[4] & ~0x20;
+ /* convert to uppercase */
+ Result = FspMountmgrControl(
+ CTL_CODE('m', 1, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
+ /* IOCTL_MOUNTMGR_DELETE_POINTS */
+ Input, InputSize, Output, &OutputSize);
+ if (!NT_SUCCESS(Result))
+ goto exit;
+
+ Result = STATUS_SUCCESS;
+
+exit:
+ MemFree(Output);
+ MemFree(Input);
+
+ return Result;
+}
+
+static NTSTATUS FspLauncherDefineDosDevice(
+ 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 FspMountSet_Drive(PWSTR VolumeName, PWSTR MountPoint, 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 = FspLauncherDefineDosDevice(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 FspMountRemove_Drive(PWSTR VolumeName, PWSTR MountPoint, HANDLE MountHandle)
+{
+ NTSTATUS Result;
+ BOOLEAN IsServiceContext;
+
+ 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.
+ */
+ Result = FspLauncherDefineDosDevice(L'-', MountPoint, VolumeName);
+ else
+ Result = DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
+ MountPoint, VolumeName) ? STATUS_SUCCESS : FspNtStatusFromWin32(GetLastError());
+
+ if (0 != MountHandle)
+ FspNtClose(MountHandle);
+
+ return Result;
+}
+
+static NTSTATUS FspMountSet_Directory(PWSTR VolumeName, PWSTR MountPoint,
+ 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;
+}
+
+static NTSTATUS FspMountRemove_Directory(HANDLE MountHandle)
+{
+ /* directory is marked DELETE_ON_CLOSE */
+ return CloseHandle(MountHandle) ? STATUS_SUCCESS : FspNtStatusFromWin32(GetLastError());
+}
+
+FSP_API NTSTATUS FspMountSet(FSP_MOUNT_DESC *Desc)
+{
+ InitOnceExecuteOnce(&FspMountInitOnce, FspMountInitialize, 0, 0);
+
+ Desc->MountHandle = 0;
+
+ if (L'*' == Desc->MountPoint[0] && ':' == Desc->MountPoint[1] && L'\0' == Desc->MountPoint[2])
+ {
+ NTSTATUS Result;
+ DWORD Drives;
+ WCHAR Drive;
+
+ Drives = GetLogicalDrives();
+ if (0 == Drives)
+ return FspNtStatusFromWin32(GetLastError());
+
+ for (Drive = 'Z'; 'D' <= Drive; Drive--)
+ if (0 == (Drives & (1 << (Drive - 'A'))))
+ {
+ Desc->MountPoint[0] = Drive;
+ Result = FspMountSet_Drive(Desc->VolumeName, Desc->MountPoint,
+ &Desc->MountHandle);
+ if (NT_SUCCESS(Result))
+ return Result;
+ }
+ Desc->MountPoint[0] = L'*';
+ return STATUS_NO_SUCH_DEVICE;
+ }
+ else if (FspPathIsMountmgrMountPoint(Desc->MountPoint))
+ return FspMountSet_Mountmgr(Desc->VolumeHandle, Desc->VolumeName, Desc->MountPoint);
+ else if (FspPathIsDrive(Desc->MountPoint))
+ return FspMountSet_Drive(Desc->VolumeName, Desc->MountPoint,
+ &Desc->MountHandle);
+ else
+ return FspMountSet_Directory(Desc->VolumeName, Desc->MountPoint, Desc->Security,
+ &Desc->MountHandle);
+}
+
+FSP_API NTSTATUS FspMountRemove(FSP_MOUNT_DESC *Desc)
+{
+ InitOnceExecuteOnce(&FspMountInitOnce, FspMountInitialize, 0, 0);
+
+ if (FspPathIsMountmgrMountPoint(Desc->MountPoint))
+ return FspMountRemove_Mountmgr(Desc->MountPoint);
+ else if (FspPathIsDrive(Desc->MountPoint))
+ return FspMountRemove_Drive(Desc->VolumeName, Desc->MountPoint, Desc->MountHandle);
+ else
+ return FspMountRemove_Directory(Desc->MountHandle);
+}