From badaf824624e6ce2a7b10879dcaa190a97a3342e Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Tue, 25 Oct 2016 20:19:04 -0700 Subject: [PATCH] tst: winfsp-tests: --resilient command line option --- build/VStudio/testing/winfsp-tests.vcxproj | 1 + .../testing/winfsp-tests.vcxproj.filters | 3 + tst/winfsp-tests/resilient.c | 134 ++++++++++++++++++ tst/winfsp-tests/winfsp-tests.c | 75 +++++----- tst/winfsp-tests/winfsp-tests.h | 19 ++- 5 files changed, 188 insertions(+), 44 deletions(-) create mode 100644 tst/winfsp-tests/resilient.c diff --git a/build/VStudio/testing/winfsp-tests.vcxproj b/build/VStudio/testing/winfsp-tests.vcxproj index a54d0da1..5e494520 100644 --- a/build/VStudio/testing/winfsp-tests.vcxproj +++ b/build/VStudio/testing/winfsp-tests.vcxproj @@ -194,6 +194,7 @@ + diff --git a/build/VStudio/testing/winfsp-tests.vcxproj.filters b/build/VStudio/testing/winfsp-tests.vcxproj.filters index 6d26ad3f..dd1e6352 100644 --- a/build/VStudio/testing/winfsp-tests.vcxproj.filters +++ b/build/VStudio/testing/winfsp-tests.vcxproj.filters @@ -67,6 +67,9 @@ Source + + Source + diff --git a/tst/winfsp-tests/resilient.c b/tst/winfsp-tests/resilient.c new file mode 100644 index 00000000..01667fdd --- /dev/null +++ b/tst/winfsp-tests/resilient.c @@ -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 + +#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; + } +} diff --git a/tst/winfsp-tests/winfsp-tests.c b/tst/winfsp-tests/winfsp-tests.c index 1233c202..da7c31fe 100644 --- a/tst/winfsp-tests/winfsp-tests.c +++ b/tst/winfsp-tests/winfsp-tests.c @@ -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) diff --git a/tst/winfsp-tests/winfsp-tests.h b/tst/winfsp-tests/winfsp-tests.h index b6b29694..032b44e4 100644 --- a/tst/winfsp-tests/winfsp-tests.h +++ b/tst/winfsp-tests/winfsp-tests.h @@ -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;