summaryrefslogtreecommitdiff
path: root/zen/FindFilePlus
diff options
context:
space:
mode:
Diffstat (limited to 'zen/FindFilePlus')
-rw-r--r--zen/FindFilePlus/find_file_plus.cpp117
1 files changed, 83 insertions, 34 deletions
diff --git a/zen/FindFilePlus/find_file_plus.cpp b/zen/FindFilePlus/find_file_plus.cpp
index ec56b0bc..fdabc46f 100644
--- a/zen/FindFilePlus/find_file_plus.cpp
+++ b/zen/FindFilePlus/find_file_plus.cpp
@@ -8,9 +8,7 @@
#include "init_dll_binding.h"
//#include <windows.h> //these two don't play nice with each other
#include "load_dll.h"
-#include <zen/scope_guard.h>
#include <new>
-//#include <cstdio>
using namespace dll;
using namespace findplus;
@@ -56,15 +54,18 @@ typedef struct _RTL_RELATIVE_NAME_U
PVOID /*PRTLP_CURDIR_REF*/ CurDirRef;
} RTL_RELATIVE_NAME_U, *PRTL_RELATIVE_NAME_U;
-typedef BOOLEAN (NTAPI* RtlDosPathNameToNtPathName_UFunc)(PCWSTR, //__in dosFileName,
- PUNICODE_STRING, //__out ntFileName,
- PCWSTR*, //__out_optFilePart,
- PRTL_RELATIVE_NAME_U); //__out_opt relativeName
+typedef BOOLEAN (NTAPI* RtlDosPathNameToNtPathName_UFunc)(PCWSTR dosFileName, //__in
+ PUNICODE_STRING ntFileName, //__out
+ PCWSTR* filePart, //__out
+ PRTL_RELATIVE_NAME_U relativeName); //__out
-typedef BOOLEAN (NTAPI* RtlDosPathNameToRelativeNtPathName_UFunc)(PCWSTR, //__in dosFileName,
- PUNICODE_STRING, //__out ntFileName,
- PCWSTR*, //__out_optFilePart,
- PRTL_RELATIVE_NAME_U); //__out_opt relativeName
+typedef BOOLEAN (NTAPI* RtlDosPathNameToRelativeNtPathName_UFunc)(PCWSTR dosFileName, //__in
+ PUNICODE_STRING ntFileName, //__out
+ PCWSTR* filePart, //__out
+ PRTL_RELATIVE_NAME_U relativeName); //__out
+
+typedef BOOLEAN (NTAPI* RtlCreateUnicodeStringFunc)(PUNICODE_STRING DestinationString, //_Out_
+ PCWSTR SourceString); //_In_
typedef VOID (NTAPI* RtlFreeUnicodeStringFunc)(PUNICODE_STRING); //__inout unicodeString
@@ -76,6 +77,7 @@ const SysDllFun<NtOpenFileFunc> ntOpenFile (L"ntdll.d
const SysDllFun<NtCloseFunc> ntClose (L"ntdll.dll", "NtClose");
const SysDllFun<NtQueryDirectoryFileFunc> ntQueryDirectoryFile (L"ntdll.dll", "NtQueryDirectoryFile");
const SysDllFun<RtlNtStatusToDosErrorFunc> rtlNtStatusToDosError (L"ntdll.dll", "RtlNtStatusToDosError");
+const SysDllFun<RtlCreateUnicodeStringFunc> rtlCreateUnicodeString (L"ntdll.dll", "RtlCreateUnicodeString");
const SysDllFun<RtlFreeUnicodeStringFunc> rtlFreeUnicodeString (L"ntdll.dll", "RtlFreeUnicodeString");
const SysDllFun<RtlDosPathNameToNtPathName_UFunc> rtlDosPathNameToNtPathName_U(SysDllFun<RtlDosPathNameToRelativeNtPathName_UFunc>(L"ntdll.dll", "RtlDosPathNameToRelativeNtPathName_U") ?
SysDllFun<RtlDosPathNameToRelativeNtPathName_UFunc>(L"ntdll.dll", "RtlDosPathNameToRelativeNtPathName_U") : //use the newer version if available
@@ -93,11 +95,12 @@ bool findplus::initDllBinding() //evaluate in ::DllMain() when attaching process
//http://msdn.microsoft.com/en-us/library/ff563638(v=VS.85).aspx
//verify dynamic dll binding
- return ntOpenFile &&
- ntClose &&
- ntQueryDirectoryFile &&
- rtlNtStatusToDosError &&
- rtlFreeUnicodeString &&
+ return ntOpenFile &&
+ ntClose &&
+ ntQueryDirectoryFile &&
+ rtlNtStatusToDosError &&
+ rtlCreateUnicodeString &&
+ rtlFreeUnicodeString &&
rtlDosPathNameToNtPathName_U;
//this may become handy some time: nt status code STATUS_ORDINAL_NOT_FOUND maps to win32 code ERROR_INVALID_ORDINAL
@@ -128,43 +131,89 @@ private:
};
+//a simple scope guard without <utility>, <type_traits>, <cassert> dependencies:
+template <typename F>
+class ScopeGuardLean
+{
+public:
+ explicit ScopeGuardLean(F fun) : dismissed_(false), fun_(fun) {}
+ ScopeGuardLean(ScopeGuardLean&& other) : dismissed_(other.dismissed_), fun_(std::move(other.fun_)) { other.dismiss(); }
+
+ void dismiss() { dismissed_ = true; }
+
+ ~ScopeGuardLean()
+ {
+ if (!dismissed_)
+ try { fun_(); }
+ catch (...) {}
+ }
+
+private:
+ ScopeGuardLean (const ScopeGuardLean&); // = delete
+ ScopeGuardLean& operator=(const ScopeGuardLean&); //
+
+ bool dismissed_;
+ F fun_;
+};
+
+template <class F> inline
+ScopeGuardLean<F> makeGuard(F fun) { return ScopeGuardLean<F>(fun); }
+
+
FileSearcher::FileSearcher(const wchar_t* dirname) :
+ dirnameNt(), //[!]
hDir(nullptr),
nextEntryOffset(0)
{
- dirnameNt.Buffer = nullptr;
- dirnameNt.Length = 0;
- dirnameNt.MaximumLength = 0;
-
- zen::ScopeGuard guardConstructor = zen::makeGuard([&] { this->~FileSearcher(); });
+ auto guardConstructor = makeGuard([&] { this->~FileSearcher(); });
//--------------------------------------------------------------------------------------------------------------
//convert dosFileName, e.g. C:\Users or \\?\C:\Users to ntFileName \??\C:\Users
//in contrast to ::FindFirstFile() implementation we don't evaluate the relativeName,
//however tests indicate ntFileName is *always* filled with an absolute name, even if dosFileName is relative
+ PCWSTR filePart = nullptr;
+ RTL_RELATIVE_NAME_U relativeName = {};
+
//NOTE: RtlDosPathNameToNtPathName_U may be used on all XP/Win7/Win8 for compatibility
// RtlDosPathNameToNtPathName_U: used by Windows XP available with OS version 3.51 (Windows NT) and higher
// RtlDosPathNameToRelativeNtPathName_U: used by Win7/Win8 available with OS version 5.2 (Windows Server 2003) and higher
- if (!rtlDosPathNameToNtPathName_U(dirname, //__in dosFileName,
- &dirnameNt, //__out ntFileName,
- nullptr, //__out_optFilePart,
- nullptr)) //__out_opt relativeName - empty if dosFileName is absolute
+ if (!rtlDosPathNameToNtPathName_U(dirname, //__in dosFileName,
+ &dirnameNt, //__out ntFileName,
+ &filePart, //__out FilePart - points into ntFileName
+ &relativeName)) //__out relativeName - points into ntFileName; empty if dosFileName is absolute
throw NtFileError(STATUS_OBJECT_PATH_NOT_FOUND); //translates to ERROR_PATH_NOT_FOUND, same behavior like ::FindFirstFileEx()
+ //note 1: internally it distinguishes between "quick path" == \\?\ and "slow path" handling!
+ //http://doxygen.reactos.org/d9/d6e/lib_2rtl_2path_8c_a11c87ad0f7752999b0b8972af6165d7a.html#a11c87ad0f7752999b0b8972af6165d7a
+ //note 2: without \\?\, i.e. slow path handling it calls RtlGetFullPathName_Ustr() which removes trailing spaces!!!
+ //http://doxygen.reactos.org/d9/d6e/lib_2rtl_2path_8c_a8624b864678ca64b031f5fc273e022af.html#a8624b864678ca64b031f5fc273e022af
+ //FindFirstFile() gets lucky because it passes "<dirname>\*" which never has trailing space chars! >:(
OBJECT_ATTRIBUTES objAttr = {};
- InitializeObjectAttributes(&objAttr, //[out] POBJECT_ATTRIBUTES initializedAttributes,
- &dirnameNt, //[in] PUNICODE_STRING objectName,
- OBJ_CASE_INSENSITIVE, //[in] ULONG attributes,
- nullptr, //[in] HANDLE rootDirectory,
- nullptr); //[in, optional] PSECURITY_DESCRIPTOR securityDescriptor
+ if (relativeName.RelativeName.Length == 0) //absolute name
+ {
+ InitializeObjectAttributes(&objAttr, //[out] POBJECT_ATTRIBUTES initializedAttributes,
+ &dirnameNt, //[in] PUNICODE_STRING objectName,
+ OBJ_CASE_INSENSITIVE, //[in] ULONG attributes,
+ nullptr, //[in] HANDLE rootDirectory,
+ nullptr); //[in, optional] PSECURITY_DESCRIPTOR securityDescriptor
+ }
+ else //relative name (it seems we alternatively could also use dirnameNt here?)
+ {
+ InitializeObjectAttributes(&objAttr, //[out] POBJECT_ATTRIBUTES initializedAttributes,
+ &relativeName.RelativeName, //[in] PUNICODE_STRING objectName,
+ OBJ_CASE_INSENSITIVE, //[in] ULONG attributes,
+ relativeName.ContainingDirectory, //[in] HANDLE rootDirectory,
+ nullptr); //[in, optional] PSECURITY_DESCRIPTOR securityDescriptor
+ }
+
{
IO_STATUS_BLOCK status = {};
- NTSTATUS rv = ntOpenFile(&hDir, //__out PHANDLE FileHandle,
+ NTSTATUS rv = ntOpenFile(&hDir, //__out PHANDLE FileHandle,
FILE_LIST_DIRECTORY | SYNCHRONIZE, //__in ACCESS_MASK desiredAccess, - 100001 used by ::FindFirstFile() on all XP/Win7/Win8
- &objAttr, //__in POBJECT_ATTRIBUTES objectAttributes,
- &status, //__out PIO_STATUS_BLOCK ioStatusBlock,
+ &objAttr, //__in POBJECT_ATTRIBUTES objectAttributes,
+ &status, //__out PIO_STATUS_BLOCK ioStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //__in ULONG shareAccess, - 7 on Win7/Win8, 3 on XP
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); //__in ULONG openOptions - 4021 used on all XP/Win7/Win8
if (!NT_SUCCESS(rv))
@@ -184,7 +233,7 @@ FileSearcher::~FileSearcher()
if (dirnameNt.Buffer)
rtlFreeUnicodeString(&dirnameNt); //cleanup identical to ::FindFirstFile()
- //note that most of this function seems inlined by the linker, so that its assembly looks equivalent to "RtlFreeHeap(GetProcessHeap(), 0, ntPathName.Buffer)"
+ //note that most of this function seems inlined by the linker, so that its assembly looks equivalent to "RtlFreeHeap(RtlGetProcessHeap(), 0, ntPathName.Buffer)"
}
@@ -364,7 +413,7 @@ FindHandle findplus::openDir(const wchar_t* dirname)
setWin32Error(rtlNtStatusToDosError(e.ntError));
return nullptr;
}
- catch (const std::bad_alloc&) //not unlikely in this context! => handle!
+ catch (const std::bad_alloc&) //not unlikely in file sync context! => handle!
{
setWin32Error(rtlNtStatusToDosError(STATUS_NO_MEMORY));
return nullptr;
bgstack15