tst: winfsp-tests: exec-test

This commit is contained in:
Bill Zissimopoulos 2017-02-12 00:26:20 -08:00
parent cf69d6a08d
commit 495c78eb25
11 changed files with 404 additions and 0 deletions

View File

@ -185,6 +185,7 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\dirctl-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\dirctl-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\exec-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\flush-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\flush-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\hooks.c" /> <ClCompile Include="..\..\..\tst\winfsp-tests\hooks.c" />
@ -213,6 +214,9 @@
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project> <Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\tst\winfsp-tests\helper\winfsp-tests-helper.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>

View File

@ -79,6 +79,9 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c"> <ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c">
<Filter>Source</Filter> <Filter>Source</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\exec-test.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h"> <ClInclude Include="..\..\..\ext\tlib\testsuite.h">
@ -91,4 +94,9 @@
<Filter>Source</Filter> <Filter>Source</Filter>
</ClInclude> </ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\tst\winfsp-tests\helper\winfsp-tests-helper.rc">
<Filter>Source</Filter>
</ResourceCompile>
</ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,228 @@
/**
* @file exec-test.c
*
* @copyright 2015-2017 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 <winfsp/winfsp.h>
#include <tlib/testsuite.h>
#include <strsafe.h>
#include "memfs.h"
#include "winfsp-tests.h"
static NTSTATUS WriteResource(
HANDLE Handle, HANDLE Module, PWSTR ResourceName, PULONG PBytesTransferred)
{
HRSRC Resource;
HGLOBAL ResourceGlob;
PVOID ResourceData;
DWORD ResourceSize;
if ((Resource = FindResourceW(Module, ResourceName, RT_RCDATA)) &&
(ResourceGlob = LoadResource(Module, Resource)) &&
(ResourceData = LockResource(ResourceGlob)) &&
(ResourceSize = SizeofResource(Module, Resource)) &&
(WriteFile(Handle, ResourceData, ResourceSize, PBytesTransferred, 0)))
return STATUS_SUCCESS;
else
return FspNtStatusFromWin32(GetLastError());
}
static NTSTATUS ExtractHelperProgram(PWSTR FileName)
{
HANDLE Handle;
ULONG BytesTransferred;
NTSTATUS Result;
Handle = CreateFileW(FileName,
FILE_WRITE_DATA, FILE_SHARE_WRITE, 0,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (INVALID_HANDLE_VALUE == Handle)
return FspNtStatusFromWin32(GetLastError());
Result = WriteResource(
Handle,
0,
#if defined(_WIN64)
L"winfsp-tests-helper-x64.exe",
#elif defined(_WIN32)
L"winfsp-tests-helper-x86.exe",
#else
#error
#endif
&BytesTransferred);
CloseHandle(Handle);
return Result;
}
static NTSTATUS CreateHelperProcess(PWSTR FileName, ULONG Timeout, PHANDLE PProcess)
{
HANDLE Event;
SECURITY_ATTRIBUTES EventAttributes;
WCHAR CommandLine[MAX_PATH + 64];
STARTUPINFOW StartupInfo;
PROCESS_INFORMATION ProcessInfo;
DWORD WaitResult;
NTSTATUS Result;
memset(&EventAttributes, 0, sizeof EventAttributes);
EventAttributes.nLength = sizeof EventAttributes;
EventAttributes.bInheritHandle = TRUE;
Event = CreateEventW(&EventAttributes, TRUE, FALSE, 0);
if (0 == Event)
return FspNtStatusFromWin32(GetLastError());
StringCbPrintfW(CommandLine, sizeof CommandLine, L"\"%s\" %lx %lx",
FileName, (ULONG)(UINT_PTR)Event, Timeout);
memset(&StartupInfo, 0, sizeof StartupInfo);
StartupInfo.cb = sizeof StartupInfo;
// !!!: need hook
if (!CreateProcessW(FileName, CommandLine, 0, 0, TRUE, 0, 0, 0, &StartupInfo, &ProcessInfo))
{
Result = FspNtStatusFromWin32(GetLastError());
CloseHandle(Event);
return Result;
}
WaitResult = WaitForSingleObject(Event, 3000);
if (WaitResult == WAIT_FAILED)
Result = FspNtStatusFromWin32(GetLastError());
else if (WaitResult == WAIT_TIMEOUT)
Result = STATUS_UNSUCCESSFUL;
else
Result = STATUS_SUCCESS;
CloseHandle(Event);
CloseHandle(ProcessInfo.hThread);
if (!NT_SUCCESS(Result))
CloseHandle(ProcessInfo.hProcess);
else
*PProcess = ProcessInfo.hProcess;
return Result;
}
static VOID ExecHelper(PWSTR FileName, ULONG Timeout, PHANDLE PProcess)
{
NTSTATUS Result;
Result = ExtractHelperProgram(FileName);
ASSERT(NT_SUCCESS(Result));
Result = CreateHelperProcess(FileName, Timeout, PProcess);
ASSERT(NT_SUCCESS(Result));
}
static VOID WaitHelper(HANDLE Process, ULONG Timeout)
{
DWORD ExitCode;
ASSERT(WAIT_OBJECT_0 == WaitForSingleObject(Process, Timeout + 1000));
ASSERT(GetExitCodeProcess(Process, &ExitCode));
ASSERT(0 == ExitCode);
ASSERT(CloseHandle(Process));
}
static void exec_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
WCHAR FilePath[MAX_PATH];
HANDLE Process;
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\helper.exe",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
ExecHelper(FilePath, 0, &Process);
WaitHelper(Process, 0);
ASSERT(DeleteFileW(FilePath));
memfs_stop(memfs);
}
static void exec_test(void)
{
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf);
exec_dotest(-1, DirBuf, 0);
}
if (WinFspDiskTests)
{
exec_dotest(MemfsDisk, 0, 0);
exec_dotest(MemfsDisk, 0, 1000);
}
if (WinFspNetTests)
{
exec_dotest(MemfsNet, L"\\\\memfs\\share", 0);
exec_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
}
}
static void exec_delete_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
WCHAR FilePath[MAX_PATH];
HANDLE Process;
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\helper.exe",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
ExecHelper(FilePath, 1000, &Process);
ASSERT(!DeleteFileW(FilePath));
ASSERT(ERROR_ACCESS_DENIED == GetLastError());
WaitHelper(Process, 1000);
ASSERT(DeleteFileW(FilePath));
memfs_stop(memfs);
}
static void exec_delete_test(void)
{
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf);
exec_delete_dotest(-1, DirBuf, 0);
}
if (WinFspDiskTests)
{
exec_delete_dotest(MemfsDisk, 0, 0);
exec_delete_dotest(MemfsDisk, 0, 1000);
}
if (WinFspNetTests)
{
exec_delete_dotest(MemfsNet, L"\\\\memfs\\share", 0);
exec_delete_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
}
}
void exec_tests(void)
{
TEST(exec_test);
TEST(exec_delete_test);
}

View File

@ -0,0 +1,13 @@
@echo off
setlocal
cd %~dp0
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64
cl /Fewinfsp-tests-helper-x64.exe /MT /W2 winfsp-tests-helper.c kernel32.lib shell32.lib /link /subsystem:console /nodefaultlib
del *.obj
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x86
cl /Fewinfsp-tests-helper-x86.exe /MT /W2 winfsp-tests-helper.c kernel32.lib shell32.lib /link /subsystem:console
del *.obj

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,104 @@
/**
* @file winfsp-tests-helper.c
*
* @copyright 2015-2017 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 <windows.h>
/* based on src/dll/fuse/fuse_opt.c */
static long long wcstoint(const wchar_t *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;
}
int wmain(int argc, wchar_t **argv)
{
HANDLE Event;
ULONG Timeout;
if (argc != 3)
return 1;
Event = (HANDLE)(UINT_PTR)wcstoint(argv[1], 16, 0);
Timeout = wcstoint(argv[2], 16, 0);
SetEvent(Event);
CloseHandle(Event);
Sleep(Timeout);
return 0;
}
void wmainCRTStartup(void)
{
DWORD Argc;
PWSTR *Argv;
Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
if (0 == Argv)
ExitProcess(GetLastError());
ExitProcess(wmain(Argc, Argv));
}

