diff --git a/build/VStudio/testing/fscrash.vcxproj b/build/VStudio/testing/fscrash.vcxproj
new file mode 100644
index 00000000..0ebd1b87
--- /dev/null
+++ b/build/VStudio/testing/fscrash.vcxproj
@@ -0,0 +1,185 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ {10757011-749D-4954-873B-AE38D8145472}
+ Win32Proj
+ fscrash
+ 8.1
+
+
+
+ Application
+ true
+ v140
+ Unicode
+
+
+ Application
+ false
+ v140
+ true
+ Unicode
+
+
+ Application
+ true
+ v140
+ Unicode
+
+
+ Application
+ false
+ v140
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)build\$(Configuration)\
+ $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\
+ $(ProjectName)-$(PlatformTarget)
+
+
+ true
+ $(SolutionDir)build\$(Configuration)\
+ $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\
+ $(ProjectName)-$(PlatformTarget)
+
+
+ false
+ $(SolutionDir)build\$(Configuration)\
+ $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\
+ $(ProjectName)-$(PlatformTarget)
+
+
+ false
+ $(SolutionDir)build\$(Configuration)\
+ $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\
+ $(ProjectName)-$(PlatformTarget)
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ ..\..\..\tst\memfs;..\..\..\inc
+
+
+ Console
+ true
+
+
+
+
+
+
+ Level3
+ Disabled
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ ..\..\..\tst\memfs;..\..\..\inc
+
+
+ Console
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ ..\..\..\tst\memfs;..\..\..\inc
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ ..\..\..\tst\memfs;..\..\..\inc
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {4a7c0b21-9e10-4c81-92de-1493efcf24eb}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build/VStudio/testing/fscrash.vcxproj.filters b/build/VStudio/testing/fscrash.vcxproj.filters
new file mode 100644
index 00000000..5f5dfd53
--- /dev/null
+++ b/build/VStudio/testing/fscrash.vcxproj.filters
@@ -0,0 +1,28 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+
+
+ Source
+
+
+ Source
+
+
+
\ No newline at end of file
diff --git a/build/VStudio/winfsp.sln b/build/VStudio/winfsp.sln
index efed5384..79b70563 100644
--- a/build/VStudio/winfsp.sln
+++ b/build/VStudio/winfsp.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
-VisualStudioVersion = 14.0.25123.0
+VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winfsp.dll", "winfsp_dll.vcxproj", "{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}"
ProjectSection(ProjectDependencies) = postProject
@@ -45,6 +45,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launchctl", "launcher\launc
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {A5EFD487-0140-4184-8C54-FFAEC2F85E35}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fscrash", "testing\fscrash.vcxproj", "{10757011-749D-4954-873B-AE38D8145472}"
+ ProjectSection(ProjectDependencies) = postProject
+ {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}
+ {C85C26BA-8C22-4D30-83DA-46C3548E6332} = {C85C26BA-8C22-4D30-83DA-46C3548E6332}
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -153,6 +159,22 @@ Global
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.Build.0 = Release|x64
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.ActiveCfg = Release|Win32
{73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.Build.0 = Release|Win32
+ {10757011-749D-4954-873B-AE38D8145472}.Debug|x64.ActiveCfg = Debug|x64
+ {10757011-749D-4954-873B-AE38D8145472}.Debug|x64.Build.0 = Debug|x64
+ {10757011-749D-4954-873B-AE38D8145472}.Debug|x86.ActiveCfg = Debug|Win32
+ {10757011-749D-4954-873B-AE38D8145472}.Debug|x86.Build.0 = Debug|Win32
+ {10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x64.ActiveCfg = Debug|x64
+ {10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x64.Build.0 = Debug|x64
+ {10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x86.ActiveCfg = Debug|Win32
+ {10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x86.Build.0 = Debug|Win32
+ {10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x64.ActiveCfg = Release|x64
+ {10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x64.Build.0 = Release|x64
+ {10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x86.ActiveCfg = Release|Win32
+ {10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x86.Build.0 = Release|Win32
+ {10757011-749D-4954-873B-AE38D8145472}.Release|x64.ActiveCfg = Release|x64
+ {10757011-749D-4954-873B-AE38D8145472}.Release|x64.Build.0 = Release|x64
+ {10757011-749D-4954-873B-AE38D8145472}.Release|x86.ActiveCfg = Release|Win32
+ {10757011-749D-4954-873B-AE38D8145472}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -164,5 +186,6 @@ Global
{95C223E6-B5F1-4FD0-9376-41CDBC824445} = {B464EF06-42AE-4674-81BB-FDDE80204822}
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
{73EAAEDA-557B-48D5-A137-328934720FB4} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
+ {10757011-749D-4954-873B-AE38D8145472} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
EndGlobalSection
EndGlobal
diff --git a/tst/fscrash/fscrash-main.c b/tst/fscrash/fscrash-main.c
new file mode 100644
index 00000000..588e4c50
--- /dev/null
+++ b/tst/fscrash/fscrash-main.c
@@ -0,0 +1,90 @@
+/**
+ * @file fscrash-main.c
+ *
+ * @copyright 2015-2016 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 file in
+ * accordance with the commercial license agreement provided with the
+ * software.
+ */
+
+#include
+
+#include "fscrash.h"
+#include "memfs.h"
+
+#define fail(format, ...) fprintf(stderr, format, __VA_ARGS__)
+
+ULONG OptCrashMask = -1, OptCrashFlags = FspCrashInterceptAccessViolation, OptCrashPercent = 10;
+ULONG OptMemfsFlags = MemfsDisk;
+
+int wmain(int argc, wchar_t **argv)
+{
+ for (int argi = 1; argc > argi; argi++)
+ {
+ const wchar_t *a = argv[argi];
+ if ('-' == a[0])
+ {
+ if (0 == wcsncmp(L"--mask=", a, sizeof "--mask=" - 1))
+ OptCrashMask = wcstoul(a + sizeof "--mask=" - 1, 0, 0);
+ else if (0 == wcsncmp(L"--percent=", a, sizeof "--percent=" - 1))
+ OptCrashPercent = wcstoul(a + sizeof "--percent=" - 1, 0, 10);
+ else if (0 == wcscmp(L"--crash", a))
+ {
+ OptCrashFlags &= ~FspCrashInterceptTerminate;
+ OptCrashFlags |= FspCrashInterceptAccessViolation;
+ }
+ else if (0 == wcscmp(L"--terminate", a))
+ {
+ OptCrashFlags &= ~FspCrashInterceptAccessViolation;
+ OptCrashFlags |= FspCrashInterceptTerminate;
+ }
+ else if (0 == wcscmp(L"--enter", a))
+ OptCrashFlags |= FspCrashInterceptEnter;
+ else if (0 == wcscmp(L"--leave", a))
+ OptCrashFlags |= FspCrashInterceptLeave;
+ else if (0 == wcscmp(L"--disk", a))
+ OptMemfsFlags = MemfsDisk;
+ else if (0 == wcscmp(L"--n", a))
+ OptMemfsFlags = MemfsDisk;
+ }
+ }
+
+ MEMFS *Memfs;
+ NTSTATUS Result;
+
+ Result = MemfsCreate(
+ OptMemfsFlags,
+ -1,
+ 1024,
+ 1024 * 1024,
+ (MemfsNet & OptMemfsFlags) ? L"\\memfs\\share" : 0,
+ 0,
+ &Memfs);
+ if (!NT_SUCCESS(Result))
+ {
+ fail("cannot create MEMFS file system: (Status=%lx)", Result);
+ exit(1);
+ }
+
+ FspCrashIntercept(MemfsFileSystem(Memfs), OptCrashMask, OptCrashFlags, OptCrashPercent);
+
+ Result = MemfsStart(Memfs);
+ if (!NT_SUCCESS(Result))
+ {
+ fail("cannot start MEMFS file system: (Status=%lx)", Result);
+ exit(1);
+ }
+
+ MemfsStop(Memfs);
+ MemfsDelete(Memfs);
+
+ return 0;
+}
diff --git a/tst/fscrash/fscrash.c b/tst/fscrash/fscrash.c
new file mode 100644
index 00000000..57990bf4
--- /dev/null
+++ b/tst/fscrash/fscrash.c
@@ -0,0 +1,132 @@
+/**
+ * @file fscrash.c
+ *
+ * @copyright 2015-2016 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 file in
+ * accordance with the commercial license agreement provided with the
+ * software.
+ */
+
+#include "fscrash.h"
+
+static SRWLOCK FspCrashLock = SRWLOCK_INIT;
+static FSP_FILE_SYSTEM *FspCrashFileSystem;
+static ULONG FspCrashPercent;
+static FSP_FILE_SYSTEM_OPERATION *FspCrashInterceptedOperations
+ [ARRAYSIZE(((FSP_FILE_SYSTEM *)0)->Operations)];
+static volatile PULONG FspCrashNullPointer;
+
+static unsigned FspCrashRandSeed = 1;
+static int FspCrashRand(void)
+{
+ /*
+ * This mimics MSVCRT rand(); we need our own version
+ * as to not interfere with the program's rand().
+ */
+
+ FspCrashRandSeed = FspCrashRandSeed * 214013 + 2531011;
+ return (FspCrashRandSeed >> 16) & RAND_MAX;
+}
+
+static __forceinline BOOLEAN FspCrashInterceptTest(FSP_FILE_SYSTEM *FileSystem)
+{
+ BOOLEAN Result;
+ AcquireSRWLockShared(&FspCrashLock);
+ Result = FileSystem == FspCrashFileSystem &&
+ FspCrashRand() < (LONG)FspCrashPercent * 0x7fff / 100;
+ ReleaseSRWLockShared(&FspCrashLock);
+ return Result;
+}
+
+#define DefineInterceptor(NAME, CRASH, ENTER, LEAVE)\
+ static NTSTATUS NAME(FSP_FILE_SYSTEM *FileSystem,\
+ FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)\
+ {\
+ NTSTATUS Result;\
+ if (ENTER)\
+ {\
+ if (FspCrashInterceptTest(FileSystem))\
+ {\
+ if (CRASH)\
+ *FspCrashNullPointer = 0x42424242;\
+ else\
+ TerminateProcess(GetCurrentProcess(), STATUS_UNSUCCESSFUL);\
+ }\
+ }\
+ Result = FspCrashInterceptedOperations[Request->Kind](FileSystem, Request, Response);\
+ if (LEAVE)\
+ {\
+ if (FspCrashInterceptTest(FileSystem))\
+ {\
+ if (CRASH)\
+ *FspCrashNullPointer = 0x42424242;\
+ else\
+ TerminateProcess(GetCurrentProcess(), STATUS_UNSUCCESSFUL);\
+ }\
+ }\
+ return Result;\
+ }
+
+DefineInterceptor(FspCrashInterceptorCE, TRUE, TRUE, FALSE)
+DefineInterceptor(FspCrashInterceptorCL, TRUE, FALSE, TRUE)
+DefineInterceptor(FspCrashInterceptorCB, TRUE, TRUE, TRUE)
+DefineInterceptor(FspCrashInterceptorTE, FALSE, TRUE, FALSE)
+DefineInterceptor(FspCrashInterceptorTL, FALSE, FALSE, TRUE)
+DefineInterceptor(FspCrashInterceptorTB, FALSE, TRUE, TRUE)
+
+VOID FspCrashIntercept(FSP_FILE_SYSTEM *FileSystem,
+ ULONG CrashMask, ULONG CrashFlags, ULONG CrashPercent)
+{
+ FSP_FILE_SYSTEM_OPERATION *Interceptor = 0;
+
+ if (CrashFlags & FspCrashInterceptAccessViolation)
+ {
+ if (FspCrashInterceptEnter == (CrashFlags & FspCrashInterceptEnter))
+ Interceptor = FspCrashInterceptorCE;
+ else
+ if (FspCrashInterceptLeave == (CrashFlags & FspCrashInterceptLeave))
+ Interceptor = FspCrashInterceptorCL;
+ else
+ Interceptor = FspCrashInterceptorCB;
+ }
+ else
+ {
+ if (FspCrashInterceptEnter == (CrashFlags & FspCrashInterceptEnter))
+ Interceptor = FspCrashInterceptorTE;
+ else
+ if (FspCrashInterceptLeave == (CrashFlags & FspCrashInterceptLeave))
+ Interceptor = FspCrashInterceptorTL;
+ else
+ Interceptor = FspCrashInterceptorTB;
+ }
+
+ RtlCopyMemory(FspCrashInterceptedOperations,
+ FileSystem->Operations, sizeof FileSystem->Operations);
+
+ for (ULONG Index = 0; ARRAYSIZE(FileSystem->Operations) > Index; Index++)
+ if (0 != ((1 << Index) & CrashMask) && 0 != FileSystem->Operations[Index])
+ FileSystem->Operations[Index] = Interceptor;
+
+ FspCrashPercent = CrashPercent;
+
+ FspCrashRandSeed = GetTickCount();
+ if (0 == FspCrashRandSeed)
+ FspCrashRandSeed = 1;
+
+ MemoryBarrier();
+}
+
+VOID FspCrash(FSP_FILE_SYSTEM *FileSystem)
+{
+ AcquireSRWLockExclusive(&FspCrashLock);
+ FspCrashFileSystem = FileSystem;
+ ReleaseSRWLockExclusive(&FspCrashLock);
+}
diff --git a/tst/fscrash/fscrash.h b/tst/fscrash/fscrash.h
new file mode 100644
index 00000000..feeec606
--- /dev/null
+++ b/tst/fscrash/fscrash.h
@@ -0,0 +1,43 @@
+/**
+ * @file fscrash.h
+ *
+ * @copyright 2015-2016 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 file in
+ * accordance with the commercial license agreement provided with the
+ * software.
+ */
+
+#ifndef FSCRASH_H_INCLUDED
+#define FSCRASH_H_INCLUDED
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum
+{
+ FspCrashInterceptAccessViolation = 0x01,
+ FspCrashInterceptTerminate = 0x02,
+ FspCrashInterceptEnter = 0x10,
+ FspCrashInterceptLeave = 0x20,
+};
+
+VOID FspCrashIntercept(FSP_FILE_SYSTEM *FileSystem,
+ ULONG CrashMask, ULONG CrashFlags, ULONG CrashPercent);
+VOID FspCrash(FSP_FILE_SYSTEM *FileSystem);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif