tst: winfsp-tests: --resilient command line option

This commit is contained in:
Bill Zissimopoulos 2016-10-25 20:19:04 -07:00
parent 3f79b2e46d
commit badaf82462
5 changed files with 188 additions and 44 deletions

View File

@ -194,6 +194,7 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\posix-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\rdwr-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\reparse-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\resilient.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\security-test.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c" />
<ClCompile Include="..\..\..\tst\winfsp-tests\timeout-test.c" />

View File

@ -67,6 +67,9 @@
<ClCompile Include="..\..\..\tst\winfsp-tests\stream-tests.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tst\winfsp-tests\resilient.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">

View File

@ -0,0 +1,134 @@
/**
* @file tst/resilient.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 <windows.h>
#define DeleteMaxTries 30
#define DeleteSleepTimeout 300
static VOID WaitDeletePending(PCWSTR FileName);
HANDLE ResilientCreateFileW(
LPCWSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile)
{
HANDLE Handle;
DWORD LastError;
Handle = CreateFileW(
lpFileName,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile);
LastError = GetLastError();
if (INVALID_HANDLE_VALUE != Handle &&
(FILE_FLAG_DELETE_ON_CLOSE & dwFlagsAndAttributes))
{
/* HACK: remember FILE_FLAG_DELETE_ON_CLOSE through HANDLE_FLAG_PROTECT_FROM_CLOSE */
SetHandleInformation(Handle,
HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
}
SetLastError(LastError);
return Handle;
}
BOOL ResilientCloseHandle(
HANDLE hObject)
{
BOOL Success;
DWORD LastError;
DWORD HandleFlags = 0, FileNameLen;
WCHAR FileNameBuf[sizeof "\\\\?\\GLOBALROOT" - 1 + 1024] = L"\\\\?\\GLOBALROOT";
if (GetHandleInformation(hObject, &HandleFlags) &&
(HANDLE_FLAG_PROTECT_FROM_CLOSE & HandleFlags))
{
SetHandleInformation(hObject,
HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
FileNameLen = GetFinalPathNameByHandle(hObject,
FileNameBuf + sizeof "\\\\?\\GLOBALROOT" - 1, 1023,
FILE_NAME_OPENED | VOLUME_NAME_NT);
if (0 == FileNameLen || FileNameLen >= 1024)
HandleFlags = 0;
}
Success = CloseHandle(
hObject);
LastError = GetLastError();
if (Success)
{
if (HANDLE_FLAG_PROTECT_FROM_CLOSE & HandleFlags)
WaitDeletePending(FileNameBuf);
}
SetLastError(LastError);
return Success;
}
BOOL ResilientDeleteFileW(
LPCWSTR lpFileName)
{
BOOL Success;
DWORD LastError;
Success = DeleteFileW(lpFileName);
LastError = GetLastError();
if (Success)
WaitDeletePending(lpFileName);
else
{
for (ULONG MaxTries = DeleteMaxTries;
!Success && ERROR_SHARING_VIOLATION == GetLastError() && 0 != MaxTries;
MaxTries--)
{
Sleep(DeleteSleepTimeout);
Success = DeleteFileW(lpFileName);
}
}
SetLastError(LastError);
return Success;
}
static VOID WaitDeletePending(PCWSTR FileName)
{
for (ULONG MaxTries = DeleteMaxTries; 0 != MaxTries; MaxTries--)
{
HANDLE Handle = CreateFileW(FileName,
FILE_READ_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (INVALID_HANDLE_VALUE != Handle)
/* should never happen! */
CloseHandle(Handle);
else if (ERROR_ACCESS_DENIED == GetLastError())
/* STATUS_DELETE_PENDING */
Sleep(DeleteSleepTimeout);
else
break;
}
}

View File

@ -167,14 +167,25 @@ HANDLE HookCreateFileW(
ABORT("cannot disable traverse privilege");
}
HANDLE h = CreateFileW(
FileNameBuf,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile);
HANDLE h;
if (!OptResilient)
h = CreateFileW(
FileNameBuf,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile);
else
h = ResilientCreateFileW(
FileNameBuf,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile);
DWORD LastError = GetLastError();
if (OptNoTraverseToken)
@ -202,44 +213,24 @@ HANDLE HookCreateFileW(
return h;
}
#undef CloseHandle
BOOL HookCloseHandle(
HANDLE hObject)
{
if (!OptResilient)
return CloseHandle(hObject);
else
return ResilientCloseHandle(hObject);
}
#undef DeleteFileW
BOOL HookDeleteFileW(
LPCWSTR lpFileName)
{
ULONG MaxTries = 30;
ULONG SleepTimeout = 300;
BOOL Success;
DWORD LastError;
Success = DeleteFileW(lpFileName);
LastError = GetLastError();
if (OptResilient)
{
if (!Success)
{
while (!Success && ERROR_SHARING_VIOLATION == GetLastError() && 0 != MaxTries--)
{
Sleep(SleepTimeout);
Success = DeleteFileW(lpFileName);
}
}
else
{
while (0 != MaxTries--)
{
HANDLE Handle = CreateFileW(lpFileName, FILE_READ_ATTRIBUTES, 0, 0, OPEN_EXISTING, 0, 0);
if (INVALID_HANDLE_VALUE != Handle)
CloseHandle(Handle); /* should never happen! */
else if (ERROR_ACCESS_DENIED == GetLastError())
Sleep(SleepTimeout);
else
break;
}
}
}
SetLastError(LastError);
return Success;
if (!OptResilient)
return DeleteFileW(lpFileName);
else
return ResilientDeleteFileW(lpFileName);
}
static VOID DisableBackupRestorePrivileges(VOID)

View File

@ -8,6 +8,8 @@ PWSTR memfs_volumename(void *data);
int mywcscmp(PWSTR a, int alen, PWSTR b, int blen);
#define CreateFileW HookCreateFileW
#define CloseHandle HookCloseHandle
#define DeleteFileW HookDeleteFileW
HANDLE HookCreateFileW(
LPCWSTR lpFileName,
DWORD dwDesiredAccess,
@ -16,11 +18,24 @@ HANDLE HookCreateFileW(
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);
#define DeleteFileW HookDeleteFileW
BOOL HookCloseHandle(
HANDLE hObject);
BOOL HookDeleteFileW(
LPCWSTR lpFileName);
HANDLE ResilientCreateFileW(
LPCWSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);
BOOL ResilientCloseHandle(
HANDLE hObject);
BOOL ResilientDeleteFileW(
LPCWSTR lpFileName);
typedef struct
{
BOOLEAN Disposition;