mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
Merge branch 'pvt-sqlfix2'
This commit is contained in:
commit
1d15c9546b
@ -204,7 +204,9 @@
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\security-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\uuid5-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\version-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\volpath-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\winfsp-tests.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\wsl-test.c" />
|
||||
</ItemGroup>
|
||||
|
@ -103,6 +103,12 @@
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\launcher-ptrans-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\volpath-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\uuid5-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
|
||||
|
@ -105,7 +105,7 @@
|
||||
<PreprocessorDefinitions> _X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>cng.lib;wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||
@ -118,7 +118,7 @@
|
||||
<PreprocessorDefinitions> _X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>cng.lib;wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||
@ -131,7 +131,7 @@
|
||||
<PreprocessorDefinitions> _WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>cng.lib;wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||
@ -144,7 +144,7 @@
|
||||
<PreprocessorDefinitions> _WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>cng.lib;wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
|
||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||
@ -156,6 +156,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\ku\posix.c" />
|
||||
<ClCompile Include="..\..\src\ku\uuid5.c" />
|
||||
<ClCompile Include="..\..\src\sys\cleanup.c" />
|
||||
<ClCompile Include="..\..\src\sys\close.c" />
|
||||
<ClCompile Include="..\..\src\sys\create.c" />
|
||||
@ -175,6 +176,7 @@
|
||||
<ClCompile Include="..\..\src\sys\ioq.c" />
|
||||
<ClCompile Include="..\..\src\sys\lockctl.c" />
|
||||
<ClCompile Include="..\..\src\sys\meta.c" />
|
||||
<ClCompile Include="..\..\src\sys\mountdev.c" />
|
||||
<ClCompile Include="..\..\src\sys\mup.c" />
|
||||
<ClCompile Include="..\..\src\sys\name.c" />
|
||||
<ClCompile Include="..\..\src\sys\psbuffer.c" />
|
||||
|
@ -113,6 +113,12 @@
|
||||
<ClCompile Include="..\..\src\ku\posix.c">
|
||||
<Filter>Source\ku</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ku\uuid5.c">
|
||||
<Filter>Source\ku</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\sys\mountdev.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\sys\driver.h">
|
||||
|
@ -54,6 +54,8 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
|
||||
#define FSP_FSCTL_DECLSPEC_ALIGN __declspec(align(FSP_FSCTL_DEFAULT_ALIGNMENT))
|
||||
|
||||
/* fsctl device codes */
|
||||
#define FSP_FSCTL_MOUNTDEV \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'M', METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_VOLUME_NAME \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'N', METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_VOLUME_LIST \
|
||||
@ -598,6 +600,8 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
|
||||
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
|
||||
PWCHAR VolumeNameBuf, SIZE_T VolumeNameSize,
|
||||
PHANDLE PVolumeHandle);
|
||||
FSP_API NTSTATUS FspFsctlMakeMountdev(HANDLE VolumeHandle,
|
||||
BOOLEAN Persistent, GUID *UniqueId);
|
||||
FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle,
|
||||
PVOID ResponseBuf, SIZE_T ResponseBufSize,
|
||||
PVOID RequestBuf, SIZE_T *PRequestBufSize,
|
||||
|
220
src/dll/fs.c
220
src/dll/fs.c
@ -93,7 +93,9 @@ FSP_API NTSTATUS FspFileSystemPreflight(PWSTR DevicePath,
|
||||
Result = STATUS_SUCCESS;
|
||||
else
|
||||
{
|
||||
if (FspPathIsDrive(MountPoint))
|
||||
if (FspPathIsMountmgrMountPoint(MountPoint))
|
||||
Result = STATUS_SUCCESS; /* cannot check with the mount manager, assume success */
|
||||
else if (FspPathIsDrive(MountPoint))
|
||||
Result = QueryDosDeviceW(MountPoint, TargetPath, MAX_PATH) ?
|
||||
STATUS_OBJECT_NAME_COLLISION : STATUS_SUCCESS;
|
||||
else
|
||||
@ -220,6 +222,48 @@ static NTSTATUS FspFileSystemLauncherDefineDosDevice(
|
||||
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)
|
||||
{
|
||||
@ -395,6 +439,105 @@ exit:
|
||||
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 struct
|
||||
{
|
||||
USHORT SymbolicLinkNameOffset;
|
||||
USHORT SymbolicLinkNameLength;
|
||||
USHORT DeviceNameOffset;
|
||||
USHORT DeviceNameLength;
|
||||
} MOUNTMGR_CREATE_POINT_INPUT;
|
||||
|
||||
GUID UniqueId;
|
||||
MOUNTMGR_CREATE_POINT_INPUT *Input = 0;
|
||||
ULONG VolumeNameSize, InputSize;
|
||||
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);
|
||||
InputSize = sizeof *Input + sizeof L"\\DosDevices\\X:" - sizeof(WCHAR) + VolumeNameSize;
|
||||
|
||||
Input = MemAlloc(InputSize);
|
||||
if (0 == Input)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memset(Input, 0, sizeof *Input);
|
||||
Input->SymbolicLinkNameOffset = sizeof *Input;
|
||||
Input->SymbolicLinkNameLength = sizeof L"\\DosDevices\\X:" - sizeof(WCHAR);
|
||||
Input->DeviceNameOffset = Input->SymbolicLinkNameOffset + Input->SymbolicLinkNameLength;
|
||||
Input->DeviceNameLength = (USHORT)VolumeNameSize;
|
||||
memcpy((PUINT8)Input + Input->SymbolicLinkNameOffset,
|
||||
L"\\DosDevices\\X:", Input->SymbolicLinkNameLength);
|
||||
((PWCHAR)((PUINT8)Input + Input->SymbolicLinkNameOffset))[12] = MountPoint[4] & ~0x20;
|
||||
/* convert to uppercase */
|
||||
memcpy((PUINT8)Input + Input->DeviceNameOffset,
|
||||
VolumeName, Input->DeviceNameLength);
|
||||
|
||||
Result = FspFileSystemMountmgrControl(
|
||||
CTL_CODE('m', 0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
/* IOCTL_MOUNTMGR_CREATE_POINT */
|
||||
Input, InputSize, 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(Input);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint)
|
||||
{
|
||||
return FspFileSystemSetMountPointEx(FileSystem, MountPoint, 0);
|
||||
@ -450,7 +593,10 @@ FSP_API NTSTATUS FspFileSystemSetMountPointEx(FSP_FILE_SYSTEM *FileSystem, PWSTR
|
||||
memcpy(P, MountPoint, L);
|
||||
MountPoint = P;
|
||||
|
||||
if (FspPathIsDrive(MountPoint))
|
||||
if (FspPathIsMountmgrMountPoint(MountPoint))
|
||||
Result = FspFileSystemSetMountPoint_Mountmgr(MountPoint, FileSystem->VolumeName,
|
||||
FileSystem->VolumeHandle);
|
||||
else if (FspPathIsDrive(MountPoint))
|
||||
Result = FspFileSystemSetMountPoint_Drive(MountPoint, FileSystem->VolumeName,
|
||||
&MountHandle);
|
||||
else
|
||||
@ -495,12 +641,80 @@ static VOID FspFileSystemRemoveMountPoint_Directory(HANDLE MountHandle)
|
||||
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 (FspPathIsDrive(FileSystem->MountPoint))
|
||||
if (FspPathIsMountmgrMountPoint(FileSystem->MountPoint))
|
||||
FspFileSystemRemoveMountPoint_Mountmgr(FileSystem->MountPoint);
|
||||
else if (FspPathIsDrive(FileSystem->MountPoint))
|
||||
FspFileSystemRemoveMountPoint_Drive(FileSystem->MountPoint, FileSystem->VolumeName,
|
||||
FileSystem->MountHandle);
|
||||
else
|
||||
|
@ -107,6 +107,20 @@ exit:
|
||||
return Result;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFsctlMakeMountdev(HANDLE VolumeHandle,
|
||||
BOOLEAN Persistent, GUID *UniqueId)
|
||||
{
|
||||
DWORD Bytes;
|
||||
|
||||
if (!DeviceIoControl(VolumeHandle,
|
||||
FSP_FSCTL_MOUNTDEV,
|
||||
&Persistent, sizeof Persistent, UniqueId, sizeof *UniqueId,
|
||||
&Bytes, 0))
|
||||
return FspNtStatusFromWin32(GetLastError());
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle,
|
||||
PVOID ResponseBuf, SIZE_T ResponseBufSize,
|
||||
PVOID RequestBuf, SIZE_T *PRequestBufSize,
|
||||
|
@ -91,6 +91,21 @@ static inline BOOLEAN FspPathIsDrive(PWSTR FileName)
|
||||
) &&
|
||||
L':' == FileName[1] && L'\0' == FileName[2];
|
||||
}
|
||||
static inline BOOLEAN FspPathIsMountmgrMountPoint(PWSTR FileName)
|
||||
{
|
||||
return
|
||||
(
|
||||
L'\\' == FileName[0] &&
|
||||
L'\\' == FileName[1] &&
|
||||
(L'?' == FileName[2] || L'.' == FileName[2]) &&
|
||||
L'\\' == FileName[3]
|
||||
) &&
|
||||
(
|
||||
(L'A' <= FileName[4] && FileName[4] <= L'Z') ||
|
||||
(L'a' <= FileName[4] && FileName[4] <= L'z')
|
||||
) &&
|
||||
L':' == FileName[5];
|
||||
}
|
||||
|
||||
#define FSP_NEXT_EA(Ea, EaEnd) \
|
||||
(0 != (Ea)->NextEntryOffset ? (PVOID)((PUINT8)(Ea) + (Ea)->NextEntryOffset) : (EaEnd))
|
||||
|
134
src/ku/uuid5.c
Normal file
134
src/ku/uuid5.c
Normal file
@ -0,0 +1,134 @@
|
||||
/**
|
||||
* @file dll/uuid5.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 <ku/library.h>
|
||||
#include <bcrypt.h>
|
||||
|
||||
/*
|
||||
* This module is used to create UUID v5 identifiers. UUID v5 identifiers
|
||||
* are effectively SHA1 hashes that are modified to fit within the UUID
|
||||
* format. The resulting identifiers use version 5 and variant 2. The hash
|
||||
* is taken over the concatenation of a namespace ID and a name; the namespace
|
||||
* ID is another UUID and the name can be any string of bytes ("octets").
|
||||
*
|
||||
* For details see RFC 4122: https://tools.ietf.org/html/rfc4122
|
||||
*/
|
||||
|
||||
NTSTATUS FspUuid5Make(const UUID *Namespace, const VOID *Buffer, ULONG Size, UUID *Uuid)
|
||||
{
|
||||
BCRYPT_ALG_HANDLE ProvHandle = 0;
|
||||
BCRYPT_HASH_HANDLE HashHandle = 0;
|
||||
UINT8 Temp[20];
|
||||
NTSTATUS Result;
|
||||
|
||||
/*
|
||||
* Windows UUID's are encoded in little-endian format. RFC 4122 specifies that for
|
||||
* UUID v5 computation, UUID's must be converted to/from big-endian.
|
||||
*
|
||||
* Note that Windows is always little-endian:
|
||||
* https://community.osr.com/discussion/comment/146810/#Comment_146810
|
||||
*/
|
||||
|
||||
/* copy Namespace to local buffer in network byte order (big-endian) */
|
||||
Temp[ 0] = ((PUINT8)Namespace)[ 3];
|
||||
Temp[ 1] = ((PUINT8)Namespace)[ 2];
|
||||
Temp[ 2] = ((PUINT8)Namespace)[ 1];
|
||||
Temp[ 3] = ((PUINT8)Namespace)[ 0];
|
||||
Temp[ 4] = ((PUINT8)Namespace)[ 5];
|
||||
Temp[ 5] = ((PUINT8)Namespace)[ 4];
|
||||
Temp[ 6] = ((PUINT8)Namespace)[ 7];
|
||||
Temp[ 7] = ((PUINT8)Namespace)[ 6];
|
||||
Temp[ 8] = ((PUINT8)Namespace)[ 8];
|
||||
Temp[ 9] = ((PUINT8)Namespace)[ 9];
|
||||
Temp[10] = ((PUINT8)Namespace)[10];
|
||||
Temp[11] = ((PUINT8)Namespace)[11];
|
||||
Temp[12] = ((PUINT8)Namespace)[12];
|
||||
Temp[13] = ((PUINT8)Namespace)[13];
|
||||
Temp[14] = ((PUINT8)Namespace)[14];
|
||||
Temp[15] = ((PUINT8)Namespace)[15];
|
||||
|
||||
/*
|
||||
* Unfortunately we cannot reuse the hashing object, because BCRYPT_HASH_REUSABLE_FLAG
|
||||
* is available in Windows 8 and later. (WinFsp currently supports Windows 7 or later).
|
||||
*/
|
||||
|
||||
Result = BCryptOpenAlgorithmProvider(&ProvHandle, BCRYPT_SHA1_ALGORITHM, 0, 0);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
Result = BCryptCreateHash(ProvHandle, &HashHandle, 0, 0, 0, 0, 0);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
Result = BCryptHashData(HashHandle, (PVOID)Temp, 16, 0);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
Result = BCryptHashData(HashHandle, (PVOID)Buffer, Size, 0);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
Result = BCryptFinishHash(HashHandle, Temp, 20, 0);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
/* copy local buffer to Uuid in host byte order (little-endian) */
|
||||
((PUINT8)Uuid)[ 0] = Temp[ 3];
|
||||
((PUINT8)Uuid)[ 1] = Temp[ 2];
|
||||
((PUINT8)Uuid)[ 2] = Temp[ 1];
|
||||
((PUINT8)Uuid)[ 3] = Temp[ 0];
|
||||
((PUINT8)Uuid)[ 4] = Temp[ 5];
|
||||
((PUINT8)Uuid)[ 5] = Temp[ 4];
|
||||
((PUINT8)Uuid)[ 6] = Temp[ 7];
|
||||
((PUINT8)Uuid)[ 7] = Temp[ 6];
|
||||
((PUINT8)Uuid)[ 8] = Temp[ 8];
|
||||
((PUINT8)Uuid)[ 9] = Temp[ 9];
|
||||
((PUINT8)Uuid)[10] = Temp[10];
|
||||
((PUINT8)Uuid)[11] = Temp[11];
|
||||
((PUINT8)Uuid)[12] = Temp[12];
|
||||
((PUINT8)Uuid)[13] = Temp[13];
|
||||
((PUINT8)Uuid)[14] = Temp[14];
|
||||
((PUINT8)Uuid)[15] = Temp[15];
|
||||
|
||||
/* [RFC 4122 Section 4.3]
|
||||
* Set the four most significant bits (bits 12 through 15) of the
|
||||
* time_hi_and_version field to the appropriate 4-bit version number
|
||||
* from Section 4.1.3.
|
||||
*/
|
||||
Uuid->Data3 = (5 << 12) | (Uuid->Data3 & 0x0fff);
|
||||
|
||||
/* [RFC 4122 Section 4.3]
|
||||
* Set the two most significant bits (bits 6 and 7) of the
|
||||
* clock_seq_hi_and_reserved to zero and one, respectively.
|
||||
*/
|
||||
Uuid->Data4[0] = (2 << 6) | (Uuid->Data4[0] & 0x3f);
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
if (0 != HashHandle)
|
||||
BCryptDestroyHash(HashHandle);
|
||||
|
||||
if (0 != ProvHandle)
|
||||
BCryptCloseAlgorithmProvider(ProvHandle, 0);
|
||||
|
||||
return Result;
|
||||
}
|
@ -23,6 +23,9 @@
|
||||
|
||||
static NTSTATUS FspFsvrtDeviceControl(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
static BOOLEAN FspFsvrtDeviceControlStorageQuery(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||
PNTSTATUS PResult);
|
||||
static NTSTATUS FspFsvolDeviceControl(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
FSP_IOCMPL_DISPATCH FspFsvolDeviceControlComplete;
|
||||
@ -31,6 +34,7 @@ FSP_DRIVER_DISPATCH FspDeviceControl;
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, FspFsvrtDeviceControl)
|
||||
#pragma alloc_text(PAGE, FspFsvrtDeviceControlStorageQuery)
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceControl)
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceControlComplete)
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceControlRequestFini)
|
||||
@ -43,10 +47,18 @@ enum
|
||||
};
|
||||
|
||||
static NTSTATUS FspFsvrtDeviceControl(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
NTSTATUS Result;
|
||||
|
||||
if (FspFsvrtDeviceControlStorageQuery(FsvrtDeviceObject, Irp, IrpSp, &Result))
|
||||
return Result;
|
||||
|
||||
if (FspMountdevDeviceControl(FsvrtDeviceObject, Irp, IrpSp, &Result))
|
||||
return Result;
|
||||
|
||||
/*
|
||||
* Fix GitHub issue #177. All credit for the investigation of this issue
|
||||
* and the suggested steps to reproduce and work around the problem goes
|
||||
@ -64,6 +76,62 @@ static NTSTATUS FspFsvrtDeviceControl(
|
||||
return STATUS_UNRECOGNIZED_VOLUME;
|
||||
}
|
||||
|
||||
static BOOLEAN FspFsvrtDeviceControlStorageQuery(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||
PNTSTATUS PResult)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
/*
|
||||
* SQL Server insists on sending us storage level IOCTL's even though
|
||||
* WinFsp file systems are not on top of a real disk. So bite the bullet
|
||||
* and implement some of those storage IOCTL's to make SQL Server happy.
|
||||
*/
|
||||
|
||||
if (IOCTL_STORAGE_QUERY_PROPERTY != IrpSp->Parameters.DeviceIoControl.IoControlCode ||
|
||||
sizeof(STORAGE_PROPERTY_QUERY) > IrpSp->Parameters.DeviceIoControl.InputBufferLength)
|
||||
return FALSE;
|
||||
|
||||
PSTORAGE_PROPERTY_QUERY Query = Irp->AssociatedIrp.SystemBuffer;
|
||||
switch (Query->PropertyId)
|
||||
{
|
||||
case StorageAccessAlignmentProperty:
|
||||
if (PropertyExistsQuery == Query->QueryType)
|
||||
*PResult = STATUS_SUCCESS;
|
||||
else if (PropertyStandardQuery == Query->QueryType)
|
||||
{
|
||||
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
|
||||
PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR Descriptor = Irp->AssociatedIrp.SystemBuffer;
|
||||
ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||||
|
||||
if (sizeof(STORAGE_DESCRIPTOR_HEADER) > OutputBufferLength)
|
||||
*PResult = STATUS_BUFFER_TOO_SMALL;
|
||||
else if (sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR) > OutputBufferLength)
|
||||
{
|
||||
Descriptor->Version = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
|
||||
Descriptor->Size = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
|
||||
Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
|
||||
*PResult = STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
RtlZeroMemory(Descriptor, sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR));
|
||||
Descriptor->Version = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
|
||||
Descriptor->Size = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
|
||||
Descriptor->BytesPerLogicalSector = FsvrtDeviceExtension->SectorSize;
|
||||
Descriptor->BytesPerPhysicalSector = FsvrtDeviceExtension->SectorSize;
|
||||
Irp->IoStatus.Information = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
|
||||
*PResult = STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
*PResult = STATUS_NOT_SUPPORTED;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolDeviceControl(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
@ -72,6 +140,15 @@ static NTSTATUS FspFsvolDeviceControl(
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
ULONG IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
|
||||
NTSTATUS Result;
|
||||
|
||||
/*
|
||||
* Possibly forward the IOCTL request to the user mode file system. The rules are:
|
||||
*
|
||||
* - File system must support DeviceControl.
|
||||
* - Only IOCTL with custom devices (see DEVICE_TYPE_FROM_CTL_CODE) and
|
||||
* METHOD_BUFFERED will be forwarded.
|
||||
*/
|
||||
|
||||
/* do we support DeviceControl? */
|
||||
if (!FsvolDeviceExtension->VolumeParams.DeviceControl)
|
||||
@ -90,7 +167,6 @@ static NTSTATUS FspFsvolDeviceControl(
|
||||
if (!FspFileNodeIsValid(FileObject->FsContext))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
NTSTATUS Result;
|
||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
||||
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
|
@ -126,10 +126,12 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
|
||||
case FspFsvolDeviceExtensionKind:
|
||||
DeviceExtensionSize = sizeof(FSP_FSVOL_DEVICE_EXTENSION);
|
||||
break;
|
||||
case FspFsvrtDeviceExtensionKind:
|
||||
DeviceExtensionSize = sizeof(FSP_FSVRT_DEVICE_EXTENSION);
|
||||
break;
|
||||
case FspFsmupDeviceExtensionKind:
|
||||
DeviceExtensionSize = sizeof(FSP_FSMUP_DEVICE_EXTENSION);
|
||||
break;
|
||||
case FspFsvrtDeviceExtensionKind:
|
||||
case FspFsctlDeviceExtensionKind:
|
||||
DeviceExtensionSize = sizeof(FSP_DEVICE_EXTENSION);
|
||||
break;
|
||||
@ -184,10 +186,12 @@ NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject)
|
||||
case FspFsvolDeviceExtensionKind:
|
||||
Result = FspFsvolDeviceInit(DeviceObject);
|
||||
break;
|
||||
case FspFsvrtDeviceExtensionKind:
|
||||
Result = STATUS_SUCCESS;
|
||||
break;
|
||||
case FspFsmupDeviceExtensionKind:
|
||||
Result = FspFsmupDeviceInit(DeviceObject);
|
||||
break;
|
||||
case FspFsvrtDeviceExtensionKind:
|
||||
case FspFsctlDeviceExtensionKind:
|
||||
Result = STATUS_SUCCESS;
|
||||
break;
|
||||
@ -213,10 +217,11 @@ VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject)
|
||||
case FspFsvolDeviceExtensionKind:
|
||||
FspFsvolDeviceFini(DeviceObject);
|
||||
break;
|
||||
case FspFsvrtDeviceExtensionKind:
|
||||
break;
|
||||
case FspFsmupDeviceExtensionKind:
|
||||
FspFsmupDeviceFini(DeviceObject);
|
||||
break;
|
||||
case FspFsvrtDeviceExtensionKind:
|
||||
case FspFsctlDeviceExtensionKind:
|
||||
break;
|
||||
default:
|
||||
|
@ -26,6 +26,8 @@
|
||||
|
||||
#define POOL_NX_OPTIN 1
|
||||
#include <ntifs.h>
|
||||
#include <mountdev.h>
|
||||
#include <ntddstor.h>
|
||||
#include <ntstrsafe.h>
|
||||
#include <wdmsec.h>
|
||||
#include <winfsp/fsctl.h>
|
||||
@ -493,6 +495,9 @@ NTSTATUS FspFileNameInExpression(
|
||||
PWCH UpcaseTable,
|
||||
PBOOLEAN PResult);
|
||||
|
||||
/* UUID5 creation (ku) */
|
||||
NTSTATUS FspUuid5Make(const UUID *Namespace, const VOID *Buffer, ULONG Size, UUID *Uuid);
|
||||
|
||||
/* utility */
|
||||
PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag);
|
||||
PVOID FspAllocateIrpMustSucceed(CCHAR StackSize);
|
||||
@ -510,6 +515,8 @@ NTSTATUS FspSendQuerySecurityIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileO
|
||||
NTSTATUS FspSendQueryEaIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
||||
PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
|
||||
PFILE_FULL_EA_INFORMATION Ea, PULONG PEaLength);
|
||||
NTSTATUS FspSendMountmgrDeviceControlIrp(ULONG IoControlCode,
|
||||
PVOID SystemBuffer, ULONG InputBufferLength, PULONG POutputBufferLength);
|
||||
NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
|
||||
NTSTATUS FspLockUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
|
||||
NTSTATUS FspMapLockedPagesInUserMode(PMDL Mdl, PVOID *PAddress, ULONG ExtraPriorityFlags);
|
||||
@ -1098,6 +1105,16 @@ typedef struct
|
||||
FSP_FSCTL_DECLSPEC_ALIGN UINT8 FsextData[];
|
||||
} FSP_FSVOL_DEVICE_EXTENSION;
|
||||
typedef struct
|
||||
{
|
||||
FSP_DEVICE_EXTENSION Base;
|
||||
UINT16 SectorSize;
|
||||
LONG IsMountdev;
|
||||
BOOLEAN Persistent;
|
||||
GUID UniqueId;
|
||||
UNICODE_STRING VolumeName;
|
||||
WCHAR VolumeNameBuf[FSP_FSCTL_VOLUME_NAME_SIZE / sizeof(WCHAR)];
|
||||
} FSP_FSVRT_DEVICE_EXTENSION;
|
||||
typedef struct
|
||||
{
|
||||
FSP_DEVICE_EXTENSION Base;
|
||||
UINT32 InitDonePfxTab:1;
|
||||
@ -1117,6 +1134,12 @@ FSP_FSVOL_DEVICE_EXTENSION *FspFsvolDeviceExtension(PDEVICE_OBJECT DeviceObject)
|
||||
return DeviceObject->DeviceExtension;
|
||||
}
|
||||
static inline
|
||||
FSP_FSVRT_DEVICE_EXTENSION *FspFsvrtDeviceExtension(PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
ASSERT(FspFsvrtDeviceExtensionKind == ((FSP_DEVICE_EXTENSION *)DeviceObject->DeviceExtension)->Kind);
|
||||
return DeviceObject->DeviceExtension;
|
||||
}
|
||||
static inline
|
||||
FSP_FSMUP_DEVICE_EXTENSION *FspFsmupDeviceExtension(PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
ASSERT(FspFsmupDeviceExtensionKind == ((FSP_DEVICE_EXTENSION *)DeviceObject->DeviceExtension)->Kind);
|
||||
@ -1221,6 +1244,20 @@ BOOLEAN FspQueryDirectoryIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* mountdev */
|
||||
NTSTATUS FspMountdevQueryDeviceName(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspMountdevQueryUniqueId(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
BOOLEAN FspMountdevDeviceControl(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||
PNTSTATUS PResult);
|
||||
NTSTATUS FspMountdevMake(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PDEVICE_OBJECT FsvolDeviceObject,
|
||||
BOOLEAN Persistent);
|
||||
VOID FspMountdevFini(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject);
|
||||
|
||||
/* fsmup */
|
||||
NTSTATUS FspMupRegister(
|
||||
PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject);
|
||||
@ -1236,6 +1273,8 @@ VOID FspVolumeDelete(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspVolumeMount(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspVolumeMakeMountdev(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspVolumeGetName(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspVolumeGetNameList(
|
||||
|
@ -77,6 +77,10 @@ static NTSTATUS FspFsctlFileSystemControl(
|
||||
case IRP_MN_USER_FS_REQUEST:
|
||||
switch (IrpSp->Parameters.FileSystemControl.FsControlCode)
|
||||
{
|
||||
case FSP_FSCTL_MOUNTDEV:
|
||||
if (0 != IrpSp->FileObject->FsContext2)
|
||||
Result = FspVolumeMakeMountdev(FsctlDeviceObject, Irp, IrpSp);
|
||||
break;
|
||||
case FSP_FSCTL_VOLUME_NAME:
|
||||
if (0 != IrpSp->FileObject->FsContext2)
|
||||
Result = FspVolumeGetName(FsctlDeviceObject, Irp, IrpSp);
|
||||
|
232
src/sys/mountdev.c
Normal file
232
src/sys/mountdev.c
Normal file
@ -0,0 +1,232 @@
|
||||
/**
|
||||
* @file sys/mountdev.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 <sys/driver.h>
|
||||
|
||||
NTSTATUS FspMountdevQueryDeviceName(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspMountdevQueryUniqueId(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
BOOLEAN FspMountdevDeviceControl(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||
PNTSTATUS PResult);
|
||||
NTSTATUS FspMountdevMake(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PDEVICE_OBJECT FsvolDeviceObject,
|
||||
BOOLEAN Persistent);
|
||||
VOID FspMountdevFini(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, FspMountdevQueryDeviceName)
|
||||
#pragma alloc_text(PAGE, FspMountdevQueryUniqueId)
|
||||
#pragma alloc_text(PAGE, FspMountdevDeviceControl)
|
||||
#pragma alloc_text(PAGE, FspMountdevMake)
|
||||
#pragma alloc_text(PAGE, FspMountdevFini)
|
||||
#endif
|
||||
|
||||
NTSTATUS FspMountdevQueryDeviceName(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
|
||||
ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||||
PMOUNTDEV_NAME OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
|
||||
if (sizeof(MOUNTDEV_NAME) > OutputBufferLength)
|
||||
/* NOTE: Windows storage samples also set: Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME) */
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
RtlZeroMemory(OutputBuffer, sizeof(MOUNTDEV_NAME));
|
||||
OutputBuffer->NameLength = FsvrtDeviceExtension->VolumeName.Length;
|
||||
|
||||
Irp->IoStatus.Information =
|
||||
FIELD_OFFSET(MOUNTDEV_NAME, Name) + OutputBuffer->NameLength;
|
||||
if (Irp->IoStatus.Information > OutputBufferLength)
|
||||
{
|
||||
Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
RtlCopyMemory(OutputBuffer->Name,
|
||||
FsvrtDeviceExtension->VolumeName.Buffer, OutputBuffer->NameLength);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS FspMountdevQueryUniqueId(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
|
||||
ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||||
PMOUNTDEV_UNIQUE_ID OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
|
||||
if (sizeof(MOUNTDEV_UNIQUE_ID) > OutputBufferLength)
|
||||
/* NOTE: Windows storage samples also set: Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID) */
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
RtlZeroMemory(OutputBuffer, sizeof(MOUNTDEV_UNIQUE_ID));
|
||||
OutputBuffer->UniqueIdLength = sizeof FsvrtDeviceExtension->UniqueId;
|
||||
|
||||
Irp->IoStatus.Information =
|
||||
FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId) + OutputBuffer->UniqueIdLength;
|
||||
if (Irp->IoStatus.Information > OutputBufferLength)
|
||||
{
|
||||
Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
RtlCopyMemory(OutputBuffer->UniqueId,
|
||||
&FsvrtDeviceExtension->UniqueId, OutputBuffer->UniqueIdLength);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
BOOLEAN FspMountdevDeviceControl(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||
PNTSTATUS PResult)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (0 != FsvrtDeviceObject)
|
||||
{
|
||||
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
|
||||
if (0 != InterlockedCompareExchange(&FsvrtDeviceExtension->IsMountdev, 0, 0))
|
||||
{
|
||||
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
|
||||
{
|
||||
case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
|
||||
*PResult = FspMountdevQueryDeviceName(FsvrtDeviceObject, Irp, IrpSp);
|
||||
return TRUE;
|
||||
case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
|
||||
*PResult = FspMountdevQueryUniqueId(FsvrtDeviceObject, Irp, IrpSp);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
NTSTATUS FspMountdevMake(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject, PDEVICE_OBJECT FsvolDeviceObject,
|
||||
BOOLEAN Persistent)
|
||||
{
|
||||
/*
|
||||
* This function converts the fsvrt device into a mountdev device that
|
||||
* responds to MountManager IOCTL's. This allows the fsvrt device to
|
||||
* be mounted using the MountManager.
|
||||
*
|
||||
* This function requires protection against concurrency. In general this
|
||||
* is achieved by acquiring the GlobalDeviceLock.
|
||||
*/
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
|
||||
UNICODE_STRING String;
|
||||
WCHAR StringBuf[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR) + 18];
|
||||
GUID Guid;
|
||||
NTSTATUS Result;
|
||||
|
||||
ASSERT(FsvolDeviceExtension->FsvrtDeviceObject == FsvrtDeviceObject);
|
||||
|
||||
if (0 != InterlockedCompareExchange(&FsvrtDeviceExtension->IsMountdev, 0, 0))
|
||||
return Persistent == FsvrtDeviceExtension->Persistent ?
|
||||
STATUS_TOO_LATE : STATUS_ACCESS_DENIED;
|
||||
|
||||
FsvrtDeviceExtension->Persistent = Persistent;
|
||||
|
||||
if (Persistent)
|
||||
{
|
||||
/* make UUID v5 from the fsvrt device GUID and a unique string derived from VolumeParams */
|
||||
RtlInitEmptyUnicodeString(&String, StringBuf, sizeof StringBuf);
|
||||
Result = RtlUnicodeStringPrintf(&String,
|
||||
L"%s:%08lx:%08lx",
|
||||
FsvolDeviceExtension->VolumeParams.FileSystemName,
|
||||
FsvolDeviceExtension->VolumeParams.VolumeSerialNumber,
|
||||
FsvolDeviceExtension->VolumeParams.VolumeCreationTime);
|
||||
ASSERT(NT_SUCCESS(Result));
|
||||
Result = FspUuid5Make(&FspFsvrtDeviceClassGuid, String.Buffer, String.Length, &Guid);
|
||||
}
|
||||
else
|
||||
/* create volume guid */
|
||||
Result = FspCreateGuid(&Guid);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
/* initialize the fsvrt device extension */
|
||||
RtlCopyMemory(&FsvrtDeviceExtension->UniqueId, &Guid, sizeof Guid);
|
||||
RtlInitEmptyUnicodeString(&FsvrtDeviceExtension->VolumeName,
|
||||
FsvrtDeviceExtension->VolumeNameBuf, sizeof FsvrtDeviceExtension->VolumeNameBuf);
|
||||
RtlCopyUnicodeString(&FsvrtDeviceExtension->VolumeName, &FsvolDeviceExtension->VolumeName);
|
||||
|
||||
/* mark the fsvrt device as initialized */
|
||||
InterlockedIncrement(&FspFsvrtDeviceExtension(FsvrtDeviceObject)->IsMountdev);
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
return Result;
|
||||
}
|
||||
|
||||
VOID FspMountdevFini(
|
||||
PDEVICE_OBJECT FsvrtDeviceObject)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
|
||||
PVOID Buffer = 0;
|
||||
ULONG Length = 4096;
|
||||
MOUNTMGR_MOUNT_POINT *MountPoint;
|
||||
NTSTATUS Result;
|
||||
|
||||
if (0 == InterlockedCompareExchange(&FsvrtDeviceExtension->IsMountdev, 0, 0))
|
||||
return;
|
||||
|
||||
if (FsvrtDeviceExtension->Persistent)
|
||||
/* if the mountdev is marked as persistent do not purge the MountManager */
|
||||
return;
|
||||
|
||||
Buffer = FspAllocNonPaged(Length);
|
||||
if (0 == Buffer)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
MountPoint = Buffer;
|
||||
RtlZeroMemory(MountPoint, sizeof *MountPoint);
|
||||
MountPoint->UniqueIdOffset = sizeof(MOUNTMGR_MOUNT_POINT);
|
||||
MountPoint->UniqueIdLength = sizeof FsvrtDeviceExtension->UniqueId;
|
||||
RtlCopyMemory((PUINT8)MountPoint + MountPoint->UniqueIdOffset,
|
||||
&FsvrtDeviceExtension->UniqueId, MountPoint->UniqueIdLength);
|
||||
|
||||
Result = FspSendMountmgrDeviceControlIrp(IOCTL_MOUNTMGR_DELETE_POINTS,
|
||||
Buffer, MountPoint->UniqueIdOffset + MountPoint->UniqueIdLength, &Length);
|
||||
|
||||
exit:
|
||||
if (0 != Buffer)
|
||||
FspFree(Buffer);
|
||||
}
|
@ -35,6 +35,8 @@ NTSTATUS FspSendQuerySecurityIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileO
|
||||
NTSTATUS FspSendQueryEaIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
||||
PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
|
||||
PFILE_FULL_EA_INFORMATION Ea, PULONG PEaLength);
|
||||
NTSTATUS FspSendMountmgrDeviceControlIrp(ULONG IoControlCode,
|
||||
PVOID SystemBuffer, ULONG InputBufferLength, PULONG POutputBufferLength);
|
||||
static NTSTATUS FspSendIrpCompletion(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context0);
|
||||
NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
|
||||
@ -136,6 +138,7 @@ NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
|
||||
#pragma alloc_text(PAGE, FspSendSetInformationIrp)
|
||||
#pragma alloc_text(PAGE, FspSendQuerySecurityIrp)
|
||||
#pragma alloc_text(PAGE, FspSendQueryEaIrp)
|
||||
#pragma alloc_text(PAGE, FspSendMountmgrDeviceControlIrp)
|
||||
#pragma alloc_text(PAGE, FspBufferUserBuffer)
|
||||
#pragma alloc_text(PAGE, FspLockUserBuffer)
|
||||
#pragma alloc_text(PAGE, FspMapLockedPagesInUserMode)
|
||||
@ -444,6 +447,63 @@ NTSTATUS FspSendQueryEaIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
||||
return Context.IoStatus.Status;
|
||||
}
|
||||
|
||||
NTSTATUS FspSendMountmgrDeviceControlIrp(ULONG IoControlCode,
|
||||
PVOID SystemBuffer, ULONG InputBufferLength, PULONG POutputBufferLength)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT(METHOD_BUFFERED == (IoControlCode & 3));
|
||||
|
||||
NTSTATUS Result;
|
||||
UNICODE_STRING DeviceName;
|
||||
PFILE_OBJECT FileObject;
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
PIRP Irp;
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
FSP_SEND_IRP_CONTEXT Context;
|
||||
ULONG OutputBufferLength = 0;
|
||||
|
||||
if (0 == POutputBufferLength)
|
||||
POutputBufferLength = &OutputBufferLength;
|
||||
|
||||
RtlInitUnicodeString(&DeviceName, MOUNTMGR_DEVICE_NAME);
|
||||
Result = IoGetDeviceObjectPointer(&DeviceName, FILE_READ_ATTRIBUTES,
|
||||
&FileObject, &DeviceObject);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
||||
if (0 == Irp)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
IrpSp = IoGetNextIrpStackLocation(Irp);
|
||||
Irp->RequestorMode = KernelMode;
|
||||
Irp->AssociatedIrp.SystemBuffer = SystemBuffer;
|
||||
IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
|
||||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength = *POutputBufferLength;
|
||||
IrpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
|
||||
IrpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
|
||||
|
||||
KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
|
||||
IoSetCompletionRoutine(Irp, FspSendIrpCompletion, &Context, TRUE, TRUE, TRUE);
|
||||
|
||||
Result = IoCallDriver(DeviceObject, Irp);
|
||||
if (STATUS_PENDING == Result)
|
||||
KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, 0);
|
||||
|
||||
*POutputBufferLength = (ULONG)Context.IoStatus.Information;
|
||||
Result = Context.IoStatus.Status;
|
||||
|
||||
exit:
|
||||
if (0 != FileObject)
|
||||
ObDereferenceObject(FileObject);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static NTSTATUS FspSendIrpCompletion(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context0)
|
||||
{
|
||||
|
@ -28,6 +28,9 @@ static NTSTATUS FspFsvolQueryFsDeviceInformation(
|
||||
static NTSTATUS FspFsvolQueryFsFullSizeInformation(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd,
|
||||
const FSP_FSCTL_VOLUME_INFO *VolumeInfo);
|
||||
static NTSTATUS FspFsvolQueryFsSectorSizeInformation(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd,
|
||||
const FSP_FSCTL_VOLUME_INFO *VolumeInfo);
|
||||
static NTSTATUS FspFsvolQueryFsSizeInformation(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd,
|
||||
const FSP_FSCTL_VOLUME_INFO *VolumeInfo);
|
||||
@ -50,6 +53,7 @@ FSP_DRIVER_DISPATCH FspSetVolumeInformation;
|
||||
#pragma alloc_text(PAGE, FspFsvolQueryFsAttributeInformation)
|
||||
#pragma alloc_text(PAGE, FspFsvolQueryFsDeviceInformation)
|
||||
#pragma alloc_text(PAGE, FspFsvolQueryFsFullSizeInformation)
|
||||
#pragma alloc_text(PAGE, FspFsvolQueryFsSectorSizeInformation)
|
||||
#pragma alloc_text(PAGE, FspFsvolQueryFsSizeInformation)
|
||||
#pragma alloc_text(PAGE, FspFsvolQueryFsVolumeInformation)
|
||||
#pragma alloc_text(PAGE, FspFsvolQueryVolumeInformation)
|
||||
@ -186,6 +190,35 @@ static NTSTATUS FspFsvolQueryFsFullSizeInformation(
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolQueryFsSectorSizeInformation(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd,
|
||||
const FSP_FSCTL_VOLUME_INFO *VolumeInfo)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (*PBuffer + sizeof(FILE_FS_SECTOR_SIZE_INFORMATION) > BufferEnd)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
PFILE_FS_SECTOR_SIZE_INFORMATION Info = (PFILE_FS_SECTOR_SIZE_INFORMATION)*PBuffer;
|
||||
|
||||
Info->LogicalBytesPerSector =
|
||||
Info->PhysicalBytesPerSectorForAtomicity =
|
||||
Info->PhysicalBytesPerSectorForPerformance =
|
||||
Info->FileSystemEffectivePhysicalBytesPerSectorForAtomicity =
|
||||
FsvolDeviceExtension->VolumeParams.SectorSize;
|
||||
Info->Flags =
|
||||
SSINFO_FLAGS_ALIGNED_DEVICE |
|
||||
SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE |
|
||||
SSINFO_FLAGS_NO_SEEK_PENALTY;
|
||||
Info->ByteOffsetForSectorAlignment = 0;
|
||||
Info->ByteOffsetForPartitionAlignment = 0;
|
||||
|
||||
*PBuffer += sizeof(FILE_FS_SECTOR_SIZE_INFORMATION);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolQueryFsSizeInformation(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd,
|
||||
const FSP_FSCTL_VOLUME_INFO *VolumeInfo)
|
||||
@ -255,7 +288,7 @@ static NTSTATUS FspFsvolQueryVolumeInformation(
|
||||
|
||||
NTSTATUS Result;
|
||||
PUINT8 Buffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
PUINT8 BufferEnd = Buffer + IrpSp->Parameters.QueryFile.Length;
|
||||
PUINT8 BufferEnd = Buffer + IrpSp->Parameters.QueryVolume.Length;
|
||||
|
||||
switch (IrpSp->Parameters.QueryVolume.FsInformationClass)
|
||||
{
|
||||
@ -268,6 +301,9 @@ static NTSTATUS FspFsvolQueryVolumeInformation(
|
||||
case FileFsFullSizeInformation:
|
||||
Result = FspFsvolQueryFsFullSizeInformation(FsvolDeviceObject, &Buffer, BufferEnd, 0);
|
||||
break;
|
||||
case FileFsSectorSizeInformation:
|
||||
Result = FspFsvolQueryFsSectorSizeInformation(FsvolDeviceObject, &Buffer, BufferEnd, 0);
|
||||
break;
|
||||
case FileFsSizeInformation:
|
||||
Result = FspFsvolQueryFsSizeInformation(FsvolDeviceObject, &Buffer, BufferEnd, 0);
|
||||
break;
|
||||
@ -310,7 +346,7 @@ NTSTATUS FspFsvolQueryVolumeInformationComplete(
|
||||
|
||||
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject;
|
||||
PUINT8 Buffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
PUINT8 BufferEnd = Buffer + IrpSp->Parameters.QueryFile.Length;
|
||||
PUINT8 BufferEnd = Buffer + IrpSp->Parameters.QueryVolume.Length;
|
||||
|
||||
FspFsvolDeviceSetVolumeInfo(FsvolDeviceObject, &Response->Rsp.QueryVolumeInformation.VolumeInfo);
|
||||
|
||||
|
@ -34,6 +34,8 @@ NTSTATUS FspVolumeMount(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
static NTSTATUS FspVolumeMountNoLock(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspVolumeMakeMountdev(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspVolumeGetName(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
NTSTATUS FspVolumeGetNameList(
|
||||
@ -57,6 +59,7 @@ NTSTATUS FspVolumeWork(
|
||||
// ! #pragma alloc_text(PAGE, FspVolumeDeleteDelayed)
|
||||
// ! #pragma alloc_text(PAGE, FspVolumeMount)
|
||||
// ! #pragma alloc_text(PAGE, FspVolumeMountNoLock)
|
||||
#pragma alloc_text(PAGE, FspVolumeMakeMountdev)
|
||||
#pragma alloc_text(PAGE, FspVolumeGetName)
|
||||
#pragma alloc_text(PAGE, FspVolumeGetNameList)
|
||||
#pragma alloc_text(PAGE, FspVolumeGetNameListNoLock)
|
||||
@ -278,7 +281,11 @@ static NTSTATUS FspVolumeCreateNoLock(
|
||||
if (NT_SUCCESS(Result))
|
||||
{
|
||||
if (0 != FsvrtDeviceObject)
|
||||
{
|
||||
FspFsvrtDeviceExtension(FsvrtDeviceObject)->SectorSize =
|
||||
FsvolDeviceExtension->VolumeParams.SectorSize;
|
||||
Result = FspDeviceInitialize(FsvrtDeviceObject);
|
||||
}
|
||||
}
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
@ -321,10 +328,22 @@ VOID FspVolumeDelete(
|
||||
// !PAGED_CODE();
|
||||
|
||||
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject;
|
||||
FSP_FILE_NODE **FileNodes;
|
||||
ULONG FileNodeCount, Index;
|
||||
NTSTATUS Result;
|
||||
|
||||
/*
|
||||
* If we have an fsvrt that is a mountdev, finalize it now! Finalizing a mountdev
|
||||
* involves interaction with the MountManager, which tries to open our devices.
|
||||
* So if we delay this interaction and we do it during final fsvrt teardown (i.e.
|
||||
* FspDeviceDelete time) we will fail such opens with STATUS_CANCELLED, which will
|
||||
* confuse the MountManager.
|
||||
*/
|
||||
if (0 != FsvrtDeviceObject)
|
||||
FspMountdevFini(FsvrtDeviceObject);
|
||||
|
||||
FspDeviceReference(FsvolDeviceObject);
|
||||
|
||||
FspDeviceGlobalLock();
|
||||
@ -543,6 +562,81 @@ static NTSTATUS FspVolumeMountNoLock(
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS FspVolumeMakeMountdev(
|
||||
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_MOUNTDEV == IrpSp->Parameters.FileSystemControl.FsControlCode);
|
||||
ASSERT(0 != IrpSp->FileObject->FsContext2);
|
||||
|
||||
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject;
|
||||
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
||||
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||||
BOOLEAN Persistent = 0 < InputBufferLength ? !!*(PBOOLEAN)Irp->AssociatedIrp.SystemBuffer : FALSE;
|
||||
MOUNTMGR_QUERY_AUTO_MOUNT QueryAutoMount;
|
||||
MOUNTMGR_SET_AUTO_MOUNT SetAutoMount;
|
||||
union
|
||||
{
|
||||
MOUNTMGR_TARGET_NAME V;
|
||||
UINT8 B[FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + FSP_FSCTL_VOLUME_NAME_SIZEMAX];
|
||||
} TargetName;
|
||||
ULONG Length;
|
||||
NTSTATUS Result;
|
||||
|
||||
if (0 == FsvrtDeviceObject)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (sizeof(GUID) > OutputBufferLength)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
FspDeviceGlobalLock();
|
||||
|
||||
Result = FspMountdevMake(FsvrtDeviceObject, FsvolDeviceObject, Persistent);
|
||||
if (NT_SUCCESS(Result))
|
||||
{
|
||||
Length = sizeof QueryAutoMount;
|
||||
Result = FspSendMountmgrDeviceControlIrp(IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT,
|
||||
&QueryAutoMount, 0, &Length);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
SetAutoMount.NewState = 0;
|
||||
Result = FspSendMountmgrDeviceControlIrp(IOCTL_MOUNTMGR_SET_AUTO_MOUNT,
|
||||
&SetAutoMount, sizeof SetAutoMount, 0);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
TargetName.V.DeviceNameLength = FsvolDeviceExtension->VolumeName.Length;
|
||||
RtlCopyMemory(TargetName.V.DeviceName,
|
||||
FsvolDeviceExtension->VolumeName.Buffer, FsvolDeviceExtension->VolumeName.Length);
|
||||
Result = FspSendMountmgrDeviceControlIrp(IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
|
||||
&TargetName.V, FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + TargetName.V.DeviceNameLength, 0);
|
||||
|
||||
SetAutoMount.NewState = QueryAutoMount.CurrentState;
|
||||
FspSendMountmgrDeviceControlIrp(IOCTL_MOUNTMGR_SET_AUTO_MOUNT,
|
||||
&SetAutoMount, sizeof SetAutoMount, 0);
|
||||
}
|
||||
else if (STATUS_TOO_LATE == Result)
|
||||
Result = STATUS_SUCCESS;
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
|
||||
&FspFsvrtDeviceExtension(FsvrtDeviceObject)->UniqueId, sizeof(GUID));
|
||||
|
||||
Irp->IoStatus.Information = sizeof(GUID);
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
FspDeviceGlobalUnlock();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
NTSTATUS FspVolumeGetName(
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
|
@ -319,6 +319,15 @@ void mount_preflight_dotest(PWSTR DeviceName)
|
||||
MountPoint[2] = L'\0';
|
||||
|
||||
GetTestDirectory(DirBuf);
|
||||
/*
|
||||
* Mount points starting with \\?\X: or \\.\X: are now considered MountManager mountpoints.
|
||||
* So skip the \\?\ prefix to avoid this problem.
|
||||
*/
|
||||
if (L'\\' == DirBuf[0] &&
|
||||
L'\\' == DirBuf[1] &&
|
||||
(L'?' == DirBuf[2] || L'.' == DirBuf[2]) &&
|
||||
L'\\' == DirBuf[3])
|
||||
memmove(DirBuf, DirBuf + 4, (wcslen(DirBuf + 4) + 1) * sizeof(WCHAR));
|
||||
|
||||
Drives = GetLogicalDrives();
|
||||
ASSERT(0 != Drives);
|
||||
|
60
tst/winfsp-tests/uuid5-test.c
Normal file
60
tst/winfsp-tests/uuid5-test.c
Normal file
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file uuid5-test.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 <winfsp/winfsp.h>
|
||||
#include <tlib/testsuite.h>
|
||||
|
||||
#include "winfsp-tests.h"
|
||||
|
||||
#pragma comment(lib, "bcrypt.lib")
|
||||
#include <ku/uuid5.c>
|
||||
|
||||
static void uuid5_test(void)
|
||||
{
|
||||
// 6ba7b810-9dad-11d1-80b4-00c04fd430c8
|
||||
static const GUID GuidNs =
|
||||
{ 0x6ba7b810, 0x9dad, 0x11d1, { 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 } };
|
||||
// 74738ff5-5367-5958-9aee-98fffdcd1876
|
||||
static const GUID Guid0 =
|
||||
{ 0x74738ff5, 0x5367, 0x5958, { 0x9a, 0xee, 0x98, 0xff, 0xfd, 0xcd, 0x18, 0x76 } };
|
||||
// 63b5d721-0b97-5e7a-a550-2f0e589b5478
|
||||
static const GUID Guid1 =
|
||||
{ 0x63b5d721, 0x0b97, 0x5e7a, { 0xa5, 0x50, 0x2f, 0x0e, 0x58, 0x9b, 0x54, 0x78 } };
|
||||
|
||||
NTSTATUS Result;
|
||||
GUID Guid;
|
||||
|
||||
Result = FspUuid5Make(&GuidNs, "www.example.org", 15, &Guid);
|
||||
ASSERT(NT_SUCCESS(Result));
|
||||
ASSERT(IsEqualGUID(&Guid0, &Guid));
|
||||
|
||||
Result = FspUuid5Make(&FspFsvrtDeviceClassGuid, "hello", 5, &Guid);
|
||||
ASSERT(NT_SUCCESS(Result));
|
||||
ASSERT(IsEqualGUID(&Guid1, &Guid));
|
||||
}
|
||||
|
||||
void uuid5_tests(void)
|
||||
{
|
||||
if (OptExternal)
|
||||
return;
|
||||
|
||||
TEST(uuid5_test);
|
||||
}
|
234
tst/winfsp-tests/volpath-test.c
Normal file
234
tst/winfsp-tests/volpath-test.c
Normal file
@ -0,0 +1,234 @@
|
||||
/**
|
||||
* @file volpath-test.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 <winfsp/winfsp.h>
|
||||
#include <tlib/testsuite.h>
|
||||
#include <strsafe.h>
|
||||
#include "memfs.h"
|
||||
|
||||
#include "winfsp-tests.h"
|
||||
|
||||
static void volpath_dotest(ULONG Flags, PWSTR Prefix)
|
||||
{
|
||||
void *memfs = memfs_start(Flags);
|
||||
|
||||
HANDLE Handle;
|
||||
BOOLEAN Success, VolumePathNameSuccess[8];
|
||||
WCHAR FilePath[MAX_PATH];
|
||||
WCHAR VolumePathName[MAX_PATH];
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
Success = CreateDirectoryW(FilePath, 0);
|
||||
ASSERT(Success);
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1\\file2",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
CloseHandle(Handle);
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
VolumePathNameSuccess[0] = GetVolumePathNameW(FilePath, VolumePathName, MAX_PATH);
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
VolumePathNameSuccess[1] = GetVolumePathNameW(FilePath, VolumePathName, MAX_PATH);
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1\\file2",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
VolumePathNameSuccess[2] = GetVolumePathNameW(FilePath, VolumePathName, MAX_PATH);
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1\\file2",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
Success = DeleteFileW(FilePath);
|
||||
ASSERT(Success);
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
Success = RemoveDirectoryW(FilePath);
|
||||
ASSERT(Success);
|
||||
|
||||
memfs_stop(memfs);
|
||||
|
||||
ASSERT(VolumePathNameSuccess[0] == VolumePathNameSuccess[1]);
|
||||
ASSERT(VolumePathNameSuccess[1] == VolumePathNameSuccess[2]);
|
||||
}
|
||||
|
||||
static void volpath_test(void)
|
||||
{
|
||||
/*
|
||||
* GetVolumePathName is not reliable on WinFsp file systems
|
||||
* when *not* using the MountManager and therefore disable
|
||||
* this test when using a non-MountManager mount point.
|
||||
*/
|
||||
if (!NtfsTests && !OptMountPoint)
|
||||
return;
|
||||
|
||||
if (WinFspDiskTests)
|
||||
volpath_dotest(MemfsDisk, 0);
|
||||
if (WinFspNetTests)
|
||||
volpath_dotest(MemfsNet, L"\\\\memfs\\share");
|
||||
}
|
||||
|
||||
static void volpath_mount_dotest(ULONG Flags, PWSTR Prefix, PWSTR MountPoint)
|
||||
{
|
||||
void *memfs = memfs_start(Flags);
|
||||
|
||||
NTSTATUS Result;
|
||||
HANDLE Handle;
|
||||
BOOLEAN Success, VolumePathNameSuccess[8];
|
||||
WCHAR FilePath[MAX_PATH];
|
||||
WCHAR VolumePathName[MAX_PATH], VolumeName[MAX_PATH];
|
||||
|
||||
Result = FspFileSystemSetMountPoint(MemfsFileSystem(memfs), MountPoint);
|
||||
ASSERT(NT_SUCCESS(Result));
|
||||
|
||||
Prefix = FspFileSystemMountPoint(MemfsFileSystem(memfs));
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
Success = CreateDirectoryW(FilePath, 0);
|
||||
ASSERT(Success);
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1\\file2",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
CloseHandle(Handle);
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
VolumePathNameSuccess[0] = GetVolumePathNameW(FilePath, VolumePathName, MAX_PATH);
|
||||
VolumePathNameSuccess[4] = GetVolumeNameForVolumeMountPointW(VolumePathName, VolumeName, MAX_PATH);
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
VolumePathNameSuccess[1] = GetVolumePathNameW(FilePath, VolumePathName, MAX_PATH);
|
||||
VolumePathNameSuccess[5] = GetVolumeNameForVolumeMountPointW(VolumePathName, VolumeName, MAX_PATH);
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1\\file2",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
VolumePathNameSuccess[2] = GetVolumePathNameW(FilePath, VolumePathName, MAX_PATH);
|
||||
VolumePathNameSuccess[6] = GetVolumeNameForVolumeMountPointW(VolumePathName, VolumeName, MAX_PATH);
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1\\file2",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
Success = DeleteFileW(FilePath);
|
||||
ASSERT(Success);
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
Success = RemoveDirectoryW(FilePath);
|
||||
ASSERT(Success);
|
||||
|
||||
FspFileSystemRemoveMountPoint(MemfsFileSystem(memfs));
|
||||
|
||||
memfs_stop(memfs);
|
||||
|
||||
ASSERT(VolumePathNameSuccess[0]);
|
||||
ASSERT(VolumePathNameSuccess[1]);
|
||||
ASSERT(VolumePathNameSuccess[2]);
|
||||
|
||||
if (MemfsNet != Flags)
|
||||
{
|
||||
ASSERT(VolumePathNameSuccess[4]);
|
||||
ASSERT(VolumePathNameSuccess[5]);
|
||||
ASSERT(VolumePathNameSuccess[6]);
|
||||
}
|
||||
}
|
||||
|
||||
static void volpath_mount_test(void)
|
||||
{
|
||||
/*
|
||||
* This test does FspFileSystemSetMountPoint and therefore
|
||||
* cannot be used with --external or --mountpoint.
|
||||
*/
|
||||
if (NtfsTests || OptMountPoint)
|
||||
return;
|
||||
|
||||
if (WinFspDiskTests)
|
||||
{
|
||||
WCHAR MountPoint[7];
|
||||
DWORD Drives;
|
||||
WCHAR Drive;
|
||||
|
||||
MountPoint[0] = L'\\';
|
||||
MountPoint[1] = L'\\';
|
||||
MountPoint[2] = L'.';
|
||||
MountPoint[3] = L'\\';
|
||||
MountPoint[4] = L'C';
|
||||
MountPoint[5] = L':';
|
||||
MountPoint[6] = L'\0';
|
||||
|
||||
Drives = GetLogicalDrives();
|
||||
ASSERT(0 != Drives);
|
||||
|
||||
for (Drive = 'Z'; 'A' <= Drive; Drive--)
|
||||
if (0 == (Drives & (1 << (Drive - 'A'))))
|
||||
break;
|
||||
ASSERT('A' <= Drive);
|
||||
|
||||
MountPoint[4] = Drive;
|
||||
|
||||
//volpath_mount_dotest(MemfsDisk, 0, 0);
|
||||
volpath_mount_dotest(MemfsDisk, 0, MountPoint);
|
||||
}
|
||||
if (WinFspNetTests)
|
||||
{
|
||||
volpath_mount_dotest(MemfsNet, L"\\\\memfs\\share", 0);
|
||||
}
|
||||
}
|
||||
|
||||
void volpath_tests(void)
|
||||
{
|
||||
/*
|
||||
* GetVolumePathName is not reliable on WinFsp file systems
|
||||
* when *not* using the MountManager and therefore disable
|
||||
* this test when using a non-MountManager mount point.
|
||||
*/
|
||||
if (!NtfsTests && !OptMountPoint)
|
||||
TEST(volpath_test);
|
||||
|
||||
/*
|
||||
* This test does FspFileSystemSetMountPoint and therefore
|
||||
* cannot be used with --external or --mountpoint.
|
||||
*/
|
||||
if (!NtfsTests && !OptMountPoint)
|
||||
TEST(volpath_mount_test);
|
||||
}
|
@ -188,6 +188,7 @@ int main(int argc, char *argv[])
|
||||
TESTSUITE(fuse_opt_tests);
|
||||
TESTSUITE(fuse_tests);
|
||||
TESTSUITE(posix_tests);
|
||||
TESTSUITE(uuid5_tests);
|
||||
TESTSUITE(eventlog_tests);
|
||||
TESTSUITE(path_tests);
|
||||
TESTSUITE(dirbuf_tests);
|
||||
@ -211,6 +212,7 @@ int main(int argc, char *argv[])
|
||||
TESTSUITE(stream_tests);
|
||||
TESTSUITE(oplock_tests);
|
||||
TESTSUITE(wsl_tests);
|
||||
TESTSUITE(volpath_tests);
|
||||
|
||||
atexit(exiting);
|
||||
signal(SIGABRT, abort_handler);
|
||||
|
Loading…
x
Reference in New Issue
Block a user