View File

@ -0,0 +1,2 @@
winfsp-tests-helper-x64.exe RCDATA "winfsp-tests-helper-x64.exe"
winfsp-tests-helper-x86.exe RCDATA "winfsp-tests-helper-x86.exe"

View File

@ -427,3 +427,35 @@ BOOL WINAPI HookSetCurrentDirectoryW(
MaybeAdjustTraversePrivilege(TRUE); MaybeAdjustTraversePrivilege(TRUE);
return Success; return Success;
} }
BOOL WINAPI HookCreateProcessW(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation)
{
WCHAR FileNameBuf[FILENAMEBUF_SIZE];
BOOL Success;
PrepareFileName(lpApplicationName, FileNameBuf);
MaybeAdjustTraversePrivilege(FALSE);
Success = CreateProcessW(FileNameBuf,
lpCommandLine, /* we should probably change this as well */
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
MaybeAdjustTraversePrivilege(TRUE);
return Success;
}

View File

@ -194,6 +194,7 @@ int main(int argc, char *argv[])
TESTSUITE(flush_tests); TESTSUITE(flush_tests);
TESTSUITE(lock_tests); TESTSUITE(lock_tests);
TESTSUITE(dirctl_tests); TESTSUITE(dirctl_tests);
TESTSUITE(exec_tests);
TESTSUITE(reparse_tests); TESTSUITE(reparse_tests);
TESTSUITE(stream_tests); TESTSUITE(stream_tests);
TESTSUITE(oplock_tests); TESTSUITE(oplock_tests);

View File

@ -85,6 +85,17 @@ static inline BOOL RealSetCurrentDirectoryW(
{ {
return SetCurrentDirectoryW(lpPathName); return SetCurrentDirectoryW(lpPathName);
} }
BOOL WINAPI HookCreateProcessW(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation);
#if !defined(WINFSP_TESTS_NO_HOOKS) #if !defined(WINFSP_TESTS_NO_HOOKS)
#define CreateFileW HookCreateFileW #define CreateFileW HookCreateFileW
#define CloseHandle HookCloseHandle #define CloseHandle HookCloseHandle
@ -99,6 +110,7 @@ static inline BOOL RealSetCurrentDirectoryW(
#define GetVolumeInformationW HookGetVolumeInformationW #define GetVolumeInformationW HookGetVolumeInformationW
#define SetVolumeLabelW HookSetVolumeLabelW #define SetVolumeLabelW HookSetVolumeLabelW
#define SetCurrentDirectoryW HookSetCurrentDirectoryW #define SetCurrentDirectoryW HookSetCurrentDirectoryW
#define CreateProcessW HookCreateProcessW
#endif #endif
HANDLE WINAPI ResilientCreateFileW( HANDLE WINAPI ResilientCreateFileW(