Compare commits

..

35 Commits

Author SHA1 Message Date
b3058a5e3e shared: minimal.h: STRTOINT 2020-11-06 09:41:49 -08:00
3bda3d754e update changelog 2020-11-04 13:39:34 -08:00
8109b005be dll: posix: trustPosixOffset 2020-11-03 14:04:27 -08:00
bd0d6638b0 dll: posix: trustPosixOffset 2020-11-03 12:31:13 -08:00
912703cd77 sys: FspBufferUserBuffer: special case Irp->UserBuffer kernel address 2020-10-30 15:39:56 -07:00
90bc12132e changelog: WinFsp 2020.2 2020-10-30 15:09:17 -07:00
f1cf020272 dll: fuse: allow mount manager mountpoints 2020-10-29 15:28:14 -07:00
2f65a77d34 tst: winfsp-tests: notify_open_change_dotest 2020-10-29 14:16:54 -07:00
4578414a2c tst: winfsp-tests: WINFSP_TESTS_EXCEPTION_FILTER_DISABLE 2020-10-29 14:16:53 -07:00
f0fd53e3f3 appveyor: user mode dumps 2020-10-29 14:16:51 -07:00
1cc42c9d70 tst: winfsp-tests: UnhandledExceptionFilter 2020-10-27 16:02:49 -07:00
28ac5a1cfe tst: winfsp-tests: UnhandledExceptionFilter 2020-10-27 15:01:38 -07:00
e1b1284153 tst: winfsp-tests: UnhandledExceptionFilter 2020-10-27 12:38:54 -07:00
5014e8bd35 dotnet: file change notification support 2020-10-23 13:55:36 -07:00
1b7a78edff inc: fuse: fuse_invalidate 2020-10-22 14:46:13 -07:00
6340811974 dll: fuse: fsp_fuse_notify: handle case-insensitive file systems 2020-10-21 15:45:07 -07:00
cd21d26b93 dll: fuse: fsp_fuse_notify
Correctly compute Windows change notification filter and action
from FUSE change notification action.
2020-10-19 18:17:05 -07:00
d5ab701e3c tst: winfsp-tests: enable notify_dirnotify_test 2020-10-18 09:11:05 -07:00
8269f57282 tools: run-tests: winfsp-tests-x86-notify 2020-10-17 23:18:30 -07:00
e59a49992a sys: FspFileNodeInvalidateCachesAndNotifyChangeByName: flush and purge only 2020-10-17 22:06:49 -07:00
10c8c440f9 tst: winfsp-tests: notify_dirnotify_test 2020-10-16 14:27:51 -07:00
f3375fc17f tst: winfsp-tests: disable notify_open_change_test
This test currently causes leaks on appveyor, but not locally.
Disabling before future investigation.
2020-10-11 10:12:17 -07:00
c1e4b00aa7 tools: run-tests: notify tests 2020-10-10 18:24:32 -07:00
1bb0580a6a tst: winfsp-tests: add --notify option 2020-10-10 14:30:14 -07:00
e54c2288f7 dll: fuse: fuse_notify 2020-10-10 10:15:36 -07:00
6b4b1dff6c sys: notify implementation 2020-10-09 15:19:51 -07:00
92b7989999 tst: winfsp-tests: notify testing 2020-10-09 15:05:31 -07:00
f2e2d83b72 tst: winfsp-tests: notify testing 2020-10-09 14:45:14 -07:00
3687df53c6 sys: wait groups and notify implementation 2020-10-09 12:40:49 -07:00
a004e4be10 sys: notify implementation 2020-10-08 20:49:24 -07:00
88edf5723e sys: notify implementation 2020-10-08 16:56:31 -07:00
7f360827f6 sys: notify implementation 2020-10-08 15:31:41 -07:00
01f91c771d sys: notify implementation 2020-10-07 17:07:35 -07:00
844fb7171e inc,dll,sys: notify implementation skeleton 2020-10-06 16:37:33 -07:00
489081b8c2 build: version: 2021 Beta1 2020-10-06 15:50:44 -07:00
38 changed files with 2159 additions and 148 deletions

View File

@ -1,6 +1,18 @@
= Changelog
v1.9B1 (2021 Beta1)::
Changes since v1.8:
* [NEW] WinFsp now supports file change notifications and cache invalidations. This functionality is offered via the following new API's:
** Native API: `FspFileSystemNotify`
** FUSE API: `fuse_notify`
** .NET API: `FileSystemHost.Notify`
* [FIX] WinFsp-FUSE correctly maps SID's from trusted domains to POSIX UID's in a multi-domain environment (using the "trustPosixOffset" attribute). Previously WinFsp-FUSE only handled SID's from the primary domain correctly.
v1.8 (2020.2)::
Changes since v1.7:

View File

@ -1,6 +1,8 @@
version: '{build}'
environment:
# Disable the winfsp-tests built-in exception filter to allow WER to collect dumps.
WINFSP_TESTS_EXCEPTION_FILTER_DISABLE: 1
matrix:
- CONFIGURATION: Debug
TESTING: Func
@ -15,18 +17,25 @@ init:
#- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
install:
# Hack to make WDK 1903 work on VS2015.
# See https://github.com/appveyor-tests/WDK-10.0.14393.0/blob/31cf12217fe0c92b218c70d7027dfe145be4f4cb/appveyor.yml#L7
- ps: |
# Hack to make WDK 1903 work on VS2015.
# See https://github.com/appveyor-tests/WDK-10.0.14393.0/blob/31cf12217fe0c92b218c70d7027dfe145be4f4cb/appveyor.yml#L7
[xml]$targets = get-content "C:\Program Files (x86)\Windows Kits\10\build\WindowsDriver.Common.targets"
$usingTask = $targets.ChildNodes[1].UsingTask | ? {$_.TaskName -eq "ValidateNTTargetVersion"}
$usingTask.AssemblyFile = '$(WDKContentRoot)build\bin\Microsoft.DriverKit.Build.Tasks.16.0.dll'
$targets.Save("C:\Program Files (x86)\Windows Kits\10\build\WindowsDriver.Common.targets")
# Submodules
- git submodule update --init --recursive
# Kernel and user mode dumps
- if exist %SystemRoot%\memory.dmp del %SystemRoot%\memory.dmp
- if exist C:\projects\LocalDumps rmdir /s/q C:\projects\LocalDumps
- mkdir C:\projects\LocalDumps
- reg add "HKLM\Software\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpFolder /t REG_EXPAND_SZ /d C:\projects\LocalDumps /f
- reg add "HKLM\Software\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpType /t REG_DWORD /d 2 /f
# Boot configuration
- appveyor AddMessage "Change boot configuration and reboot" -Category Information
- bcdedit /set testsigning on
- if %TESTING%==Func verifier /standard /driver winfsp-x64.sys
- if exist %SystemRoot%\memory.dmp del %SystemRoot%\memory.dmp
- ps: Restart-Computer -Force
- ps: Start-Sleep -s 60
@ -53,9 +62,11 @@ test_script:
- if %TESTING%==Avast tools\run-tests.bat %CONFIGURATION% avast-tests
- if %TESTING%==Perf tools\run-perf-tests.bat %CONFIGURATION% baseline > perf-tests.csv && type perf-tests.csv & appveyor PushArtifact perf-tests.csv
- choco uninstall winfsp -y
- if exist %SystemRoot%\memory.dmp exit 1
on_finish:
- if exist %SystemRoot%\memory.dmp (7z a memory.dmp.zip %SystemRoot%\memory.dmp && appveyor PushArtifact memory.dmp.zip)
- verifier /query
- if exist %SystemRoot%\memory.dmp (7z a km.dmp.zip %SystemRoot%\memory.dmp && appveyor PushArtifact km.dmp.zip)
- dir /a/b C:\projects\LocalDumps | findstr "^" && (7z a um.dmp.zip C:\projects\LocalDumps && appveyor PushArtifact um.dmp.zip) || ver>nul
- if exist *.dmp.zip (7z a sym.pdb.zip build\VStudio\build\%CONFIGURATION%\*.pdb && appveyor PushArtifact sym.pdb.zip)
- if exist *.dmp.zip exit 1
#- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

View File

@ -107,7 +107,7 @@
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ntdll.lib;netapi32.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -123,7 +123,7 @@
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ntdll.lib;netapi32.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -143,7 +143,7 @@
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ntdll.lib;netapi32.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -163,7 +163,7 @@
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>ntdll.lib;netapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ntdll.lib;netapi32.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@ -195,6 +195,7 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\lock-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\memfs-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\mount-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\notify-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\oplock-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\path-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\posix-test.c" />

View File

@ -109,6 +109,9 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\uuid5-test.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\notify-test.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">

View File

@ -16,10 +16,10 @@
<MyCompanyName>Navimatics LLC</MyCompanyName>
<MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright>
<MyCanonicalVersion>1.8</MyCanonicalVersion>
<MyCanonicalVersion>1.9</MyCanonicalVersion>
<MyProductVersion>2020.2</MyProductVersion>
<MyProductStage>Gold</MyProductStage>
<MyProductVersion>2021 Beta1</MyProductVersion>
<MyProductStage>Beta</MyProductStage>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>

View File

@ -52,6 +52,7 @@
<ClCompile Include="..\..\src\dll\fuse\fuse_main.c" />
<ClCompile Include="..\..\src\dll\fuse\fuse_opt.c" />
<ClCompile Include="..\..\src\dll\launch.c" />
<ClCompile Include="..\..\src\dll\ldap.c" />
<ClCompile Include="..\..\src\dll\mount.c" />
<ClCompile Include="..\..\src\dll\np.c" />
<ClCompile Include="..\..\src\dll\security.c" />
@ -224,7 +225,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib;netapi32.lib;wldap32.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
@ -251,7 +252,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib;netapi32.lib;wldap32.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link>
</ItemDefinitionGroup>
@ -281,7 +282,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib;netapi32.lib;wldap32.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
<AdditionalOptions>/PDBALTPATH:$(TargetFileName).pdb %(AdditionalOptions)</AdditionalOptions>
</Link>
@ -312,7 +313,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib;netapi32.lib;wldap32.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
<AdditionalOptions>/PDBALTPATH:$(TargetFileName).pdb %(AdditionalOptions)</AdditionalOptions>
</Link>

View File

@ -169,6 +169,9 @@
<ClCompile Include="..\..\src\shared\ku\posix.c">
<Filter>Source\shared\ku</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dll\ldap.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\src\dll\library.def">

View File

@ -152,6 +152,8 @@ FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_exit)(struct fsp_fuse_env *env,
struct fuse *f);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_exited)(struct fsp_fuse_env *env,
struct fuse *f);
FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_notify)(struct fsp_fuse_env *env,
struct fuse *f, const char *path, uint32_t action);
FSP_FUSE_API struct fuse_context *FSP_FUSE_API_NAME(fsp_fuse_get_context)(struct fsp_fuse_env *env);
FSP_FUSE_SYM(
@ -212,6 +214,13 @@ int fuse_exited(struct fuse *f),
(fsp_fuse_env(), f);
})
FSP_FUSE_SYM(
int fuse_notify(struct fuse *f, const char *path, uint32_t action),
{
return FSP_FUSE_API_CALL(fsp_fuse_notify)
(fsp_fuse_env(), f, path, action);
})
FSP_FUSE_SYM(
struct fuse_context *fuse_get_context(void),
{
@ -236,9 +245,8 @@ int fuse_interrupted(void),
FSP_FUSE_SYM(
int fuse_invalidate(struct fuse *f, const char *path),
{
(void)f;
(void)path;
return -EINVAL;
return FSP_FUSE_API_CALL(fsp_fuse_notify)
(fsp_fuse_env(), f, path, 0);
})
FSP_FUSE_SYM(

View File

@ -79,6 +79,17 @@ extern "C" {
#define UF_ARCHIVE FSP_FUSE_UF_ARCHIVE
#endif
/* notify extension */
#define FSP_FUSE_NOTIFY_MKDIR 0x0001
#define FSP_FUSE_NOTIFY_RMDIR 0x0002
#define FSP_FUSE_NOTIFY_CREATE 0x0004
#define FSP_FUSE_NOTIFY_UNLINK 0x0008
#define FSP_FUSE_NOTIFY_CHMOD 0x0010
#define FSP_FUSE_NOTIFY_CHOWN 0x0020
#define FSP_FUSE_NOTIFY_UTIME 0x0040
#define FSP_FUSE_NOTIFY_CHFLAGS 0x0080
#define FSP_FUSE_NOTIFY_TRUNCATE 0x0100
struct fuse_file_info
{
int flags;

View File

@ -66,6 +66,8 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 't', METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define FSP_FSCTL_STOP \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'S', METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSP_FSCTL_NOTIFY \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'n', METHOD_NEITHER, FILE_ANY_ACCESS)
/* fsctl internal device codes (usable only in-kernel) */
#define FSP_FSCTL_TRANSACT_INTERNAL \
@ -268,6 +270,15 @@ typedef struct
FSP_FSCTL_STATIC_ASSERT(24 == sizeof(FSP_FSCTL_STREAM_INFO),
"sizeof(FSP_FSCTL_STREAM_INFO) must be exactly 24.");
typedef struct
{
UINT16 Size;
UINT32 Filter;
UINT32 Action;
WCHAR FileNameBuf[];
} FSP_FSCTL_NOTIFY_INFO;
FSP_FSCTL_STATIC_ASSERT(12 == sizeof(FSP_FSCTL_NOTIFY_INFO),
"sizeof(FSP_FSCTL_NOTIFY_INFO) must be exactly 12.");
typedef struct
{
UINT64 UserContext;
UINT64 UserContext2;
@ -617,6 +628,8 @@ FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle,
PVOID RequestBuf, SIZE_T *PRequestBufSize,
BOOLEAN Batch);
FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle);
FSP_API NTSTATUS FspFsctlNotify(HANDLE VolumeHandle,
FSP_FSCTL_NOTIFY_INFO *NotifyInfo, SIZE_T Size);
FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath,
PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize);
FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath);

View File

@ -1186,6 +1186,72 @@ FSP_API VOID FspFileSystemStopDispatcher(FSP_FILE_SYSTEM *FileSystem);
*/
FSP_API VOID FspFileSystemSendResponse(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_RSP *Response);
/**
* Begin notifying Windows that the file system has file changes.
*
* A file system that wishes to notify Windows about file changes must
* first issue an FspFileSystemBegin call, followed by 0 or more
* FspFileSystemNotify calls, followed by an FspFileSystemNotifyEnd call.
*
* This operation blocks concurrent file rename operations. File rename
* operations may interfere with file notification, because a file being
* notified may also be concurrently renamed. After all file change
* notifications have been issued, you must make sure to call
* FspFileSystemNotifyEnd to allow file rename operations to proceed.
*
* @param FileSystem
* The file system object.
* @return
* STATUS_SUCCESS or error code. The error code STATUS_CANT_WAIT means that
* a file rename operation is currently in progress and the operation must be
* retried at a later time.
*/
FSP_API NTSTATUS FspFileSystemNotifyBegin(FSP_FILE_SYSTEM *FileSystem, ULONG Timeout);
/**
* End notifying Windows that the file system has file changes.
*
* A file system that wishes to notify Windows about file changes must
* first issue an FspFileSystemBegin call, followed by 0 or more
* FspFileSystemNotify calls, followed by an FspFileSystemNotifyEnd call.
*
* This operation allows any blocked file rename operations to proceed.
*
* @param FileSystem
* The file system object.
* @return
* STATUS_SUCCESS or error code.
*/
FSP_API NTSTATUS FspFileSystemNotifyEnd(FSP_FILE_SYSTEM *FileSystem);
/**
* Notify Windows that the file system has file changes.
*
* A file system that wishes to notify Windows about file changes must
* first issue an FspFileSystemBegin call, followed by 0 or more
* FspFileSystemNotify calls, followed by an FspFileSystemNotifyEnd call.
*
* Note that FspFileSystemNotify requires file names to be normalized. A
* normalized file name is one that contains the correct case of all characters
* in the file name.
*
* For case-sensitive file systems all file names are normalized by definition.
* For case-insensitive file systems that implement file name normalization,
* a normalized file name is the one that the file system specifies in the
* response to Create or Open (see also FspFileSystemGetOpenFileInfo). For
* case-insensitive file systems that do not implement file name normalization
* a normalized file name is the upper case version of the file name used
* to open the file.
*
* @param FileSystem
* The file system object.
* @param NotifyInfo
* Buffer containing information about file changes.
* @param Size
* Size of buffer.
* @return
* STATUS_SUCCESS or error code.
*/
FSP_API NTSTATUS FspFileSystemNotify(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_NOTIFY_INFO *NotifyInfo, SIZE_T Size);
/**
* Get the current operation context.
*
@ -1645,6 +1711,28 @@ UINT32 FspFileSystemGetEaPackedSize(PFILE_FULL_EA_INFORMATION SingleEa)
/* magic computations are courtesy of NTFS */
return 5 + SingleEa->EaNameLength + SingleEa->EaValueLength;
}
/**
* Add notify information to a buffer.
*
* This is a helper for filling a buffer to use with FspFileSystemNotify.
*
* @param NotifyInfo
* The notify information to add.
* @param Buffer
* Pointer to a buffer that will receive the notify information.
* @param Length
* Length of buffer.
* @param PBytesTransferred [out]
* Pointer to a memory location that will receive the actual number of bytes stored. This should
* be initialized to 0 prior to the first call to FspFileSystemAddNotifyInfo for a particular
* buffer.
* @return
* TRUE if the notify information was added, FALSE if there was not enough space to add it.
* @see
* FspFileSystemNotify
*/
FSP_API BOOLEAN FspFileSystemAddNotifyInfo(FSP_FSCTL_NOTIFY_INFO *NotifyInfo,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
/*
* Directory buffering

View File

@ -432,6 +432,58 @@ FSP_API FSP_FILE_SYSTEM_OPERATION_CONTEXT *FspFileSystemGetOperationContext(VOID
return (FSP_FILE_SYSTEM_OPERATION_CONTEXT *)TlsGetValue(FspFileSystemTlsKey);
}
FSP_API NTSTATUS FspFileSystemNotifyBegin(FSP_FILE_SYSTEM *FileSystem, ULONG Timeout)
{
static const ULONG Delays[] =
{
10/*ms*/,
10/*ms*/,
50/*ms*/,
50/*ms*/,
100/*ms*/,
100/*ms*/,
300/*ms*/,
};
ULONG Total = 0, Delay;
NTSTATUS Result;
for (ULONG i = 0, n = sizeof(Delays) / sizeof(Delays[0]);; i++)
{
Result = FspFsctlNotify(FileSystem->VolumeHandle, 0, 0);
if (STATUS_CANT_WAIT != Result)
return Result;
Delay = n > i ? Delays[i] : Delays[n - 1];
if (INFINITE == Timeout)
Sleep(Delay);
else
{
if (Total >= Timeout)
break;
if (Total + Delay > Timeout)
Delay = Timeout - Total;
Total += Delay;
Sleep(Delay);
}
}
return Result;
}
FSP_API NTSTATUS FspFileSystemNotifyEnd(FSP_FILE_SYSTEM *FileSystem)
{
FSP_FSCTL_NOTIFY_INFO NotifyInfo;
memset(&NotifyInfo, 0, sizeof NotifyInfo);
return FspFsctlNotify(FileSystem->VolumeHandle, &NotifyInfo, sizeof NotifyInfo.Size);
}
FSP_API NTSTATUS FspFileSystemNotify(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_NOTIFY_INFO *NotifyInfo, SIZE_T Size)
{
return FspFsctlNotify(FileSystem->VolumeHandle, NotifyInfo, Size);
}
/*
* Out-of-Line
*/

View File

@ -161,6 +161,25 @@ FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle)
return STATUS_SUCCESS;
}
FSP_API NTSTATUS FspFsctlNotify(HANDLE VolumeHandle,
FSP_FSCTL_NOTIFY_INFO *NotifyInfo, SIZE_T Size)
{
NTSTATUS Result = STATUS_SUCCESS;
DWORD Bytes = 0;
if (!DeviceIoControl(VolumeHandle,
FSP_FSCTL_NOTIFY,
NotifyInfo, (DWORD)Size, 0, 0,
&Bytes, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
exit:
return Result;
}
FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath,
PWCHAR VolumeListBuf, PSIZE_T PVolumeListSize)
{

View File

@ -1866,3 +1866,9 @@ FSP_API BOOLEAN FspFileSystemAddEa(PFILE_FULL_EA_INFORMATION SingleEa,
return TRUE;
}
FSP_API BOOLEAN FspFileSystemAddNotifyInfo(FSP_FSCTL_NOTIFY_INFO *NotifyInfo,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
{
return FspFileSystemAddXxxInfo(NotifyInfo, Buffer, Length, PBytesTransferred);
}

View File

@ -184,6 +184,28 @@ FSP_FUSE_API struct fuse_chan *fsp_fuse_mount(struct fsp_fuse_env *env,
MountPointBuf[1] = L'\0';
Size = 2 * sizeof(WCHAR);
}
else if (
(
'\\' == mountpoint[0] &&
'\\' == mountpoint[1] &&
('?' == mountpoint[2] || '.' == mountpoint[2]) &&
'\\' == mountpoint[3]
) &&
(
('A' <= mountpoint[4] && mountpoint[4] <= 'Z') ||
('a' <= mountpoint[4] && mountpoint[4] <= 'z')
) &&
':' == mountpoint[5] && '\0' == mountpoint[6])
{
MountPointBuf[0] = '\\';
MountPointBuf[1] = '\\';
MountPointBuf[2] = mountpoint[2];
MountPointBuf[3] = '\\';
MountPointBuf[4] = mountpoint[4];
MountPointBuf[5] = ':';
MountPointBuf[6] = '\0';
Size = 7 * sizeof(WCHAR);
}
else if (
(
('A' <= mountpoint[0] && mountpoint[0] <= 'Z') ||
@ -610,6 +632,115 @@ FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_exited)(struct fsp_fuse_env *env,
return f->exited;
}
FSP_FUSE_API int fsp_fuse_notify(struct fsp_fuse_env *env,
struct fuse *f, const char *path, uint32_t action)
{
PWSTR Path = 0;
int PathLength;
union
{
FSP_FSCTL_NOTIFY_INFO V;
UINT8 B[sizeof(FSP_FSCTL_NOTIFY_INFO) + FSP_FSCTL_TRANSACT_PATH_SIZEMAX];
} NotifyInfo;
NTSTATUS Result;
int result;
Result = FspPosixMapPosixToWindowsPath(path, &Path);
if (!NT_SUCCESS(Result))
{
result = -ENOMEM;
goto exit;
}
PathLength = lstrlenW(Path);
if (FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR) <= PathLength)
{
result = -ENAMETOOLONG;
goto exit;
}
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + PathLength * sizeof(WCHAR));
NotifyInfo.V.Filter = 0;
NotifyInfo.V.Action = 0;
memcpy(NotifyInfo.V.FileNameBuf, Path, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
if (!f->VolumeParams.CaseSensitiveSearch)
{
/*
* Case-insensitive FUSE file systems do not normalize open file names, which means
* that the FSD automatically normalizes file names internally by uppercasing them.
*
* The FspFileSystemNotify API requires normalized names, so upper case the file name
* here in the case of case-insensitive file systems.
*/
CharUpperBuffW(NotifyInfo.V.FileNameBuf, PathLength);
}
if (action & FSP_FUSE_NOTIFY_MKDIR)
{
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_DIR_NAME;
NotifyInfo.V.Action = FILE_ACTION_ADDED;
}
else if (action & FSP_FUSE_NOTIFY_RMDIR)
{
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_DIR_NAME;
NotifyInfo.V.Action = FILE_ACTION_REMOVED;
}
else if (action & FSP_FUSE_NOTIFY_CREATE)
{
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_FILE_NAME;
NotifyInfo.V.Action = FILE_ACTION_ADDED;
}
else if (action & FSP_FUSE_NOTIFY_UNLINK)
{
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_FILE_NAME;
NotifyInfo.V.Action = FILE_ACTION_REMOVED;
}
if (action & (FSP_FUSE_NOTIFY_CHMOD | FSP_FUSE_NOTIFY_CHOWN))
{
NotifyInfo.V.Filter |= FILE_NOTIFY_CHANGE_SECURITY;
if (0 == NotifyInfo.V.Action)
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
}
if (action & FSP_FUSE_NOTIFY_UTIME)
{
NotifyInfo.V.Filter |= FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_LAST_WRITE;
if (0 == NotifyInfo.V.Action)
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
}
if (action & FSP_FUSE_NOTIFY_CHFLAGS)
{
NotifyInfo.V.Filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
if (0 == NotifyInfo.V.Action)
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
}
if (action & FSP_FUSE_NOTIFY_TRUNCATE)
{
NotifyInfo.V.Filter |= FILE_NOTIFY_CHANGE_SIZE;
if (0 == NotifyInfo.V.Action)
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
}
Result = FspFileSystemNotify(f->FileSystem, &NotifyInfo.V, NotifyInfo.V.Size);
if (!NT_SUCCESS(Result))
{
result = -ENOMEM;
goto exit;
}
result = 0;
exit:
if (0 != Path)
FspPosixDeletePath(Path);
return result;
}
FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env)
{
struct fuse_context *context;

View File

@ -30,60 +30,6 @@
#define fsp_fuse_opt_match_exact ((const char *)1) /* exact option match */
#define fsp_fuse_opt_match_next ((const char *)2) /* option match, value is next arg */
static long long strtoint(const char *p, int base, int is_signed)
{
long long v;
int maxdig, maxalp, sign = +1;
if (is_signed)
{
if ('+' == *p)
p++;
else if ('-' == *p)
p++, sign = -1;
}
if (0 == base)
{
if ('0' == *p)
{
p++;
if ('x' == *p || 'X' == *p)
{
p++;
base = 16;
}
else
base = 8;
}
else
{
base = 10;
}
}
maxdig = 10 < base ? '9' : (base - 1) + '0';
maxalp = 10 < base ? (base - 1 - 10) + 'a' : 0;
for (v = 0; *p; p++)
{
int c = *p;
if ('0' <= c && c <= maxdig)
v = base * v + (c - '0');
else
{
c |= 0x20;
if ('a' <= c && c <= maxalp)
v = base * v + (c - 'a') + 10;
else
break;
}
}
return sign * v;
}
static void fsp_fuse_opt_match_templ(
const char *templ, const char **pspec,
const char **parg)
@ -281,19 +227,19 @@ static int fsp_fuse_opt_process_arg(struct fsp_fuse_env *env,
z++;
break;
case 'd':
llv = strtoint(argl, 10, 1);
llv = strtollint(argl, 0, 10, 1);
goto ivar;
case 'i':
llv = strtoint(argl, 0, 1);
llv = strtollint(argl, 0, 0, 1);
goto ivar;
case 'o':
llv = strtoint(argl, 8, 0);
llv = strtollint(argl, 0, 8, 0);
goto ivar;
case 'u':
llv = strtoint(argl, 10, 0);
llv = strtollint(argl, 0, 10, 0);
goto ivar;
case 'x': case 'X':
llv = strtoint(argl, 16, 0);
llv = strtollint(argl, 0, 16, 0);
ivar:
if (z)
VAR(data, opt, size_t) = (size_t)llv;

157
src/dll/ldap.c Normal file
View File

@ -0,0 +1,157 @@
/**
* @file dll/ldap.c
*
* @copyright 2015-2020 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 <dll/library.h>
#include <winldap.h>
ULONG FspLdapConnect(PWSTR HostName, PVOID *PLdap)
{
LDAP *Ldap = 0;
ULONG LdapResult;
*PLdap = 0;
Ldap = ldap_initW(HostName, LDAP_PORT);
if (0 == Ldap)
{
LdapResult = LdapGetLastError();
goto exit;
}
/* enable signing and encryption */
ldap_set_optionW(Ldap, LDAP_OPT_SIGN, LDAP_OPT_ON);
ldap_set_optionW(Ldap, LDAP_OPT_ENCRYPT, LDAP_OPT_ON);
LdapResult = ldap_bind_sW(Ldap, 0, 0, LDAP_AUTH_NEGOTIATE);
if (LDAP_SUCCESS != LdapResult)
goto exit;
*PLdap = Ldap;
LdapResult = LDAP_SUCCESS;
exit:
if (LDAP_SUCCESS != LdapResult)
{
if (0 != Ldap)
ldap_unbind(Ldap);
}
return LdapResult;
}
VOID FspLdapClose(PVOID Ldap0)
{
LDAP *Ldap = Ldap0;
ldap_unbind(Ldap);
}
ULONG FspLdapGetValue(PVOID Ldap0, PWSTR Base, ULONG Scope, PWSTR Filter, PWSTR Attribute,
PWSTR *PValue)
{
LDAP *Ldap = Ldap0;
PWSTR Attributes[2];
LDAPMessage *Message = 0, *Entry;
PWSTR *Values = 0;
int Size;
PWSTR Value;
ULONG LdapResult;
*PValue = 0;
Attributes[0] = Attribute;
Attributes[1] = 0;
LdapResult = ldap_search_sW(Ldap, Base, Scope, Filter, Attributes, 0, &Message);
if (LDAP_SUCCESS != LdapResult)
goto exit;
Entry = ldap_first_entry(Ldap, Message);
if (0 == Entry)
{
LdapResult = LDAP_OTHER;
goto exit;
}
Values = ldap_get_valuesW(Ldap, Entry, Attributes[0]);
if (0 == Values || 0 == ldap_count_valuesW(Values))
{
LdapResult = LDAP_OTHER;
goto exit;
}
Size = (lstrlenW(Values[0]) + 1) * sizeof(WCHAR);
Value = MemAlloc(Size);
if (0 == Value)
{
LdapResult = LDAP_NO_MEMORY;
goto exit;
}
memcpy(Value, Values[0], Size);
*PValue = Value;
LdapResult = LDAP_SUCCESS;
exit:
if (0 != Values)
ldap_value_freeW(Values);
if (0 != Message)
ldap_msgfree(Message);
return LdapResult;
}
ULONG FspLdapGetDefaultNamingContext(PVOID Ldap, PWSTR *PValue)
{
return FspLdapGetValue(Ldap, 0, LDAP_SCOPE_BASE, L"(objectClass=*)", L"defaultNamingContext",
PValue);
}
ULONG FspLdapGetTrustPosixOffset(PVOID Ldap, PWSTR Context, PWSTR Domain, PWSTR *PValue)
{
WCHAR Base[1024];
WCHAR Filter[512];
BOOLEAN IsFlatName;
*PValue = 0;
if (sizeof Base / sizeof Base[0] - 64 < lstrlenW(Context) ||
sizeof Filter / sizeof Filter[0] - 64 < lstrlenW(Domain))
return LDAP_OTHER;
IsFlatName = TRUE;
for (PWSTR P = Domain; *P; P++)
if (L'.' == *P)
{
IsFlatName = FALSE;
break;
}
wsprintfW(Base,
L"CN=System,%s",
Context);
wsprintfW(Filter,
IsFlatName ?
L"(&(objectClass=trustedDomain)(flatName=%s))" :
L"(&(objectClass=trustedDomain)(name=%s))",
Domain);
return FspLdapGetValue(Ldap, Base, LDAP_SCOPE_ONELEVEL, Filter, L"trustPosixOffset", PValue);
}

View File

@ -64,6 +64,13 @@ NTSTATUS FspEventLogUnregister(VOID);
PSID FspWksidNew(WELL_KNOWN_SID_TYPE WellKnownSidType, PNTSTATUS PResult);
PSID FspWksidGet(WELL_KNOWN_SID_TYPE WellKnownSidType);
ULONG FspLdapConnect(PWSTR HostName, PVOID *PLdap);
VOID FspLdapClose(PVOID Ldap);
ULONG FspLdapGetValue(PVOID Ldap, PWSTR Base, ULONG Scope, PWSTR Filter, PWSTR Attribute,
PWSTR *PValue);
ULONG FspLdapGetDefaultNamingContext(PVOID Ldap, PWSTR *PValue);
ULONG FspLdapGetTrustPosixOffset(PVOID Ldap, PWSTR Context, PWSTR Domain, PWSTR *PValue);
PWSTR FspDiagIdent(VOID);
#define FspFileSystemDirectoryBufferEntryInvalid ((ULONG)-1)

View File

@ -46,6 +46,7 @@ case ERROR_CANT_ACCESS_FILE: return STATUS_IO_REPARSE_TAG_NOT_H
case ERROR_CANT_DISABLE_MANDATORY: return STATUS_CANT_DISABLE_MANDATORY;
case ERROR_CANT_OPEN_ANONYMOUS: return STATUS_CANT_OPEN_ANONYMOUS;
case ERROR_CANT_RESOLVE_FILENAME: return STATUS_REPARSE_POINT_NOT_RESOLVED;
case ERROR_CANT_WAIT: return STATUS_CANT_WAIT;
case ERROR_CHILD_MUST_BE_VOLATILE: return STATUS_CHILD_MUST_BE_VOLATILE;
case ERROR_CLEANER_CARTRIDGE_INSTALLED: return STATUS_CLEANER_CARTRIDGE_INSTALLED;
case ERROR_CLUSTER_INVALID_NETWORK: return STATUS_CLUSTER_INVALID_NETWORK;

View File

@ -582,6 +582,75 @@ namespace Fsp
Response.IoStatus.Status = (UInt32)Status;
Api.FspFileSystemSendResponse(_FileSystemPtr, ref Response);
}
/// <summary>
/// Begin notifying Windows that the file system has file changes.
/// </summary>
/// <remarks>
/// <para>
/// A file system that wishes to notify Windows about file changes must
/// first issue an FspFileSystemBegin call, followed by 0 or more
/// FspFileSystemNotify calls, followed by an FspFileSystemNotifyEnd call.
/// </para><para>
/// This operation blocks concurrent file rename operations. File rename
/// operations may interfere with file notification, because a file being
/// notified may also be concurrently renamed. After all file change
/// notifications have been issued, you must make sure to call
/// FspFileSystemNotifyEnd to allow file rename operations to proceed.
/// </para>
/// </remarks>
/// <returns>
/// STATUS_SUCCESS or error code. The error code STATUS_CANT_WAIT means that
/// a file rename operation is currently in progress and the operation must be
/// retried at a later time.
/// </returns>
public Int32 NotifyBegin(UInt32 Timeout)
{
return Api.FspFileSystemNotifyBegin(_FileSystemPtr, Timeout);
}
/// <summary>
/// End notifying Windows that the file system has file changes.
/// </summary>
/// <remarks>
/// <para>
/// A file system that wishes to notify Windows about file changes must
/// first issue an FspFileSystemBegin call, followed by 0 or more
/// FspFileSystemNotify calls, followed by an FspFileSystemNotifyEnd call.
/// </para><para>
/// This operation allows any blocked file rename operations to proceed.
/// </para>
/// </remarks>
/// <returns>STATUS_SUCCESS or error code.</returns>
public Int32 NotifyEnd()
{
return Api.FspFileSystemNotifyEnd(_FileSystemPtr);
}
/// <summary>
/// Notify Windows that the file system has file changes.
/// </summary>
/// <remarks>
/// <para>
/// A file system that wishes to notify Windows about file changes must
/// first issue an FspFileSystemBegin call, followed by 0 or more
/// FspFileSystemNotify calls, followed by an FspFileSystemNotifyEnd call.
/// </para><para>
/// Note that FspFileSystemNotify requires file names to be normalized. A
/// normalized file name is one that contains the correct case of all characters
/// in the file name.
/// </para><para>
/// For case-sensitive file systems all file names are normalized by definition.
/// For case-insensitive file systems that implement file name normalization,
/// a normalized file name is the one that the file system specifies in the
/// response to Create or Open (see also FspFileSystemGetOpenFileInfo). For
/// case-insensitive file systems that do not implement file name normalization
/// a normalized file name is the upper case version of the file name used
/// to open the file.
/// </para>
/// </remarks>
/// <returns>STATUS_SUCCESS or error code.</returns>
public Int32 Notify(NotifyInfo[] NotifyInfoArray)
{
return Api.FspFileSystemNotify(_FileSystemPtr, NotifyInfoArray);
}
/* FSP_FILE_SYSTEM_INTERFACE */
private static Byte[] ByteBufferNotNull = new Byte[0];

View File

@ -310,6 +310,44 @@ namespace Fsp.Interop
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct NotifyInfoInternal
{
internal const int FileNameBufSize = 1024 * 2/*FSP_FSCTL_TRANSACT_PATH_SIZEMAX*/;
internal static int FileNameBufOffset =
(int)Marshal.OffsetOf(typeof(DirInfo), "FileNameBuf");
internal UInt16 Size;
internal UInt32 Filter;
internal UInt32 Action;
//internal unsafe fixed UInt16 FileNameBuf[];
internal unsafe fixed UInt16 FileNameBuf[FileNameBufSize];
internal unsafe void SetFileNameBuf(String Value)
{
fixed (UInt16 *P = FileNameBuf)
{
int Size = null != Value ? Value.Length : 0;
if (Size > FileNameBufSize)
Size = FileNameBufSize;
for (int I = 0; Size > I; I++)
P[I] = Value[I];
this.Size = (UInt16)(FileNameBufOffset + Size * 2);
}
}
}
/// <summary>
/// Contains file change notification information.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct NotifyInfo
{
public String FileName;
public UInt32 Action;
public UInt32 Filter;
}
[StructLayout(LayoutKind.Sequential)]
internal struct FullEaInformation
{
@ -743,6 +781,18 @@ namespace Fsp.Interop
IntPtr FileSystem,
ref FspFsctlTransactRsp Response);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 FspFileSystemNotifyBegin(
IntPtr FileSystem,
UInt32 Timeout);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 FspFileSystemNotifyEnd(
IntPtr FileSystem);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 FspFileSystemNotify(
IntPtr FileSystem,
IntPtr NotifyInfo,
UIntPtr Size);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal unsafe delegate FspFileSystemOperationContext *FspFileSystemGetOperationContext();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr FspFileSystemMountPointF(
@ -805,6 +855,13 @@ namespace Fsp.Interop
out UInt32 PBytesTransferred);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U1)]
internal delegate Boolean FspFileSystemAddNotifyInfo(
IntPtr NotifyInfo,
IntPtr Buffer,
UInt32 Length,
out UInt32 PBytesTransferred);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U1)]
internal delegate Boolean FspFileSystemAcquireDirectoryBuffer(
ref IntPtr PDirBuffer,
[MarshalAs(UnmanagedType.U1)] Boolean Reset,
@ -930,6 +987,9 @@ namespace Fsp.Interop
internal static Proto.FspFileSystemStartDispatcher FspFileSystemStartDispatcher;
internal static Proto.FspFileSystemStopDispatcher FspFileSystemStopDispatcher;
internal static Proto.FspFileSystemSendResponse FspFileSystemSendResponse;
internal static Proto.FspFileSystemNotifyBegin FspFileSystemNotifyBegin;
internal static Proto.FspFileSystemNotifyEnd FspFileSystemNotifyEnd;
internal static Proto.FspFileSystemNotify _FspFileSystemNotify;
internal static Proto.FspFileSystemGetOperationContext FspFileSystemGetOperationContext;
internal static Proto.FspFileSystemMountPointF FspFileSystemMountPoint;
internal static Proto.FspFileSystemSetOperationGuardStrategyF FspFileSystemSetOperationGuardStrategy;
@ -941,6 +1001,7 @@ namespace Fsp.Interop
internal static Proto.FspFileSystemCanReplaceReparsePoint _FspFileSystemCanReplaceReparsePoint;
internal static Proto.FspFileSystemAddStreamInfo _FspFileSystemAddStreamInfo;
internal static Proto.FspFileSystemAddEa _FspFileSystemAddEa;
internal static Proto.FspFileSystemAddNotifyInfo _FspFileSystemAddNotifyInfo;
internal static Proto.FspFileSystemAcquireDirectoryBuffer FspFileSystemAcquireDirectoryBuffer;
internal static Proto.FspFileSystemFillDirectoryBuffer FspFileSystemFillDirectoryBuffer;
internal static Proto.FspFileSystemReleaseDirectoryBuffer FspFileSystemReleaseDirectoryBuffer;
@ -1013,6 +1074,15 @@ namespace Fsp.Interop
{
return _FspFileSystemAddStreamInfo(IntPtr.Zero, Buffer, Length, out PBytesTransferred);
}
internal static unsafe Boolean FspFileSystemAddNotifyInfo(
ref NotifyInfoInternal NotifyInfo,
IntPtr Buffer,
UInt32 Length,
out UInt32 PBytesTransferred)
{
fixed (NotifyInfoInternal *P = &NotifyInfo)
return _FspFileSystemAddNotifyInfo((IntPtr)P, Buffer, Length, out PBytesTransferred);
}
internal delegate Int32 EnumerateEa(
Object FileNode,
@ -1070,6 +1140,34 @@ namespace Fsp.Interop
return _FspFileSystemAddEa(IntPtr.Zero, Buffer, Length, out PBytesTransferred);
}
internal static unsafe Int32 FspFileSystemNotify(
IntPtr FileSystem,
NotifyInfo[] NotifyInfoArray)
{
int Length = 0;
for (int I = 0; NotifyInfoArray.Length > I; I++)
{
Length = (Length + 7) & ~7; // align to next qword boundary
Length += NotifyInfoInternal.FileNameBufOffset +
NotifyInfoArray[I].FileName.Length * 2;
}
Byte[] Buffer = new Byte[Length];
UInt32 BytesTransferred = default(UInt32);
fixed (Byte *P = Buffer)
{
for (int I = 0; NotifyInfoArray.Length > I; I++)
{
NotifyInfoInternal Internal = default(NotifyInfoInternal);
Internal.Action = NotifyInfoArray[I].Action;
Internal.Filter = NotifyInfoArray[I].Filter;
Internal.SetFileNameBuf(NotifyInfoArray[I].FileName);
FspFileSystemAddNotifyInfo(
ref Internal, (IntPtr)P, (UInt32)Length, out BytesTransferred);
}
return _FspFileSystemNotify(FileSystem, (IntPtr)P, (UIntPtr)BytesTransferred);
}
}
internal unsafe static Object GetUserContext(
IntPtr NativePtr)
{
@ -1330,6 +1428,9 @@ namespace Fsp.Interop
FspFileSystemStartDispatcher = GetEntryPoint<Proto.FspFileSystemStartDispatcher>(Module);
FspFileSystemStopDispatcher = GetEntryPoint<Proto.FspFileSystemStopDispatcher>(Module);
FspFileSystemSendResponse = GetEntryPoint<Proto.FspFileSystemSendResponse>(Module);
FspFileSystemNotifyBegin = GetEntryPoint<Proto.FspFileSystemNotifyBegin>(Module);
FspFileSystemNotifyEnd = GetEntryPoint<Proto.FspFileSystemNotifyEnd>(Module);
_FspFileSystemNotify = GetEntryPoint<Proto.FspFileSystemNotify>(Module);
FspFileSystemGetOperationContext = GetEntryPoint<Proto.FspFileSystemGetOperationContext>(Module);
FspFileSystemMountPoint = GetEntryPoint<Proto.FspFileSystemMountPointF>(Module);
FspFileSystemSetOperationGuardStrategy = GetEntryPoint<Proto.FspFileSystemSetOperationGuardStrategyF>(Module);
@ -1341,6 +1442,7 @@ namespace Fsp.Interop
_FspFileSystemCanReplaceReparsePoint = GetEntryPoint<Proto.FspFileSystemCanReplaceReparsePoint>(Module);
_FspFileSystemAddStreamInfo = GetEntryPoint<Proto.FspFileSystemAddStreamInfo>(Module);
_FspFileSystemAddEa = GetEntryPoint<Proto.FspFileSystemAddEa>(Module);
_FspFileSystemAddNotifyInfo = GetEntryPoint<Proto.FspFileSystemAddNotifyInfo>(Module);
FspFileSystemAcquireDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemAcquireDirectoryBuffer>(Module);
FspFileSystemFillDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemFillDirectoryBuffer>(Module);
FspFileSystemReleaseDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemReleaseDirectoryBuffer>(Module);

View File

@ -55,36 +55,6 @@ static void printlog(HANDLE h, const char *format, ...)
va_end(ap);
}
static unsigned wcstoint(const wchar_t *p, const wchar_t **endp, int base)
{
unsigned v;
int maxdig, maxalp;
maxdig = 10 < base ? '9' : (base - 1) + '0';
maxalp = 10 < base ? (base - 1 - 10) + 'a' : 0;
for (v = 0; *p; p++)
{
int c = *p;
if ('0' <= c && c <= maxdig)
v = base * v + (c - '0');
else
{
c |= 0x20;
if ('a' <= c && c <= maxalp)
v = base * v + (c - 'a') + 10;
else
break;
}
}
if (0 != endp)
*endp = (wchar_t *)p;
return v;
}
static void usage(void)
{
fatal(ERROR_INVALID_PARAMETER,
@ -380,7 +350,7 @@ static NTSTATUS id_uid(PWSTR UidStr)
UINT32 Uid;
NTSTATUS Result;
Uid = wcstoint(UidStr, &UidStr, 10);
Uid = wcstouint(UidStr, &UidStr, 10, 0);
if (L'\0' != *UidStr)
return STATUS_INVALID_PARAMETER;
@ -525,13 +495,13 @@ static NTSTATUS perm_mode(PWSTR PermStr)
UINT32 Uid, Gid, Mode;
NTSTATUS Result;
Uid = wcstoint(PermStr, &PermStr, 10);
Uid = wcstouint(PermStr, &PermStr, 10, 0);
if (L':' != *PermStr)
return STATUS_INVALID_PARAMETER;
Gid = wcstoint(PermStr + 1, &PermStr, 10);
Gid = wcstouint(PermStr + 1, &PermStr, 10, 0);
if (L':' != *PermStr)
return STATUS_INVALID_PARAMETER;
Mode = wcstoint(PermStr + 1, &PermStr, 8);
Mode = wcstouint(PermStr + 1, &PermStr, 8, 0);
if (L'\0' != *PermStr)
return STATUS_INVALID_PARAMETER;

View File

@ -26,6 +26,8 @@
#include <dll/library.h>
#include <aclapi.h>
#include <dsgetdc.h>
#include <lm.h>
#define _NTDEF_
#include <ntsecapi.h>

View File

@ -111,8 +111,59 @@ static union
#define FspUnmappedUid (65534)
static PISID FspAccountDomainSid, FspPrimaryDomainSid;
static struct
{
PSID DomainSid;
PWSTR NetbiosDomainName;
PWSTR DnsDomainName;
ULONG TrustPosixOffset;
} *FspTrustedDomains;
ULONG FspTrustedDomainCount;
static INIT_ONCE FspPosixInitOnce = INIT_ONCE_STATIC_INIT;
#if !defined(_KERNEL_MODE)
static ULONG FspPosixInitializeTrustPosixOffsets(VOID)
{
PVOID Ldap = 0;
PWSTR DefaultNamingContext = 0;
PWSTR TrustPosixOffsetString = 0;
ULONG LdapResult;
LdapResult = FspLdapConnect(0/* default LDAP server */, &Ldap);
if (0 != LdapResult)
goto exit;
LdapResult = FspLdapGetDefaultNamingContext(Ldap, &DefaultNamingContext);
if (0 != LdapResult)
goto exit;
/* get the "trustPosixOffset" for each trusted domain */
for (ULONG I = 0; FspTrustedDomainCount > I; I++)
{
MemFree(TrustPosixOffsetString);
LdapResult = FspLdapGetTrustPosixOffset(Ldap,
DefaultNamingContext, FspTrustedDomains[I].DnsDomainName, &TrustPosixOffsetString);
if (0 == LdapResult)
FspTrustedDomains[I].TrustPosixOffset = wcstouint(TrustPosixOffsetString, 0, 10, 1);
}
LdapResult = 0;
exit:
MemFree(TrustPosixOffsetString);
MemFree(DefaultNamingContext);
if (0 != Ldap)
FspLdapClose(Ldap);
/* if the "trustPosixOffset" looks wrong, fix it up using Cygwin magic value 0xfe500000 */
for (ULONG I = 0; FspTrustedDomainCount > I; I++)
{
if (0x100000 > FspTrustedDomains[I].TrustPosixOffset)
FspTrustedDomains[I].TrustPosixOffset = 0xfe500000;
}
return LdapResult;
}
static BOOL WINAPI FspPosixInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
@ -120,8 +171,10 @@ static BOOL WINAPI FspPosixInitialize(
LSA_HANDLE PolicyHandle = 0;
PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = 0;
PPOLICY_DNS_DOMAIN_INFO PrimaryDomainInfo = 0;
PDS_DOMAIN_TRUSTSW TrustedDomains = 0;
ULONG TrustedDomainCount, RealTrustedDomainCount;
BYTE Count;
ULONG Size;
ULONG Size, Temp;
NTSTATUS Result;
Result = LsaOpenPolicy(0, &Obja, POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle);
@ -148,9 +201,104 @@ static BOOL WINAPI FspPosixInitialize(
FspPrimaryDomainSid = MemAlloc(Size);
if (0 != FspPrimaryDomainSid)
memcpy(FspPrimaryDomainSid, PrimaryDomainInfo->Sid, Size);
if (ERROR_SUCCESS == DsEnumerateDomainTrustsW(
0, DS_DOMAIN_DIRECT_INBOUND | DS_DOMAIN_DIRECT_OUTBOUND | DS_DOMAIN_IN_FOREST,
&TrustedDomains, &TrustedDomainCount))
{
Size = 0;
RealTrustedDomainCount = 0;
for (ULONG I = 0; TrustedDomainCount > I; I++)
{
if (0 == TrustedDomains[I].DomainSid ||
(0 == TrustedDomains[I].NetbiosDomainName &&
0 == TrustedDomains[I].DnsDomainName) ||
EqualSid(TrustedDomains[I].DomainSid, FspPrimaryDomainSid))
continue;
if (0 != TrustedDomains[I].DomainSid)
{
Size = FSP_FSCTL_DEFAULT_ALIGN_UP(Size);
Size += GetLengthSid(TrustedDomains[I].DomainSid);
}
if (0 != TrustedDomains[I].NetbiosDomainName)
{
Size = FSP_FSCTL_ALIGN_UP(Size, sizeof(WCHAR));
Size += (lstrlenW(TrustedDomains[I].NetbiosDomainName) + 1) * sizeof(WCHAR);
}
if (0 != TrustedDomains[I].DnsDomainName)
{
Size = FSP_FSCTL_ALIGN_UP(Size, sizeof(WCHAR));
Size += (lstrlenW(TrustedDomains[I].DnsDomainName) + 1) * sizeof(WCHAR);
}
RealTrustedDomainCount++;
}
Size = FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof FspTrustedDomains[0] * RealTrustedDomainCount) + Size;
if (0 < RealTrustedDomainCount)
{
FspTrustedDomains = MemAlloc(Size);
if (0 != FspTrustedDomains)
{
Size = FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof FspTrustedDomains[0] * RealTrustedDomainCount);
for (ULONG I = 0, J = 0; TrustedDomainCount > I; I++)
{
if (0 == TrustedDomains[I].DomainSid ||
(0 == TrustedDomains[I].NetbiosDomainName &&
0 == TrustedDomains[I].DnsDomainName) ||
EqualSid(TrustedDomains[I].DomainSid, FspPrimaryDomainSid))
continue;
FspTrustedDomains[J].DomainSid = 0;
FspTrustedDomains[J].NetbiosDomainName = 0;
FspTrustedDomains[J].DnsDomainName = 0;
FspTrustedDomains[J].TrustPosixOffset = 0;
if (0 != TrustedDomains[I].DomainSid)
{
Size = FSP_FSCTL_DEFAULT_ALIGN_UP(Size);
FspTrustedDomains[J].DomainSid =
(PVOID)((PUINT8)FspTrustedDomains + Size);
Size += (Temp = GetLengthSid(TrustedDomains[I].DomainSid));
memcpy(FspTrustedDomains[J].DomainSid,
TrustedDomains[I].DomainSid, Temp);
}
if (0 != TrustedDomains[I].NetbiosDomainName)
{
Size = FSP_FSCTL_ALIGN_UP(Size, sizeof(WCHAR));
FspTrustedDomains[J].NetbiosDomainName =
(PVOID)((PUINT8)FspTrustedDomains + Size);
Size += (Temp = (lstrlenW(TrustedDomains[I].NetbiosDomainName) + 1) * sizeof(WCHAR));
memcpy(FspTrustedDomains[J].NetbiosDomainName,
TrustedDomains[I].NetbiosDomainName, Temp);
}
if (0 != TrustedDomains[I].DnsDomainName)
{
Size = FSP_FSCTL_ALIGN_UP(Size, sizeof(WCHAR));
FspTrustedDomains[J].DnsDomainName =
(PVOID)((PUINT8)FspTrustedDomains + Size);
Size += (Temp = (lstrlenW(TrustedDomains[I].DnsDomainName) + 1) * sizeof(WCHAR));
memcpy(FspTrustedDomains[J].DnsDomainName,
TrustedDomains[I].DnsDomainName, Temp);
}
if (0 == FspTrustedDomains[J].NetbiosDomainName)
FspTrustedDomains[J].NetbiosDomainName =
FspTrustedDomains[J].DnsDomainName;
else
if (0 == FspTrustedDomains[J].DnsDomainName)
FspTrustedDomains[J].DnsDomainName =
FspTrustedDomains[J].NetbiosDomainName;
J++;
}
FspTrustedDomainCount = RealTrustedDomainCount;
}
}
}
}
if (0 < FspTrustedDomainCount)
FspPosixInitializeTrustPosixOffsets();
exit:
if (0 != TrustedDomains)
NetApiBufferFree(TrustedDomains);
if (0 != PrimaryDomainInfo)
LsaFreeMemory(PrimaryDomainInfo);
@ -172,6 +320,7 @@ VOID FspPosixFinalize(BOOLEAN Dynamic)
if (Dynamic)
{
MemFree(FspTrustedDomains);
MemFree(FspAccountDomainSid);
MemFree(FspPrimaryDomainSid);
}
@ -318,7 +467,8 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
}
else if (0x100000 <= Uid && Uid < 0xff000000)
{
if (0 != FspPrimaryDomainSid &&
if ((Uid < 0x300000 || 0 == FspTrustedDomainCount) &&
0 != FspPrimaryDomainSid &&
5 == FspPrimaryDomainSid->IdentifierAuthority.Value[5] &&
4 == FspPrimaryDomainSid->SubAuthorityCount)
{
@ -329,11 +479,30 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
FspPrimaryDomainSid->SubAuthority[3],
Uid - 0x100000);
}
else
{
PISID DomainSid = 0;
ULONG TrustPosixOffset = 0;
for (ULONG I = 0; FspTrustedDomainCount > I; I++)
{
if (FspTrustedDomains[I].TrustPosixOffset <= Uid &&
FspTrustedDomains[I].TrustPosixOffset > TrustPosixOffset)
{
DomainSid = FspTrustedDomains[I].DomainSid;
TrustPosixOffset = FspTrustedDomains[I].TrustPosixOffset;
}
}
if (0 != DomainSid)
{
*PSid = FspPosixCreateSid(5, 5,
21,
DomainSid->SubAuthority[1],
DomainSid->SubAuthority[2],
DomainSid->SubAuthority[3],
Uid - TrustPosixOffset);
}
}
}
/*
* I am sorry, I am not going to bother with all that trustPosixOffset stuff.
* But if you need it, I accept patches :)
*/
/* [IDMAP]
* Mandatory Labels:
@ -432,11 +601,15 @@ FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
else if (0 != FspAccountDomainSid &&
FspPosixIsRelativeSid(FspAccountDomainSid, Sid))
*PUid = 0x30000 + Rid;
/*
* I am sorry, I am not going to bother with all that trustPosixOffset stuff.
* But if you need it, I accept patches :)
*/
else
for (ULONG I = 0; FspTrustedDomainCount > I; I++)
{
if (FspPosixIsRelativeSid(FspTrustedDomains[I].DomainSid, Sid))
{
*PUid = FspTrustedDomains[I].TrustPosixOffset + Rid;
break;
}
}
}
/* [IDMAP]

View File

@ -130,6 +130,62 @@ WINFSP_SHARED_MINIMAL_STRNCMP(invariant_wcsnicmp, wchar_t, invariant_toupper)
#undef WINFSP_SHARED_MINIMAL_STRCMP
#undef WINFSP_SHARED_MINIMAL_STRNCMP
#define WINFSP_SHARED_MINIMAL_STRTOINT(NAME, CTYPE, ITYPE)\
static inline\
ITYPE NAME(const CTYPE *p, const CTYPE **endp, int base, int is_signed)\
{\
ITYPE v;\
int maxdig, maxalp, sign = +1;\
if (is_signed)\
{\
if ('+' == *p)\
p++;\
else if ('-' == *p)\
p++, sign = -1;\
}\
if (0 == base)\
{\
if ('0' == *p)\
{\
p++;\
if ('x' == *p || 'X' == *p)\
{\
p++;\
base = 16;\
}\
else\
base = 8;\
}\
else\
{\
base = 10;\
}\
}\
maxdig = 10 < base ? '9' : (base - 1) + '0';\
maxalp = 10 < base ? (base - 1 - 10) + 'a' : 0;\
for (v = 0; *p; p++)\
{\
int c = *p;\
if ('0' <= c && c <= maxdig)\
v = base * v + (c - '0');\
else\
{\
c |= 0x20;\
if ('a' <= c && c <= maxalp)\
v = base * v + (c - 'a') + 10;\
else\
break;\
}\
}\
if (0 != endp)\
*endp = (CTYPE *)p;\
return sign * v;\
}
WINFSP_SHARED_MINIMAL_STRTOINT(strtouint, char, unsigned int)
WINFSP_SHARED_MINIMAL_STRTOINT(strtollint, char, long long int)
WINFSP_SHARED_MINIMAL_STRTOINT(wcstouint, wchar_t, unsigned int)
WINFSP_SHARED_MINIMAL_STRTOINT(wcstollint, wchar_t, long long int)
static inline void *MemAlloc(size_t Size)
{
return HeapAlloc(GetProcessHeap(), 0, Size);

View File

@ -41,7 +41,9 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject);
static IO_TIMER_ROUTINE FspFsvolDeviceTimerRoutine;
static WORKER_THREAD_ROUTINE FspFsvolDeviceExpirationRoutine;
VOID FspFsvolDeviceFileRenameAcquireShared(PDEVICE_OBJECT DeviceObject);
BOOLEAN FspFsvolDeviceFileRenameTryAcquireShared(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameAcquireExclusive(PDEVICE_OBJECT DeviceObject);
BOOLEAN FspFsvolDeviceFileRenameTryAcquireExclusive(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
@ -83,7 +85,9 @@ VOID FspDeviceDeleteAll(VOID);
#pragma alloc_text(PAGE, FspFsvolDeviceInit)
#pragma alloc_text(PAGE, FspFsvolDeviceFini)
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameAcquireShared)
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameTryAcquireShared)
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameAcquireExclusive)
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameTryAcquireExclusive)
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameSetOwner)
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameRelease)
#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameReleaseOwner)
@ -411,10 +415,11 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
return Result;
FsvolDeviceExtension->InitDoneEa = 1;
/* initialize the FSRTL Notify mechanism */
/* initialize the Volume Notify and FSRTL Notify mechanisms */
Result = FspNotifyInitializeSync(&FsvolDeviceExtension->NotifySync);
if (!NT_SUCCESS(Result))
return Result;
FspWgroupInitialize(&FsvolDeviceExtension->VolumeNotifyWgroup);
InitializeListHead(&FsvolDeviceExtension->NotifyList);
FsvolDeviceExtension->InitDoneNotify = 1;
@ -473,7 +478,7 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject)
if (FsvolDeviceExtension->InitDoneStat)
FspStatisticsDelete(FsvolDeviceExtension->Statistics);
/* uninitialize the FSRTL Notify mechanism */
/* uninitialize the Volume Notify and FSRTL Notify mechanisms */
if (FsvolDeviceExtension->InitDoneNotify)
{
FspNotifyCleanupAll(
@ -596,6 +601,15 @@ VOID FspFsvolDeviceFileRenameAcquireShared(PDEVICE_OBJECT DeviceObject)
ExAcquireResourceSharedLite(&FsvolDeviceExtension->FileRenameResource, TRUE);
}
BOOLEAN FspFsvolDeviceFileRenameTryAcquireShared(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
return ExAcquireResourceSharedLite(&FsvolDeviceExtension->FileRenameResource, FALSE);
}
VOID FspFsvolDeviceFileRenameAcquireExclusive(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
@ -605,6 +619,15 @@ VOID FspFsvolDeviceFileRenameAcquireExclusive(PDEVICE_OBJECT DeviceObject)
ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->FileRenameResource, TRUE);
}
BOOLEAN FspFsvolDeviceFileRenameTryAcquireExclusive(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
return ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->FileRenameResource, FALSE);
}
VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner)
{
PAGED_CODE();

View File

@ -652,6 +652,28 @@ VOID FspIrpHookReset(PIRP Irp);
PVOID FspIrpHookContext(PVOID Context);
NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
/* utility: wait groups
*
* A Wait Group is a synchronization primitive that encapsulates a counter.
* A Wait Group is considered signaled when the counter is 0 and non-signaled
* when the counter is non-0. (Wait Group functionality is similar to Golang's
* sync.WaitGroup.)
*
* Wait Groups must always be allocated in non-paged storage.
*/
typedef struct
{
KEVENT Event;
LONG Count;
KSPIN_LOCK SpinLock;
} FSP_WGROUP;
VOID FspWgroupInitialize(FSP_WGROUP *Wgroup);
VOID FspWgroupIncrement(FSP_WGROUP *Wgroup);
VOID FspWgroupDecrement(FSP_WGROUP *Wgroup);
VOID FspWgroupSignalPermanently(FSP_WGROUP *Wgroup);
NTSTATUS FspWgroupWait(FSP_WGROUP *Wgroup,
KPROCESSOR_MODE WaitMode, BOOLEAN Alertable, PLARGE_INTEGER PTimeout);
/* silos */
typedef struct
{
@ -1124,6 +1146,8 @@ typedef struct
KSPIN_LOCK InfoSpinLock;
UINT64 InfoExpirationTime;
FSP_FSCTL_VOLUME_INFO VolumeInfo;
LONG VolumeNotifyLock;
FSP_WGROUP VolumeNotifyWgroup;
PNOTIFY_SYNC NotifySync;
LIST_ENTRY NotifyList;
FSP_STATISTICS *Statistics;
@ -1182,7 +1206,9 @@ VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject);
BOOLEAN FspDeviceReference(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceDereference(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameAcquireShared(PDEVICE_OBJECT DeviceObject);
BOOLEAN FspFsvolDeviceFileRenameTryAcquireShared(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameAcquireExclusive(PDEVICE_OBJECT DeviceObject);
BOOLEAN FspFsvolDeviceFileRenameTryAcquireExclusive(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject);
VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner);
@ -1328,6 +1354,8 @@ NTSTATUS FspVolumeTransactFsext(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeStop(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeNotify(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeWork(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
@ -1359,8 +1387,10 @@ typedef struct
FAST_MUTEX HeaderFastMutex;
SECTION_OBJECT_POINTERS SectionObjectPointers;
KSPIN_LOCK NpInfoSpinLock; /* allows to invalidate non-page Info w/o resources acquired */
UINT64 Security;
UINT64 DirInfo;
UINT64 StreamInfo;
UINT64 Ea;
} FSP_FILE_NODE_NONPAGED;
typedef struct FSP_FILE_NODE
{
@ -1391,11 +1421,9 @@ typedef struct FSP_FILE_NODE
UINT64 ChangeTime;
UINT32 EaSize;
ULONG FileInfoChangeNumber;
UINT64 Security;
ULONG SecurityChangeNumber;
ULONG DirInfoChangeNumber;
ULONG StreamInfoChangeNumber;
UINT64 Ea;
ULONG EaChangeNumber;
ULONG EaChangeCount;
BOOLEAN TruncateOnClose;
@ -1540,6 +1568,7 @@ BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, P
VOID FspFileNodeSetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG SecurityChangeNumber);
VOID FspFileNodeInvalidateSecurity(FSP_FILE_NODE *FileNode);
static inline
ULONG FspFileNodeSecurityChangeNumber(FSP_FILE_NODE *FileNode)
{
@ -1573,6 +1602,7 @@ BOOLEAN FspFileNodeReferenceEa(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG
VOID FspFileNodeSetEa(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetEa(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG EaChangeNumber);
VOID FspFileNodeInvalidateEa(FSP_FILE_NODE *FileNode);
static inline
ULONG FspFileNodeEaChangeNumber(FSP_FILE_NODE *FileNode)
{
@ -1582,6 +1612,9 @@ ULONG FspFileNodeEaChangeNumber(FSP_FILE_NODE *FileNode)
}
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action,
BOOLEAN InvalidateCaches);
VOID FspFileNodeInvalidateCachesAndNotifyChangeByName(PDEVICE_OBJECT FsvolDeviceObject,
PUNICODE_STRING FileName, ULONG Filter, ULONG Action,
BOOLEAN InvalidateParentCaches);
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc);

View File

@ -76,6 +76,7 @@ BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, P
VOID FspFileNodeSetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG SecurityChangeNumber);
VOID FspFileNodeInvalidateSecurity(FSP_FILE_NODE *FileNode);
BOOLEAN FspFileNodeReferenceDirInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize);
VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
@ -93,8 +94,12 @@ BOOLEAN FspFileNodeReferenceEa(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG
VOID FspFileNodeSetEa(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size);
BOOLEAN FspFileNodeTrySetEa(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG EaChangeNumber);
VOID FspFileNodeInvalidateEa(FSP_FILE_NODE *FileNode);
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action,
BOOLEAN InvalidateCaches);
VOID FspFileNodeInvalidateCachesAndNotifyChangeByName(PDEVICE_OBJECT FsvolDeviceObject,
PUNICODE_STRING FileName, ULONG Filter, ULONG Action,
BOOLEAN InvalidateParentCaches);
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp);
static NTSTATUS FspFileNodeCompleteLockIrp(PVOID Context, PIRP Irp);
NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc);
@ -149,9 +154,10 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfoAndSecurityOnOpen)
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfo)
#pragma alloc_text(PAGE, FspFileNodeInvalidateFileInfo)
#pragma alloc_text(PAGE, FspFileNodeReferenceSecurity)
#pragma alloc_text(PAGE, FspFileNodeSetSecurity)
#pragma alloc_text(PAGE, FspFileNodeTrySetSecurity)
// !#pragma alloc_text(PAGE, FspFileNodeReferenceSecurity)
// !#pragma alloc_text(PAGE, FspFileNodeSetSecurity)
// !#pragma alloc_text(PAGE, FspFileNodeTrySetSecurity)
// !#pragma alloc_text(PAGE, FspFileNodeInvalidateSecurity)
// !#pragma alloc_text(PAGE, FspFileNodeReferenceDirInfo)
// !#pragma alloc_text(PAGE, FspFileNodeSetDirInfo)
// !#pragma alloc_text(PAGE, FspFileNodeTrySetDirInfo)
@ -162,10 +168,12 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
// !#pragma alloc_text(PAGE, FspFileNodeSetStreamInfo)
// !#pragma alloc_text(PAGE, FspFileNodeTrySetStreamInfo)
// !#pragma alloc_text(PAGE, FspFileNodeInvalidateStreamInfo)
#pragma alloc_text(PAGE, FspFileNodeReferenceEa)
#pragma alloc_text(PAGE, FspFileNodeSetEa)
#pragma alloc_text(PAGE, FspFileNodeTrySetEa)
// !#pragma alloc_text(PAGE, FspFileNodeReferenceEa)
// !#pragma alloc_text(PAGE, FspFileNodeSetEa)
// !#pragma alloc_text(PAGE, FspFileNodeTrySetEa)
// !#pragma alloc_text(PAGE, FspFileNodeInvalidateEa)
#pragma alloc_text(PAGE, FspFileNodeNotifyChange)
#pragma alloc_text(PAGE, FspFileNodeInvalidateCachesAndNotifyChangeByName)
#pragma alloc_text(PAGE, FspFileNodeProcessLockIrp)
#pragma alloc_text(PAGE, FspFileNodeCompleteLockIrp)
#pragma alloc_text(PAGE, FspFileDescCreate)
@ -368,10 +376,10 @@ VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode)
FsRtlTeardownPerStreamContexts(&FileNode->Header);
FspMetaCacheInvalidateItem(FsvolDeviceExtension->EaCache, FileNode->Ea);
FspMetaCacheInvalidateItem(FsvolDeviceExtension->EaCache, FileNode->NonPaged->Ea);
FspMetaCacheInvalidateItem(FsvolDeviceExtension->StreamInfoCache, FileNode->NonPaged->StreamInfo);
FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, FileNode->NonPaged->DirInfo);
FspMetaCacheInvalidateItem(FsvolDeviceExtension->SecurityCache, FileNode->Security);
FspMetaCacheInvalidateItem(FsvolDeviceExtension->SecurityCache, FileNode->NonPaged->Security);
FspDeviceDereference(FileNode->FsvolDeviceObject);
@ -1905,38 +1913,54 @@ VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode)
BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize)
{
PAGED_CODE();
// !PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
UINT64 Security;
/* no need to acquire the NpInfoSpinLock as the FileNode is acquired */
Security = NonPaged->Security;
return FspMetaCacheReferenceItemBuffer(FsvolDeviceExtension->SecurityCache,
FileNode->Security, PBuffer, PSize);
Security, PBuffer, PSize);
}
VOID FspFileNodeSetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size)
{
PAGED_CODE();
// !PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
KIRQL Irql;
UINT64 Security;
FspMetaCacheInvalidateItem(FsvolDeviceExtension->SecurityCache, FileNode->Security);
FileNode->Security = 0 != Buffer ?
/* no need to acquire the NpInfoSpinLock as the FileNode is acquired */
Security = NonPaged->Security;
FspMetaCacheInvalidateItem(FsvolDeviceExtension->SecurityCache, Security);
Security = 0 != Buffer ?
FspMetaCacheAddItem(FsvolDeviceExtension->SecurityCache, Buffer, Size) : 0;
FileNode->SecurityChangeNumber++;
/* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeInvalidateSecurity */
KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql);
NonPaged->Security = Security;
KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql);
}
BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG SecurityChangeNumber)
{
PAGED_CODE();
// !PAGED_CODE();
if (FspFileNodeSecurityChangeNumber(FileNode) != SecurityChangeNumber)
return FALSE;
@ -1945,6 +1969,27 @@ BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG
return TRUE;
}
VOID FspFileNodeInvalidateSecurity(FSP_FILE_NODE *FileNode)
{
// !PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
KIRQL Irql;
UINT64 Security;
/* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeSetSecurity */
KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql);
Security = NonPaged->Security;
KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql);
FspMetaCacheInvalidateItem(FsvolDeviceExtension->SecurityCache, Security);
}
BOOLEAN FspFileNodeReferenceDirInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize)
{
// !PAGED_CODE();
@ -2130,38 +2175,54 @@ VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode)
BOOLEAN FspFileNodeReferenceEa(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize)
{
PAGED_CODE();
// !PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
UINT64 Ea;
/* no need to acquire the NpInfoSpinLock as the FileNode is acquired */
Ea = NonPaged->Ea;
return FspMetaCacheReferenceItemBuffer(FsvolDeviceExtension->EaCache,
FileNode->Ea, PBuffer, PSize);
Ea, PBuffer, PSize);
}
VOID FspFileNodeSetEa(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size)
{
PAGED_CODE();
// !PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
KIRQL Irql;
UINT64 Ea;
FspMetaCacheInvalidateItem(FsvolDeviceExtension->EaCache, FileNode->Ea);
FileNode->Ea = 0 != Buffer ?
/* no need to acquire the NpInfoSpinLock as the FileNode is acquired */
Ea = NonPaged->Ea;
FspMetaCacheInvalidateItem(FsvolDeviceExtension->EaCache, Ea);
Ea = 0 != Buffer ?
FspMetaCacheAddItem(FsvolDeviceExtension->EaCache, Buffer, Size) : 0;
FileNode->EaChangeNumber++;
/* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeInvalidateEa */
KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql);
NonPaged->Ea = Ea;
KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql);
}
BOOLEAN FspFileNodeTrySetEa(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
ULONG EaChangeNumber)
{
PAGED_CODE();
// !PAGED_CODE();
if (FspFileNodeEaChangeNumber(FileNode) != EaChangeNumber)
return FALSE;
@ -2170,6 +2231,27 @@ BOOLEAN FspFileNodeTrySetEa(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size,
return TRUE;
}
VOID FspFileNodeInvalidateEa(FSP_FILE_NODE *FileNode)
{
// !PAGED_CODE();
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged;
KIRQL Irql;
UINT64 Ea;
/* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeSetEa */
KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql);
Ea = NonPaged->Ea;
KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql);
FspMetaCacheInvalidateItem(FsvolDeviceExtension->EaCache, Ea);
}
VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action,
BOOLEAN InvalidateCaches)
{
@ -2232,6 +2314,108 @@ VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action
}
}
VOID FspFileNodeInvalidateCachesAndNotifyChangeByName(PDEVICE_OBJECT FsvolDeviceObject,
PUNICODE_STRING FileName, ULONG Filter, ULONG Action,
BOOLEAN InvalidateParentCaches)
{
PAGED_CODE();
FSP_FILE_NODE *FileNode;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
FileNode = FspFsvolDeviceLookupContextByName(FsvolDeviceObject, FileName);
if (0 != FileNode)
FspFileNodeReference(FileNode);
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (0 != FileNode)
{
FspFileNodeAcquireExclusive(FileNode, Full);
if (0 != FileNode->NonPaged->SectionObjectPointers.DataSectionObject)
{
IO_STATUS_BLOCK IoStatus;
FspCcFlushCache(&FileNode->NonPaged->SectionObjectPointers, 0, 0, &IoStatus);
if (NT_SUCCESS(IoStatus.Status))
CcPurgeCacheSection(&FileNode->NonPaged->SectionObjectPointers, 0, 0, FALSE);
}
FspFileNodeInvalidateFileInfo(FileNode);
FspFileNodeInvalidateSecurity(FileNode);
FspFileNodeInvalidateDirInfo(FileNode);
FspFileNodeInvalidateStreamInfo(FileNode);
FspFileNodeInvalidateEa(FileNode);
FspFileNodeNotifyChange(FileNode, Filter, Action, InvalidateParentCaches);
FspFileNodeRelease(FileNode, Full);
FspFileNodeDereference(FileNode);
}
else
{
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
UNICODE_STRING Parent, Suffix;
BOOLEAN IsStream;
IsStream = FALSE;
for (PWSTR P = FileName->Buffer, EndP = P + FileName->Length / sizeof(WCHAR); EndP > P; P++)
if (L':' == *P)
{
IsStream = TRUE;
break;
}
if (IsStream)
{
if (FlagOn(Filter, FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME))
SetFlag(Filter, FILE_NOTIFY_CHANGE_STREAM_NAME);
if (FlagOn(Filter, FILE_NOTIFY_CHANGE_SIZE))
SetFlag(Filter, FILE_NOTIFY_CHANGE_STREAM_SIZE);
if (FlagOn(Filter, FILE_NOTIFY_CHANGE_LAST_WRITE))
SetFlag(Filter, FILE_NOTIFY_CHANGE_STREAM_WRITE);
ClearFlag(Filter, ~(FILE_NOTIFY_CHANGE_STREAM_NAME | FILE_NOTIFY_CHANGE_STREAM_SIZE |
FILE_NOTIFY_CHANGE_STREAM_WRITE));
switch (Action)
{
case FILE_ACTION_ADDED:
Action = FILE_ACTION_ADDED_STREAM;
break;
case FILE_ACTION_REMOVED:
Action = FILE_ACTION_REMOVED_STREAM;
break;
case FILE_ACTION_MODIFIED:
Action = FILE_ACTION_MODIFIED_STREAM;
break;
}
}
if (0 != Filter)
{
FspFileNameSuffix(FileName, &Parent, &Suffix);
if (InvalidateParentCaches)
{
FspFsvolDeviceInvalidateVolumeInfo(FsvolDeviceObject);
if (!IsStream)
{
if (sizeof(WCHAR) == FileName->Length && L'\\' == FileName->Buffer[0])
; /* root does not have a parent */
else
FspFileNodeInvalidateDirInfoByName(FsvolDeviceObject, &Parent);
}
}
FspNotifyReportChange(
FsvolDeviceExtension->NotifySync, &FsvolDeviceExtension->NotifyList,
FileName,
(USHORT)((PUINT8)Suffix.Buffer - (PUINT8)FileName->Buffer),
0, Filter, Action);
}
}
}
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp)
{
PAGED_CODE();

View File

@ -98,6 +98,10 @@ static NTSTATUS FspFsctlFileSystemControl(
if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeStop(FsctlDeviceObject, Irp, IrpSp);
break;
case FSP_FSCTL_NOTIFY:
if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeNotify(FsctlDeviceObject, Irp, IrpSp);
break;
default:
if (CTL_CODE(0, 0xC00, 0, 0) ==
(IrpSp->Parameters.FileSystemControl.FsControlCode & CTL_CODE(0, 0xC00, 0, 0)))

View File

@ -131,6 +131,12 @@ NTSTATUS FspIrpHook(PIRP Irp, PIO_COMPLETION_ROUTINE CompletionRoutine, PVOID Ow
VOID FspIrpHookReset(PIRP Irp);
PVOID FspIrpHookContext(PVOID Context);
NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
VOID FspWgroupInitialize(FSP_WGROUP *Wgroup);
VOID FspWgroupIncrement(FSP_WGROUP *Wgroup);
VOID FspWgroupDecrement(FSP_WGROUP *Wgroup);
VOID FspWgroupSignalPermanently(FSP_WGROUP *Wgroup);
NTSTATUS FspWgroupWait(FSP_WGROUP *Wgroup,
KPROCESSOR_MODE WaitMode, BOOLEAN Alertable, PLARGE_INTEGER PTimeout);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspIsNtDdiVersionAvailable)
@ -176,6 +182,11 @@ NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
#pragma alloc_text(PAGE, FspIrpHookReset)
// !#pragma alloc_text(PAGE, FspIrpHookContext)
// !#pragma alloc_text(PAGE, FspIrpHookNext)
// !#pragma alloc_text(PAGE, FspWgroupInitialize)
// !#pragma alloc_text(PAGE, FspWgroupIncrement)
// !#pragma alloc_text(PAGE, FspWgroupDecrement)
// !#pragma alloc_text(PAGE, FspWgroupSignalPermanently)
// !#pragma alloc_text(PAGE, FspWgroupWait)
#endif
static const LONG Delays[] =
@ -597,6 +608,13 @@ NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation)
if (0 == Length || 0 != Irp->AssociatedIrp.SystemBuffer)
return STATUS_SUCCESS;
if (KernelMode == Irp->RequestorMode &&
(PUINT8)MM_SYSTEM_RANGE_START <= (PUINT8)Irp->UserBuffer)
{
Irp->AssociatedIrp.SystemBuffer = Irp->UserBuffer;
return STATUS_SUCCESS;
}
PVOID SystemBuffer = FspAllocNonPagedExternal(Length);
if (0 == SystemBuffer)
return STATUS_INSUFFICIENT_RESOURCES;
@ -1488,3 +1506,56 @@ NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
return Result;
}
VOID FspWgroupInitialize(FSP_WGROUP *Wgroup)
{
// !PAGED_CODE();
KeInitializeEvent(&Wgroup->Event, NotificationEvent, TRUE);
Wgroup->Count = 0;
KeInitializeSpinLock(&Wgroup->SpinLock);
}
VOID FspWgroupIncrement(FSP_WGROUP *Wgroup)
{
// !PAGED_CODE();
KIRQL Irql;
KeAcquireSpinLock(&Wgroup->SpinLock, &Irql);
if (0 <= Wgroup->Count && 1 == ++Wgroup->Count)
KeClearEvent(&Wgroup->Event);
KeReleaseSpinLock(&Wgroup->SpinLock, Irql);
}
VOID FspWgroupDecrement(FSP_WGROUP *Wgroup)
{
// !PAGED_CODE();
KIRQL Irql;
KeAcquireSpinLock(&Wgroup->SpinLock, &Irql);
if (0 < Wgroup->Count && 0 == --Wgroup->Count)
KeSetEvent(&Wgroup->Event, 1, FALSE);
KeReleaseSpinLock(&Wgroup->SpinLock, Irql);
}
VOID FspWgroupSignalPermanently(FSP_WGROUP *Wgroup)
{
// !PAGED_CODE();
KIRQL Irql;
KeAcquireSpinLock(&Wgroup->SpinLock, &Irql);
Wgroup->Count = -1;
KeSetEvent(&Wgroup->Event, 1, FALSE);
KeReleaseSpinLock(&Wgroup->SpinLock, Irql);
}
NTSTATUS FspWgroupWait(FSP_WGROUP *Wgroup,
KPROCESSOR_MODE WaitMode, BOOLEAN Alertable, PLARGE_INTEGER PTimeout)
{
// !PAGED_CODE();
return KeWaitForSingleObject(&Wgroup->Event, Executive, WaitMode, Alertable, PTimeout);
}

View File

@ -50,6 +50,11 @@ NTSTATUS FspVolumeTransactFsext(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeStop(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeNotify(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspVolumeNotifyLock(
PDEVICE_OBJECT FsvolDeviceObject);
static WORKER_THREAD_ROUTINE FspVolumeNotifyWork;
NTSTATUS FspVolumeWork(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
@ -68,6 +73,9 @@ NTSTATUS FspVolumeWork(
#pragma alloc_text(PAGE, FspVolumeTransact)
#pragma alloc_text(PAGE, FspVolumeTransactFsext)
#pragma alloc_text(PAGE, FspVolumeStop)
#pragma alloc_text(PAGE, FspVolumeNotify)
#pragma alloc_text(PAGE, FspVolumeNotifyLock)
#pragma alloc_text(PAGE, FspVolumeNotifyWork)
#pragma alloc_text(PAGE, FspVolumeWork)
#endif
@ -468,6 +476,11 @@ static VOID FspVolumeDeleteNoLock(
FspMupUnregister(Globals->FsmupDeviceObject, FsvolDeviceObject);
}
/* release the volume notify lock if held (so that any pending rename will abort) */
FspWgroupSignalPermanently(&FsvolDeviceExtension->VolumeNotifyWgroup);
if (1 == InterlockedCompareExchange(&FsvolDeviceExtension->VolumeNotifyLock, 0, 1))
FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, FsvolDeviceObject);
/* release the volume device object */
FspDeviceDereference(FsvolDeviceObject);
}
@ -1054,6 +1067,222 @@ NTSTATUS FspVolumeStop(
return STATUS_SUCCESS;
}
typedef struct
{
WORK_QUEUE_ITEM WorkItem;
PDEVICE_OBJECT FsvolDeviceObject;
ULONG InputBufferLength;
FSP_FSCTL_DECLSPEC_ALIGN UINT8 InputBuffer[];
} FSP_VOLUME_NOTIFY_WORK_ITEM;
NTSTATUS FspVolumeNotify(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
/*
* FspVolumeNotify processing requires multiple locks that cannot be acquired
* synchronously or deadlocks are possible. (The reason is that FspVolumeNotify
* may be called by the user mode file system while servicing a request that
* has already acquired one of the required locks.)
*
* For this reason FspVolumeNotify does its processing asynchronously; it ships
* its payload as a work item to a system worker thread, which will perform the
* actual processing. See FspVolumeNotifyWork.
*/
ASSERT(IRP_MJ_FILE_SYSTEM_CONTROL == IrpSp->MajorFunction);
ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction);
ASSERT(FSP_FSCTL_NOTIFY == IrpSp->Parameters.FileSystemControl.FsControlCode);
ASSERT(METHOD_NEITHER == (IrpSp->Parameters.FileSystemControl.FsControlCode & 3));
ASSERT(0 != IrpSp->FileObject->FsContext2);
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PVOID InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
FSP_VOLUME_NOTIFY_WORK_ITEM *NotifyWorkItem = 0;
NTSTATUS Result;
if (0 == InputBufferLength)
return FspVolumeNotifyLock(FsvolDeviceObject);
if (!FspDeviceReference(FsvolDeviceObject))
return STATUS_CANCELLED;
NotifyWorkItem = FspAllocNonPaged(
FIELD_OFFSET(FSP_VOLUME_NOTIFY_WORK_ITEM, InputBuffer) + InputBufferLength);
if (0 == NotifyWorkItem)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto fail;
}
try
{
ProbeForRead(InputBuffer, InputBufferLength, 1);
RtlCopyMemory(NotifyWorkItem->InputBuffer, InputBuffer, InputBufferLength);
NotifyWorkItem->InputBufferLength = InputBufferLength;
}
except (EXCEPTION_EXECUTE_HANDLER)
{
Result = GetExceptionCode();
Result = FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
goto fail;
}
ExInitializeWorkItem(&NotifyWorkItem->WorkItem, FspVolumeNotifyWork, NotifyWorkItem);
NotifyWorkItem->FsvolDeviceObject = FsvolDeviceObject;
FspWgroupIncrement(&FsvolDeviceExtension->VolumeNotifyWgroup);
ExQueueWorkItem(&NotifyWorkItem->WorkItem, DelayedWorkQueue);
return STATUS_SUCCESS;
fail:
if (0 != NotifyWorkItem)
FspFree(NotifyWorkItem);
FspDeviceDereference(FsvolDeviceObject);
return Result;
}
static NTSTATUS FspVolumeNotifyLock(
PDEVICE_OBJECT FsvolDeviceObject)
{
PAGED_CODE();
NTSTATUS Result;
if (!FspDeviceReference(FsvolDeviceObject))
return STATUS_CANCELLED;
/*
* Acquire the rename lock shared to disallow concurrent RENAME's.
*
* This guards against the race where a file that we want to invalidate
* is being concurrently renamed to a different name. Thus we may think
* that the file is not open and not invalidate its caches, whereas the
* file has simply changed name.
*/
Result = STATUS_CANT_WAIT;
if (FspFsvolDeviceFileRenameTryAcquireShared(FsvolDeviceObject))
{
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
if (0 == InterlockedCompareExchange(&FsvolDeviceExtension->VolumeNotifyLock, 1, 0))
{
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, FsvolDeviceObject);
Result = STATUS_SUCCESS;
}
else
FspFsvolDeviceFileRenameRelease(FsvolDeviceObject);
}
FspDeviceDereference(FsvolDeviceObject);
return Result;
}
static VOID FspVolumeNotifyWork(PVOID NotifyWorkItem0)
{
PAGED_CODE();
FsRtlEnterFileSystem();
IoSetTopLevelIrp(0);
FSP_VOLUME_NOTIFY_WORK_ITEM *NotifyWorkItem = NotifyWorkItem0;
PDEVICE_OBJECT FsvolDeviceObject = NotifyWorkItem->FsvolDeviceObject;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
FSP_FSCTL_NOTIFY_INFO *NotifyInfo = (PVOID)NotifyWorkItem->InputBuffer;
PUINT8 NotifyInfoEnd = (PUINT8)NotifyInfo + NotifyWorkItem->InputBufferLength;
ULONG NotifyInfoSize;
UNICODE_STRING FileName = { 0 }, StreamPart = { 0 }, AbsFileName = { 0 }, FullFileName = { 0 };
ULONG StreamType = FspFileNameStreamTypeNone;
BOOLEAN Unlock = FALSE;
NTSTATUS Result;
/* iterate over notify information and invalidate/notify each file */
for (; (PUINT8)NotifyInfo + sizeof(NotifyInfo->Size) <= NotifyInfoEnd;
NotifyInfo = (PVOID)((PUINT8)NotifyInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(NotifyInfoSize)))
{
NotifyInfoSize = NotifyInfo->Size;
if (sizeof(FSP_FSCTL_NOTIFY_INFO) > NotifyInfoSize)
{
Unlock = TRUE;
break;
}
FileName.Length =
FileName.MaximumLength = (USHORT)(NotifyInfoSize - sizeof(FSP_FSCTL_NOTIFY_INFO));
FileName.Buffer = NotifyInfo->FileNameBuf;
if (sizeof(WCHAR) * 2/* not empty or root */ <= FileName.Length &&
L'\\' == FileName.Buffer[FileName.Length / sizeof(WCHAR) - 1])
FileName.Length -= sizeof(WCHAR);
if (!FspFileNameIsValid(&FileName, FsvolDeviceExtension->VolumeParams.MaxComponentLength,
FsvolDeviceExtension->VolumeParams.NamedStreams ? &StreamPart : 0,
&StreamType))
continue;
if (sizeof(WCHAR) <= FileName.Length && L'\\' == FileName.Buffer[0])
{
/* absolute file names are used as-is */
AbsFileName = FileName;
FspFileNodeInvalidateCachesAndNotifyChangeByName(FsvolDeviceObject,
&FileName, NotifyInfo->Filter, NotifyInfo->Action,
TRUE);
}
else if (0 != AbsFileName.Length)
{
/* relative file names are considered relative to the last absolute file name */
if (0 == FullFileName.Buffer)
{
FullFileName.Buffer = FspAllocatePoolMustSucceed(
NonPagedPool, FSP_FSCTL_TRANSACT_PATH_SIZEMAX, FSP_ALLOC_INTERNAL_TAG);
FullFileName.MaximumLength = FSP_FSCTL_TRANSACT_PATH_SIZEMAX;
}
FullFileName.Length = 0;
Result = RtlAppendUnicodeStringToString(&FullFileName, &AbsFileName);
if (NT_SUCCESS(Result))
{
if (sizeof(WCHAR) * 2/* not empty or root */ <= AbsFileName.Length)
Result = RtlAppendUnicodeToString(&FullFileName, L"\\");
}
if (NT_SUCCESS(Result))
Result = RtlAppendUnicodeStringToString(&FullFileName, &FileName);
if (NT_SUCCESS(Result))
FspFileNodeInvalidateCachesAndNotifyChangeByName(FsvolDeviceObject,
&FullFileName, NotifyInfo->Filter, NotifyInfo->Action,
FALSE);
}
}
if (0 != FullFileName.Buffer)
FspFree(FullFileName.Buffer);
FspFree(NotifyWorkItem);
FspWgroupDecrement(&FsvolDeviceExtension->VolumeNotifyWgroup);
if (Unlock)
{
FspWgroupWait(&FsvolDeviceExtension->VolumeNotifyWgroup, KernelMode, FALSE, 0);
if (1 == InterlockedCompareExchange(&FsvolDeviceExtension->VolumeNotifyLock, 0, 1))
FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, FsvolDeviceObject);
}
FspDeviceDereference(FsvolDeviceObject);
FsRtlExitFileSystem();
}
NTSTATUS FspVolumeWork(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{

View File

@ -347,6 +347,7 @@ STATUS_BAD_VALIDATION_CLASS ERROR_BAD_VALIDATION_CLASS
STATUS_BAD_TOKEN_TYPE ERROR_BAD_TOKEN_TYPE
STATUS_BAD_MASTER_BOOT_RECORD ERROR_INVALID_PARAMETER
STATUS_NO_SECURITY_ON_OBJECT ERROR_NO_SECURITY_ON_OBJECT
STATUS_CANT_WAIT ERROR_CANT_WAIT
STATUS_CANT_ACCESS_DOMAIN_INFO ERROR_CANT_ACCESS_DOMAIN_INFO
STATUS_INVALID_SERVER_STATE ERROR_INVALID_SERVER_STATE
STATUS_INVALID_DOMAIN_STATE ERROR_INVALID_DOMAIN_STATE

View File

@ -37,6 +37,7 @@ set dfl_tests=^
winfsp-tests-x64-mountpoint-dir-case-sensitive ^
winfsp-tests-x64-no-traverse ^
winfsp-tests-x64-oplock ^
winfsp-tests-x64-notify ^
winfsp-tests-x64-external ^
winfsp-tests-x64-external-share ^
fsx-memfs-x64-disk ^
@ -56,6 +57,7 @@ set dfl_tests=^
winfsp-tests-x86-mountpoint-dir-case-sensitive ^
winfsp-tests-x86-no-traverse ^
winfsp-tests-x86-oplock ^
winfsp-tests-x86-notify ^
winfsp-tests-x86-external ^
winfsp-tests-x86-external-share ^
fsx-memfs-x86-disk ^
@ -214,6 +216,11 @@ winfsp-tests-x64 --oplock=filter --resilient * +ea*
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-x64-notify
winfsp-tests-x64 --notify --resilient * +ea*
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-x86
winfsp-tests-x86 +*
if !ERRORLEVEL! neq 0 goto fail
@ -254,6 +261,11 @@ winfsp-tests-x86 --oplock=filter --resilient * +ea*
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-x86-notify
winfsp-tests-x86 --notify --resilient * +ea*
if !ERRORLEVEL! neq 0 goto fail
exit /b 0
:winfsp-tests-x64-external
M:
fltmc instances -v M: | findstr aswSnx >nul

View File

@ -21,6 +21,7 @@
#define WINFSP_TESTS_NO_HOOKS
#include "winfsp-tests.h"
#include <winfsp/winfsp.h>
#define FILENAMEBUF_SIZE 1024
@ -107,6 +108,75 @@ static VOID PrepareFileName(PCWSTR FileName, PWSTR FileNameBuf)
}
}
typedef struct
{
HANDLE VolumeHandle;
FSP_FSCTL_NOTIFY_INFO *NotifyInfo;
} MAYBE_NOTIFY_DATA;
static DWORD WINAPI MaybeNotifyRoutine(PVOID Context)
{
MAYBE_NOTIFY_DATA *NotifyData = Context;
/*
* The supplied VolumeHandle may be invalid or refer to the wrong object.
* This is ok because:
*
* - If the VolumeHandle is invalid, Windows will catch it and will fail the operation.
* - If the VolumeHandle refers to the wrong object, the FspFsctlNotify "should" fail
* because of an unknown DeviceIoControl code.
* - If the VolumeHandle refers to the wrong file system, it is still ok if we send an
* extraneous notify.
*/
FspFsctlNotify(NotifyData->VolumeHandle,
NotifyData->NotifyInfo, NotifyData->NotifyInfo->Size);
HeapFree(GetProcessHeap(), 0, NotifyData->NotifyInfo);
HeapFree(GetProcessHeap(), 0, NotifyData);
return 0;
}
static VOID MaybeNotify(PWSTR FileName, ULONG Filter, ULONG Action)
{
static WCHAR DevicePrefix[] =
L"\\\\?\\GLOBALROOT\\Device\\Volume{01234567-0123-0123-0101-010101010101}";
static WCHAR MemfsSharePrefix[] =
L"\\\\memfs\\share";
MAYBE_NOTIFY_DATA *NotifyData;
FSP_FSCTL_NOTIFY_INFO *NotifyInfo;
size_t L;
if (!OptNotify || OptExternal || 0 == memfs_handle)
return;
if (0 == wcsncmp(FileName, DevicePrefix, wcschr(DevicePrefix, L'{') - DevicePrefix))
FileName += wcslen(DevicePrefix);
else if (0 == mywcscmp(
FileName, (int)wcslen(MemfsSharePrefix), MemfsSharePrefix, (int)wcslen(MemfsSharePrefix)))
FileName += wcslen(MemfsSharePrefix);
else
return;
L = wcslen(FileName);
NotifyData = HeapAlloc(GetProcessHeap(), 0, sizeof *NotifyData);
NotifyInfo = HeapAlloc(GetProcessHeap(), 0, sizeof *NotifyInfo + L * sizeof(WCHAR));
if (0 == NotifyData || 0 == NotifyInfo)
ABORT("cannot malloc notify data");
NotifyInfo->Size = (UINT16)(sizeof *NotifyInfo + L * sizeof(WCHAR));
NotifyInfo->Filter = Filter;
NotifyInfo->Action = Action;
memcpy(NotifyInfo->FileNameBuf, FileName, L * sizeof(WCHAR));
NotifyData->VolumeHandle = memfs_handle;
NotifyData->NotifyInfo = NotifyInfo;
if (!QueueUserWorkItem(MaybeNotifyRoutine, NotifyData, 0))
ABORT("cannot queue notify data");
}
typedef struct
{
HANDLE File;
@ -210,6 +280,9 @@ HANDLE WINAPI HookCreateFileW(
PrepareFileName(lpFileName, FileNameBuf);
MaybeNotify(FileNameBuf,
FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED);
MaybeRequestOplock(FileNameBuf);
MaybeAdjustTraversePrivilege(FALSE);
@ -241,6 +314,9 @@ BOOL WINAPI HookSetFileAttributesW(
PrepareFileName(lpFileName, FileNameBuf);
MaybeNotify(FileNameBuf,
FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED);
MaybeAdjustTraversePrivilege(FALSE);
Success = SetFileAttributesW(FileNameBuf, dwFileAttributes);
MaybeAdjustTraversePrivilege(TRUE);
@ -256,6 +332,9 @@ BOOL WINAPI HookCreateDirectoryW(
PrepareFileName(lpPathName, FileNameBuf);
MaybeNotify(FileNameBuf,
FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED);
MaybeAdjustTraversePrivilege(FALSE);
Success = CreateDirectoryW(FileNameBuf, lpSecurityAttributes);
MaybeAdjustTraversePrivilege(TRUE);
@ -270,6 +349,9 @@ BOOL WINAPI HookDeleteFileW(
PrepareFileName(lpFileName, FileNameBuf);
MaybeNotify(FileNameBuf,
FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED);
MaybeRequestOplock(FileNameBuf);
MaybeAdjustTraversePrivilege(FALSE);
@ -287,6 +369,9 @@ BOOL WINAPI HookRemoveDirectoryW(
PrepareFileName(lpPathName, FileNameBuf);
MaybeNotify(FileNameBuf,
FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED);
MaybeAdjustTraversePrivilege(FALSE);
Success = (OptResilient ? ResilientRemoveDirectoryW : RemoveDirectoryW)(
FileNameBuf);
@ -306,6 +391,13 @@ BOOL WINAPI HookMoveFileExW(
PrepareFileName(lpExistingFileName, OldFileNameBuf);
PrepareFileName(lpNewFileName, NewFileNameBuf);
MaybeNotify(OldFileNameBuf,
FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED);
if (OptCaseInsensitive ?
_wcsicmp(OldFileNameBuf, NewFileNameBuf) : wcscmp(OldFileNameBuf, NewFileNameBuf))
MaybeNotify(NewFileNameBuf,
FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED);
MaybeRequestOplock(OldFileNameBuf);
if (OptCaseInsensitive ?
_wcsicmp(OldFileNameBuf, NewFileNameBuf) : wcscmp(OldFileNameBuf, NewFileNameBuf))
@ -326,6 +418,9 @@ HANDLE WINAPI HookFindFirstFileW(
PrepareFileName(lpFileName, FileNameBuf);
MaybeNotify(FileNameBuf,
FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED);
MaybeAdjustTraversePrivilege(FALSE);
Handle = FindFirstFileW(FileNameBuf, lpFindFileData);
MaybeAdjustTraversePrivilege(TRUE);
@ -343,6 +438,9 @@ HANDLE WINAPI HookFindFirstStreamW(
PrepareFileName(lpFileName, FileNameBuf);
MaybeNotify(FileNameBuf,
FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED);
MaybeAdjustTraversePrivilege(FALSE);
Handle = FindFirstStreamW(FileNameBuf, InfoLevel, lpFindStreamData, dwFlags);
MaybeAdjustTraversePrivilege(TRUE);
@ -426,6 +524,9 @@ BOOL WINAPI HookSetCurrentDirectoryW(
PrepareFileName(lpPathName, FileNameBuf);
MaybeNotify(FileNameBuf,
FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED);
MaybeAdjustTraversePrivilege(FALSE);
Success = SetCurrentDirectoryW(FileNameBuf);
MaybeAdjustTraversePrivilege(TRUE);
@ -449,6 +550,9 @@ BOOL WINAPI HookCreateProcessW(
PrepareFileName(lpApplicationName, FileNameBuf);
MaybeNotify(FileNameBuf,
FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED);
MaybeAdjustTraversePrivilege(FALSE);
Success = CreateProcessW(FileNameBuf,
lpCommandLine, /* we should probably change this as well */

View File

@ -27,6 +27,7 @@
#include "winfsp-tests.h"
int memfs_running;
HANDLE memfs_handle;
void *memfs_start_ex(ULONG Flags, ULONG FileInfoTimeout)
{
@ -66,6 +67,7 @@ void *memfs_start_ex(ULONG Flags, ULONG FileInfoTimeout)
ASSERT(NT_SUCCESS(Result));
memfs_running = 1;
memfs_handle = MemfsFileSystem(Memfs)->VolumeHandle;
return Memfs;
}
@ -77,6 +79,7 @@ void *memfs_start(ULONG Flags)
void memfs_stop(void *data)
{
memfs_handle = 0;
memfs_running = 0;
if (0 == data)

View File

@ -0,0 +1,460 @@
/**
* @file notify-test.c
*
* @copyright 2015-2020 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 <process.h>
#include <strsafe.h>
#include "memfs.h"
#include "winfsp-tests.h"
static
void notify_abandon_dotest(ULONG Flags)
{
void *memfs = memfs_start(Flags);
FSP_FILE_SYSTEM *FileSystem = MemfsFileSystem(memfs);
NTSTATUS Result;
Result = FspFsctlNotify(FileSystem->VolumeHandle, 0, 0);
ASSERT(STATUS_SUCCESS == Result);
Result = FspFsctlNotify(FileSystem->VolumeHandle, 0, 0);
ASSERT(STATUS_CANT_WAIT == Result);
memfs_stop(memfs);
}
static
void notify_abandon_test(void)
{
if (WinFspDiskTests)
notify_abandon_dotest(MemfsDisk);
if (WinFspNetTests)
notify_abandon_dotest(MemfsNet);
}
static
unsigned __stdcall notify_abandon_rename_dotest_thread(void *FilePath)
{
FspDebugLog(__FUNCTION__ ": \"%S\"\n", FilePath);
WCHAR NewFilePath[MAX_PATH];
HANDLE Handle;
BOOL Success;
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
if (INVALID_HANDLE_VALUE == Handle)
return GetLastError();
CloseHandle(Handle);
StringCbPrintfW(NewFilePath, sizeof NewFilePath, L"%s.new", FilePath);
Success = MoveFileExW(FilePath, NewFilePath, 0);
return Success ? 0 : GetLastError();
}
static
void notify_abandon_rename_dotest(ULONG Flags, PWSTR Prefix)
{
void *memfs = memfs_start(Flags);
FSP_FILE_SYSTEM *FileSystem = MemfsFileSystem(memfs);
WCHAR FilePath[MAX_PATH];
HANDLE Thread;
DWORD ExitCode;
NTSTATUS Result;
Result = FspFsctlNotify(FileSystem->VolumeHandle, 0, 0);
ASSERT(STATUS_SUCCESS == Result);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\file0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Thread = (HANDLE)_beginthreadex(0, 0, notify_abandon_rename_dotest_thread, FilePath, 0, 0);
ASSERT(0 != Thread);
Sleep(1000);
memfs_stop(memfs);
WaitForSingleObject(Thread, INFINITE);
GetExitCodeThread(Thread, &ExitCode);
CloseHandle(Thread);
ASSERT(ERROR_OPERATION_ABORTED == ExitCode);
}
static
void notify_abandon_rename_test(void)
{
if (WinFspDiskTests)
notify_abandon_rename_dotest(MemfsDisk, 0);
if (WinFspNetTests)
notify_abandon_rename_dotest(MemfsNet, L"\\\\memfs\\share");
}
static
void notify_timeout_dotest(ULONG Flags)
{
void *memfs = memfs_start(Flags);
FSP_FILE_SYSTEM *FileSystem = MemfsFileSystem(memfs);
NTSTATUS Result;
Result = FspFsctlNotify(FileSystem->VolumeHandle, 0, 0);
ASSERT(STATUS_SUCCESS == Result);
Result = FspFileSystemNotifyBegin(FileSystem, 0);
ASSERT(STATUS_CANT_WAIT == Result);
Result = FspFileSystemNotifyBegin(FileSystem, 9);
ASSERT(STATUS_CANT_WAIT == Result);
Result = FspFileSystemNotifyBegin(FileSystem, 10);
ASSERT(STATUS_CANT_WAIT == Result);
Result = FspFileSystemNotifyBegin(FileSystem, 11);
ASSERT(STATUS_CANT_WAIT == Result);
Result = FspFileSystemNotifyBegin(FileSystem, 20);
ASSERT(STATUS_CANT_WAIT == Result);
Result = FspFileSystemNotifyBegin(FileSystem, 1000);
ASSERT(STATUS_CANT_WAIT == Result);
memfs_stop(memfs);
}
static
void notify_timeout_test(void)
{
if (WinFspDiskTests)
notify_timeout_dotest(MemfsDisk);
if (WinFspNetTests)
notify_timeout_dotest(MemfsNet);
}
static
void notify_change_dotest(ULONG Flags)
{
void *memfs = memfs_start(Flags);
FSP_FILE_SYSTEM *FileSystem = MemfsFileSystem(memfs);
union
{
FSP_FSCTL_NOTIFY_INFO V;
UINT8 B[1024];
} Buffer;
ULONG Length = 0;
union
{
FSP_FSCTL_NOTIFY_INFO V;
UINT8 B[sizeof(FSP_FSCTL_NOTIFY_INFO) + MAX_PATH * sizeof(WCHAR)];
} NotifyInfo;
PWSTR FileName;
NTSTATUS Result;
Result = FspFileSystemNotifyBegin(FileSystem, 0);
ASSERT(STATUS_SUCCESS == Result);
FileName = L"\\";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_LAST_WRITE;
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"bar";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_LAST_WRITE;
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"baz";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_LAST_WRITE;
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"\\foo";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_LAST_WRITE;
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"bar";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_LAST_WRITE;
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"baz";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_LAST_WRITE;
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"\\foo\\";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_LAST_WRITE;
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"bar";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_LAST_WRITE;
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"baz";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_LAST_WRITE;
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
Result = FspFileSystemNotify(FileSystem, &Buffer.V, Length);
ASSERT(STATUS_SUCCESS == Result);
Result = FspFileSystemNotifyEnd(FileSystem);
ASSERT(STATUS_SUCCESS == Result);
memfs_stop(memfs);
}
static
void notify_change_test(void)
{
if (WinFspDiskTests)
notify_change_dotest(MemfsDisk);
if (WinFspNetTests)
notify_change_dotest(MemfsNet);
}
static
void notify_open_change_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
FSP_FILE_SYSTEM *FileSystem = MemfsFileSystem(memfs);
HANDLE DirHandle, FileHandle;
WCHAR FilePath[MAX_PATH];
union
{
FSP_FSCTL_NOTIFY_INFO V;
UINT8 B[sizeof(FSP_FSCTL_NOTIFY_INFO) + MAX_PATH * sizeof(WCHAR)];
} NotifyInfo;
PWSTR FileName;
BOOL Success;
NTSTATUS Result;
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = CreateDirectoryW(FilePath, 0);
ASSERT(Success);
DirHandle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE, 0);
ASSERT(INVALID_HANDLE_VALUE != DirHandle);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1\\file0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
FileHandle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != FileHandle);
//DWORD Bytes;
//Success = WriteFile(FileHandle, "foobar", 6, &Bytes, 0);
//ASSERT(Success);
Result = FspFileSystemNotifyBegin(FileSystem, 1000);
ASSERT(STATUS_SUCCESS == Result);
FileName = L"\\dir1";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_LAST_WRITE;
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
Result = FspFileSystemNotify(FileSystem, &NotifyInfo.V, NotifyInfo.V.Size);
ASSERT(STATUS_SUCCESS == Result);
FileName = L"\\dir1\\file0";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_LAST_WRITE;
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
Result = FspFileSystemNotify(FileSystem, &NotifyInfo.V, NotifyInfo.V.Size);
ASSERT(STATUS_SUCCESS == Result);
Result = FspFileSystemNotifyEnd(FileSystem);
ASSERT(STATUS_SUCCESS == Result);
CloseHandle(FileHandle);
CloseHandle(DirHandle);
memfs_stop(memfs);
}
static
void notify_open_change_test(void)
{
if (WinFspDiskTests)
{
notify_open_change_dotest(MemfsDisk, 0, 0);
notify_open_change_dotest(MemfsDisk, 0, 1000);
notify_open_change_dotest(MemfsDisk, 0, INFINITE);
}
if (WinFspNetTests)
{
notify_open_change_dotest(MemfsNet, L"\\\\memfs\\share", 0);
notify_open_change_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
notify_open_change_dotest(MemfsNet, L"\\\\memfs\\share", INFINITE);
}
}
static
unsigned __stdcall notify_dirnotify_dotest_thread(void *FileSystem0)
{
FspDebugLog(__FUNCTION__ "\n");
FSP_FILE_SYSTEM *FileSystem = FileSystem0;
union
{
FSP_FSCTL_NOTIFY_INFO V;
UINT8 B[sizeof(FSP_FSCTL_NOTIFY_INFO) + MAX_PATH * sizeof(WCHAR)];
} NotifyInfo;
PWSTR FileName;
NTSTATUS Result;
Sleep(1000); /* wait for ReadDirectoryChangesW */
FileName = L"\\Directory\\Subdirectory\\file0";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_FILE_NAME;
NotifyInfo.V.Action = FILE_ACTION_ADDED;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
Result = FspFileSystemNotify(FileSystem, &NotifyInfo.V, NotifyInfo.V.Size);
return Result;
}
static
void notify_dirnotify_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
FSP_FILE_SYSTEM *FileSystem = MemfsFileSystem(memfs);
WCHAR FilePath[MAX_PATH];
HANDLE Handle;
BOOL Success;
HANDLE Thread;
DWORD ExitCode;
DWORD BytesTransferred;
PFILE_NOTIFY_INFORMATION NotifyInfo;
NotifyInfo = malloc(4096);
ASSERT(0 != NotifyInfo);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\Directory",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = CreateDirectoryW(FilePath, 0);
ASSERT(Success);
Handle = CreateFileW(FilePath,
FILE_LIST_DIRECTORY, FILE_SHARE_READ, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Thread = (HANDLE)_beginthreadex(0, 0, notify_dirnotify_dotest_thread, FileSystem, 0, 0);
ASSERT(0 != Thread);
Success = ReadDirectoryChangesW(Handle,
NotifyInfo, 4096, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME, &BytesTransferred, 0, 0);
ASSERT(Success);
ASSERT(0 < BytesTransferred);
ASSERT(FILE_ACTION_ADDED == NotifyInfo->Action);
ASSERT(wcslen(L"Subdirectory\\file0") * sizeof(WCHAR) == NotifyInfo->FileNameLength);
ASSERT(0 == mywcscmp(L"Subdirectory\\file0", -1,
NotifyInfo->FileName, NotifyInfo->FileNameLength / sizeof(WCHAR)));
ASSERT(0 == NotifyInfo->NextEntryOffset);
WaitForSingleObject(Thread, INFINITE);
GetExitCodeThread(Thread, &ExitCode);
CloseHandle(Thread);
ASSERT(STATUS_SUCCESS == ExitCode);
Success = CloseHandle(Handle);
ASSERT(Success);
Success = RemoveDirectoryW(FilePath);
ASSERT(Success);
free(NotifyInfo);
memfs_stop(memfs);
}
static
void notify_dirnotify_test(void)
{
if (WinFspDiskTests &&
!OptNoTraverseToken /* WinFsp does not support change notifications w/o traverse privilege */ &&
!OptCaseRandomize)
{
notify_dirnotify_dotest(MemfsDisk, 0, 0);
notify_dirnotify_dotest(MemfsDisk, 0, 1000);
notify_dirnotify_dotest(MemfsDisk, 0, INFINITE);
}
if (WinFspNetTests &&
!OptNoTraverseToken /* WinFsp does not support change notifications w/o traverse privilege */ &&
!OptCaseRandomize)
{
notify_dirnotify_dotest(MemfsNet, L"\\\\memfs\\share", 0);
notify_dirnotify_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
notify_dirnotify_dotest(MemfsNet, L"\\\\memfs\\share", INFINITE);
}
}
void notify_tests(void)
{
if (OptExternal || OptNotify)
return;
TEST(notify_abandon_test);
TEST(notify_abandon_rename_test);
TEST(notify_timeout_test);
TEST(notify_change_test);
TEST(notify_open_change_test);
TEST(notify_dirnotify_test);
}

View File

@ -20,6 +20,7 @@
*/
#include <windows.h>
#include <dbghelp.h>
#include <lm.h>
#include <signal.h>
#include <tlib/testsuite.h>
@ -38,6 +39,7 @@ BOOLEAN OptCaseInsensitiveCmp = FALSE;
BOOLEAN OptCaseInsensitive = FALSE;
BOOLEAN OptCaseRandomize = FALSE;
BOOLEAN OptFlushAndPurgeOnCleanup = FALSE;
BOOLEAN OptNotify = FALSE;
WCHAR OptOplock = 0;
WCHAR OptMountPointBuf[MAX_PATH], *OptMountPoint;
WCHAR OptShareNameBuf[MAX_PATH], *OptShareName, *OptShareTarget;
@ -174,6 +176,37 @@ static void abort_handler(int sig)
LONG WINAPI UnhandledExceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
if (0 != ExceptionInfo && 0 != ExceptionInfo->ExceptionRecord)
{
static CHAR OutBuf[128];
static union
{
SYMBOL_INFO V;
UINT8 Buf[sizeof(SYMBOL_INFO) + 64];
} Info;
LARGE_INTEGER Large;
Info.V.SizeOfStruct = sizeof(SYMBOL_INFO);
Info.V.MaxNameLen = 64;
if (SymFromAddr(GetCurrentProcess(),
(DWORD64)ExceptionInfo->ExceptionRecord->ExceptionAddress,
&Large.QuadPart,
&Info.V))
{
wsprintfA(OutBuf, "\nEXCEPTION 0x%lX at %s+0x%lX(0x%p)\n",
ExceptionInfo->ExceptionRecord->ExceptionCode,
Info.V.Name,
Large.LowPart,
ExceptionInfo->ExceptionRecord->ExceptionAddress);
}
else
{
wsprintfA(OutBuf, "\nEXCEPTION 0x%lX at 0x%p\n",
ExceptionInfo->ExceptionRecord->ExceptionCode,
ExceptionInfo->ExceptionRecord->ExceptionAddress);
}
WriteFile(GetStdHandle(STD_ERROR_HANDLE), OutBuf, lstrlenA(OutBuf), &Large.LowPart, 0);
}
exiting();
return EXCEPTION_EXECUTE_HANDLER;
}
@ -211,12 +244,17 @@ int main(int argc, char *argv[])
TESTSUITE(ea_tests);
TESTSUITE(stream_tests);
TESTSUITE(oplock_tests);
TESTSUITE(notify_tests);
TESTSUITE(wsl_tests);
TESTSUITE(volpath_tests);
SymInitialize(GetCurrentProcess(), 0, TRUE);
atexit(exiting);
signal(SIGABRT, abort_handler);
SetUnhandledExceptionFilter(UnhandledExceptionHandler);
#pragma warning(suppress: 4996)
if (0 == getenv("WINFSP_TESTS_EXCEPTION_FILTER_DISABLE"))
SetUnhandledExceptionFilter(UnhandledExceptionHandler);
for (int argi = 1; argc > argi; argi++)
{
@ -258,6 +296,11 @@ int main(int argc, char *argv[])
OptFlushAndPurgeOnCleanup = TRUE;
rmarg(argv, argc, argi);
}
else if (0 == strcmp("--notify", a))
{
OptNotify = TRUE;
rmarg(argv, argc, argi);
}
else if (0 == strcmp("--oplock=batch", a))
{
OptOplock = 'B';

View File

@ -159,6 +159,7 @@ extern BOOLEAN OptCaseInsensitiveCmp;
extern BOOLEAN OptCaseInsensitive;
extern BOOLEAN OptCaseRandomize;
extern BOOLEAN OptFlushAndPurgeOnCleanup;
extern BOOLEAN OptNotify;
extern WCHAR OptOplock;
extern WCHAR OptMountPointBuf[], *OptMountPoint;
extern WCHAR OptShareNameBuf[], *OptShareName, *OptShareTarget;
@ -168,3 +169,4 @@ extern HANDLE OptNoTraverseToken;
extern LUID OptNoTraverseLuid;
extern int memfs_running;
extern HANDLE memfs_handle;