From 3a65665d36022c50637fc53d5c9c1ee022c5b3b5 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 10 Feb 2020 10:51:23 -0500 Subject: wstring_view when possible first implementation of NtQueryDirectoryFile --- src/CMakeLists.txt | 3 + src/directoryrefresher.cpp | 5 +- src/envfs.cpp | 303 ++++++++++++++++++++++++++++++++++++++++++ src/envfs.h | 17 +++ src/main.cpp | 2 + src/shared/directoryentry.cpp | 76 ++++++++--- src/shared/directoryentry.h | 20 +-- src/shared/util.cpp | 7 + src/shared/util.h | 1 + src/usvfsconnector.cpp | 2 + 10 files changed, 403 insertions(+), 33 deletions(-) create mode 100644 src/envfs.cpp create mode 100644 src/envfs.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ad8f74c0..08421acb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -132,6 +132,7 @@ SET(organizer_SRCS filerenamer.cpp texteditor.cpp env.cpp + envfs.cpp envmetrics.cpp envmodule.cpp envsecurity.cpp @@ -262,6 +263,7 @@ SET(organizer_HDRS filerenamer.h texteditor.h env.h + envfs.h envmetrics.h envmodule.h envsecurity.h @@ -392,6 +394,7 @@ set(downloads set(env env + envfs envmetrics envmodule envsecurity diff --git a/src/directoryrefresher.cpp b/src/directoryrefresher.cpp index 87305599..b7dd51ba 100644 --- a/src/directoryrefresher.cpp +++ b/src/directoryrefresher.cpp @@ -159,7 +159,7 @@ void DirectoryRefresher::addModToStructure(DirectoryEntry *directoryStructure , const QStringList &archives) { addModFilesToStructure(directoryStructure, modName, priority, directory, stealFiles); - + if (Settings::instance().archiveParsing()) { addModBSAToStructure(directoryStructure, modName, priority, directory, archives); } @@ -167,6 +167,9 @@ void DirectoryRefresher::addModToStructure(DirectoryEntry *directoryStructure void DirectoryRefresher::refresh() { + SetThisThreadName("DirectoryRefresher"); + TimeThis tt("DirectoryRefresher::refresh()"); + QMutexLocker locker(&m_RefreshLock); delete m_DirectoryStructure; diff --git a/src/envfs.cpp b/src/envfs.cpp new file mode 100644 index 00000000..cb2764ae --- /dev/null +++ b/src/envfs.cpp @@ -0,0 +1,303 @@ +#include "envfs.h" +#include +#include + +using namespace MOBase; + +struct NtCloser +{ + using pointer = HANDLE; + void operator()(HANDLE h) + { + } +}; + +using NtHandle = std::unique_ptr; + +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; +typedef const UNICODE_STRING *PCUNICODE_STRING; + +typedef struct _OBJECT_ATTRIBUTES { + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; + + +typedef struct _FILE_DIRECTORY_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; + + +#define FILE_SHARE_VALID_FLAGS 0x00000007 + +// copied from ntstatus.h +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) +#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) +#define STATUS_NO_SUCH_FILE ((NTSTATUS)0xC000000FL) + +typedef struct _IO_STATUS_BLOCK IO_STATUS_BLOCK; + +typedef struct _IO_STATUS_BLOCK *PIO_STATUS_BLOCK; +// typedef VOID (NTAPI *PIO_APC_ROUTINE )(__in PVOID ApcContext, __in +// PIO_STATUS_BLOCK IoStatusBlock, __in ULONG Reserved); +typedef VOID(NTAPI *PIO_APC_ROUTINE)(PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG Reserved); + + +typedef enum _FILE_INFORMATION_CLASS { + FileDirectoryInformation = 1 +} FILE_INFORMATION_CLASS; + +typedef NTSTATUS(WINAPI *NtQueryDirectoryFile_type)( + HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, + FILE_INFORMATION_CLASS, BOOLEAN, PUNICODE_STRING, BOOLEAN); + +typedef NTSTATUS(WINAPI *NtOpenFile_type)(PHANDLE, ACCESS_MASK, + POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, + ULONG, ULONG); + +NtOpenFile_type NtOpenFile = nullptr; +NtQueryDirectoryFile_type NtQueryDirectoryFile = nullptr; + + +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 + +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 + +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_REMOTE_INSTANCE 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 + +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 + +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN7) +#define FILE_OPEN_REQUIRING_OPLOCK 0x00010000 +#endif + +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_OPEN_REPARSE_POINT 0x00200000 +#define FILE_OPEN_NO_RECALL 0x00400000 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 + +#define FILE_VALID_OPTION_FLAGS 0x00ffffff +#define FILE_VALID_PIPE_OPTION_FLAGS 0x00000032 +#define FILE_VALID_MAILSLOT_OPTION_FLAGS 0x00000032 +#define FILE_VALID_SET_FLAGS 0x00000036 + +typedef struct _IO_STATUS_BLOCK { +#pragma warning(push) +#pragma warning(disable: 4201) // we'll always use the Microsoft compiler + union { + NTSTATUS Status; + PVOID Pointer; + } DUMMYUNIONNAME; +#pragma warning(pop) + + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + + + +namespace env +{ + +std::wstring_view toStringView(const UNICODE_STRING* s) +{ + if (s && s->Buffer) { + return {s->Buffer, (s->Length / sizeof(wchar_t))}; + } else { + return {}; + } +} + +std::wstring_view toStringView(POBJECT_ATTRIBUTES poa) +{ + if (poa->ObjectName) { + return toStringView(poa->ObjectName); + } + + return {}; +} + +QString toString(POBJECT_ATTRIBUTES poa) +{ + const auto sv = toStringView(poa); + return QString::fromWCharArray(sv.data(), static_cast(sv.size())); +} + + +constexpr std::size_t AllocSize = 1024 * 1024; +std::vector> g_buffers; + + + +void forEachEntryImpl( + void* cx, POBJECT_ATTRIBUTES poa, std::size_t depth, + DirStartF* dirStartF, DirEndF* dirEndF, FileF* fileF) +{ + IO_STATUS_BLOCK iosb; + UNICODE_STRING ObjectName; + OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName }; + NTSTATUS status; + + //log::debug("{}{}", std::wstring(depth * 2, L' '), toString(poa)); + + status = NtOpenFile( + &oa.RootDirectory, FILE_GENERIC_READ, poa, &iosb, FILE_SHARE_VALID_FLAGS, + FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT); + + if (status < 0) { + log::error( + "NtOpenFile() failed for '{}', {}", + toString(poa), formatSystemMessage(status)); + + return; + } + + NtHandle rootDirectoryHandle(oa.RootDirectory); + + //std::unique_ptr buffer(new unsigned char[AllocSize]); + + unsigned char* buffer; + + if (depth >= g_buffers.size()) { + g_buffers.emplace_back(std::make_unique(AllocSize)); + buffer = g_buffers.back().get(); + } else { + buffer = g_buffers[depth].get(); + } + + union + { + PVOID pv; + PBYTE pb; + PFILE_DIRECTORY_INFORMATION DirInfo; + }; + + for (;;) { + status = NtQueryDirectoryFile( + oa.RootDirectory, NULL, NULL, NULL, &iosb, + buffer, AllocSize, FileDirectoryInformation, FALSE, NULL, FALSE); + + if (status == STATUS_NO_MORE_FILES) { + break; + } else if (status < 0) { + log::error( + "NtQueryDirectoryFile() failed for '{}', {}", + toString(poa), formatSystemMessage(status)); + break; + } + + ULONG NextEntryOffset = 0; + + pv = buffer; + + auto isDotDir = [](auto* o) { + if (o->Length == 2 && o->Buffer[0] == '.') { + return true; + } + + if (o->Length == 4 && o->Buffer[0] == '.' && o->Buffer[1] == '.') { + return true; + } + + return false; + }; + + std::size_t count = 0; + + for (;;) { + ++count; + pb += NextEntryOffset; + + ObjectName.Buffer = DirInfo->FileName; + ObjectName.Length = (USHORT)DirInfo->FileNameLength; + + if (!isDotDir(&ObjectName)) { + ObjectName.MaximumLength = ObjectName.Length; + + if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + dirStartF(cx, toStringView(&oa)); + forEachEntryImpl(cx, &oa, depth+1, dirStartF, dirEndF, fileF); + dirEndF(cx, toStringView(&oa)); + } else { + //log::debug("{}{}", std::wstring((depth + 1) * 2, L' '), toString(&oa)); + FILETIME ft; + ft.dwLowDateTime = DirInfo->LastWriteTime.LowPart; + ft.dwHighDateTime = DirInfo->LastWriteTime.HighPart; + fileF(cx, toStringView(&oa), ft); + } + } + + NextEntryOffset = DirInfo->NextEntryOffset; + + if (NextEntryOffset == 0) { + break; + } + } + + //log::debug("{}{} processed {} files", std::wstring(depth * 2, L' '), toString(poa), count); + + if (AllocSize - iosb.Information > (ULONG)FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName[256])) { + // NO_MORE_FILES + break; + } + } +} + +void forEachEntry( + const std::wstring& path, void* cx, + DirStartF* dirStartF, DirEndF* dirEndF, FileF* fileF) +{ + if (!NtOpenFile) { + HMODULE m = ::LoadLibraryW(L"ntdll.dll"); + NtOpenFile = (NtOpenFile_type)::GetProcAddress(m, "NtOpenFile"); + NtQueryDirectoryFile = (NtQueryDirectoryFile_type)::GetProcAddress(m, "NtQueryDirectoryFile"); + ::FreeLibrary(m); + } + + const std::wstring ntpath = std::wstring(L"\\??\\") + path; + + UNICODE_STRING ObjectName = {}; + ObjectName.Buffer = const_cast(ntpath.c_str()); + ObjectName.Length = (USHORT)ntpath.size() * sizeof(wchar_t); + ObjectName.MaximumLength = ObjectName.Length; + + OBJECT_ATTRIBUTES oa = {}; + oa.Length = sizeof(oa); + oa.ObjectName = &ObjectName; + + forEachEntryImpl(cx, &oa, 0, dirStartF, dirEndF, fileF); +} + +} // namespace diff --git a/src/envfs.h b/src/envfs.h new file mode 100644 index 00000000..aeaa6796 --- /dev/null +++ b/src/envfs.h @@ -0,0 +1,17 @@ +#ifndef ENV_ENVFS_H +#define ENV_ENVFS_H + +namespace env +{ + +using DirStartF = void (void*, std::wstring_view); +using DirEndF = void (void*, std::wstring_view); +using FileF = void (void*, std::wstring_view, FILETIME); + +void forEachEntry( + const std::wstring& path, void* cx, + DirStartF* dirStartF, DirEndF* dirEndF, FileF* fileF); + +} // namespace + +#endif // ENV_ENVFS_H diff --git a/src/main.cpp b/src/main.cpp index 4b291e75..6e2220ae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -885,6 +885,8 @@ int main(int argc, char *argv[]) MOApplication application(argc, argv); QStringList arguments = application.arguments(); + SetThisThreadName("main"); + setupPath(); bool forcePrimary = false; diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index 6e44cc91..28201a11 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -20,6 +20,8 @@ along with Mod Organizer. If not, see . #include "directoryentry.h" #include "windows_error.h" #include "error_report.h" +#include "envfs.h" +#include #include #include #include @@ -172,15 +174,15 @@ FileEntry::FileEntry() : { } -FileEntry::FileEntry(Index index, const std::wstring &name, DirectoryEntry *parent) : - m_Index(index), m_Name(name), m_Origin(-1), m_Archive(L"", -1), m_Parent(parent), +FileEntry::FileEntry(Index index, std::wstring_view name, DirectoryEntry *parent) : + m_Index(index), m_Name(name.begin(), name.end()), m_Origin(-1), m_Archive(L"", -1), m_Parent(parent), m_FileSize(NoFileSize), m_CompressedFileSize(NoFileSize), m_LastAccessed(time(nullptr)) { } void FileEntry::addOrigin( - int origin, FILETIME fileTime, const std::wstring &archive, int order) + int origin, FILETIME fileTime, std::wstring_view archive, int order) { m_LastAccessed = time(nullptr); if (m_Parent != nullptr) { @@ -192,7 +194,7 @@ void FileEntry::addOrigin( // alternatives m_Origin = origin; m_FileTime = fileTime; - m_Archive = std::pair(archive, order); + m_Archive = std::pair(std::wstring(archive.begin(), archive.end()), order); } else if ( (m_Parent != nullptr) && ( @@ -213,7 +215,7 @@ void FileEntry::addOrigin( m_Origin = origin; m_FileTime = fileTime; - m_Archive = std::pair(archive, order); + m_Archive = std::pair(std::wstring(archive.begin(), archive.end()), order); } else { // This mod is just an alternative @@ -232,14 +234,14 @@ void FileEntry::addOrigin( if ((m_Parent != nullptr) && (m_Parent->getOriginByID(iter->first).getPriority() < m_Parent->getOriginByID(origin).getPriority())) { - m_Alternatives.insert(iter, {origin, {archive, order}}); + m_Alternatives.insert(iter, {origin, {std::wstring(archive.begin(), archive.end()), order}}); found = true; break; } } if (!found) { - m_Alternatives.push_back({origin, {archive, order}}); + m_Alternatives.push_back({origin, {std::wstring(archive.begin(), archive.end()), order}}); } } } @@ -509,12 +511,12 @@ bool FileRegister::indexValid(FileEntry::Index index) const return (m_Files.find(index) != m_Files.end()); } -FileEntry::Ptr FileRegister::createFile(const std::wstring &name, DirectoryEntry *parent) +FileEntry::Ptr FileRegister::createFile(std::wstring_view name, DirectoryEntry *parent) { FileEntry::Index index = generateIndex(); auto r = m_Files.insert_or_assign( - index, FileEntry::Ptr(new FileEntry(index, name, parent))); + index, FileEntry::Ptr(new FileEntry(index, std::move(name), parent))); return r.first->second; } @@ -637,20 +639,20 @@ void FileRegister::unregisterFile(FileEntry::Ptr file) DirectoryEntry::DirectoryEntry( - const std::wstring &name, DirectoryEntry *parent, int originID) : + std::wstring name, DirectoryEntry *parent, int originID) : m_OriginConnection(new OriginConnection), - m_Name(name), m_Parent(parent), m_Populated(false), m_TopLevel(true) + m_Name(std::move(name)), m_Parent(parent), m_Populated(false), m_TopLevel(true) { m_FileRegister.reset(new FileRegister(m_OriginConnection)); m_Origins.insert(originID); } DirectoryEntry::DirectoryEntry( - const std::wstring &name, DirectoryEntry *parent, int originID, + std::wstring name, DirectoryEntry *parent, int originID, boost::shared_ptr fileRegister, boost::shared_ptr originConnection) : m_FileRegister(fileRegister), m_OriginConnection(originConnection), - m_Name(name), m_Parent(parent), m_Populated(false), m_TopLevel(false) + m_Name(std::move(name)), m_Parent(parent), m_Populated(false), m_TopLevel(false) { m_Origins.insert(originID); } @@ -1025,8 +1027,8 @@ void DirectoryEntry::removeFiles(const std::set &indices) } FileEntry::Ptr DirectoryEntry::insert( - const std::wstring &fileName, FilesOrigin &origin, FILETIME fileTime, - const std::wstring &archive, int order) + std::wstring_view fileName, FilesOrigin &origin, FILETIME fileTime, + std::wstring_view archive, int order) { std::wstring fileNameLower = ToLowerCopy(fileName); @@ -1050,6 +1052,35 @@ FileEntry::Ptr DirectoryEntry::insert( void DirectoryEntry::addFiles(FilesOrigin &origin, wchar_t *buffer, int bufferOffset) { + struct Context + { + FilesOrigin& origin; + std::stack current; + }; + + Context cx = {origin}; + cx.current.push(this); + + env::forEachEntry(buffer, &cx, + [](void* pcx, std::wstring_view path) { + Context* cx = (Context*)pcx; + cx->current.push(cx->current.top()->getSubDirectory(path, true, cx->origin.getID())); + }, + + [](void* pcx, std::wstring_view path) { + Context* cx = (Context*)pcx; + auto* current= cx->current.top(); + std::sort(current->m_SubDirectories.begin(), current->m_SubDirectories.end(), &DirCompareByName); + cx->current.pop(); + }, + + [](void* pcx, std::wstring_view path, FILETIME ft) { + Context* cx = (Context*)pcx; + cx->current.top()->insert(path, cx->origin, ft, L"", -1); + } + ); + + /* WIN32_FIND_DATAW findData; _snwprintf_s(buffer + bufferOffset, MAXPATH_UNICODE - bufferOffset, _TRUNCATE, L"\\*"); @@ -1087,7 +1118,7 @@ void DirectoryEntry::addFiles(FilesOrigin &origin, wchar_t *buffer, int bufferOf } std::sort(m_SubDirectories.begin(), m_SubDirectories.end(), &DirCompareByName); - ::FindClose(searchHandle); + ::FindClose(searchHandle);*/ } void DirectoryEntry::addFiles( @@ -1119,17 +1150,18 @@ void DirectoryEntry::addFiles( } DirectoryEntry *DirectoryEntry::getSubDirectory( - const std::wstring &name, bool create, int originID) + std::wstring_view name, bool create, int originID) { - for (DirectoryEntry *entry : m_SubDirectories) { - if (CaseInsensitiveEqual(entry->getName(), name)) { - return entry; - } + auto itor = m_SubDirectoriesLookup.find(ToLowerCopy(name)); + + if (itor != m_SubDirectoriesLookup.end()) { + return itor->second; } if (create) { auto* entry = new DirectoryEntry( - name, this, originID, m_FileRegister, m_OriginConnection); + std::wstring(name.begin(), name.end()), this, originID, + m_FileRegister, m_OriginConnection); addDirectoryToList(entry); diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h index e26011d7..1a8a4247 100644 --- a/src/shared/directoryentry.h +++ b/src/shared/directoryentry.h @@ -78,7 +78,7 @@ public: AlternativesVector; FileEntry(); - FileEntry(Index index, const std::wstring &name, DirectoryEntry *parent); + FileEntry(Index index, std::wstring_view name, DirectoryEntry *parent); Index getIndex() const { @@ -91,7 +91,7 @@ public: } void addOrigin( - int origin, FILETIME fileTime, const std::wstring &archive, int order); + int origin, FILETIME fileTime, std::wstring_view archive, int order); // remove the specified origin from the list of origins that contain this // file. if no origin is left, the file is effectively deleted and true is @@ -261,7 +261,7 @@ public: bool indexValid(FileEntry::Index index) const; - FileEntry::Ptr createFile(const std::wstring &name, DirectoryEntry *parent); + FileEntry::Ptr createFile(std::wstring_view name, DirectoryEntry *parent); FileEntry::Ptr getFile(FileEntry::Index index) const; size_t size() const @@ -312,10 +312,10 @@ public: using FileKey = DirectoryEntryFileKey; DirectoryEntry( - const std::wstring &name, DirectoryEntry *parent, int originID); + std::wstring name, DirectoryEntry *parent, int originID); DirectoryEntry( - const std::wstring &name, DirectoryEntry *parent, int originID, + std::wstring name, DirectoryEntry *parent, int originID, boost::shared_ptr fileRegister, boost::shared_ptr originConnection); @@ -501,8 +501,8 @@ private: DirectoryEntry(const DirectoryEntry &reference); FileEntry::Ptr insert( - const std::wstring &fileName, FilesOrigin &origin, FILETIME fileTime, - const std::wstring &archive, int order); + std::wstring_view fileName, FilesOrigin &origin, FILETIME fileTime, + std::wstring_view archive, int order); void addFiles( FilesOrigin &origin, wchar_t *buffer, int bufferOffset); @@ -511,10 +511,10 @@ private: FilesOrigin &origin, BSA::Folder::Ptr archiveFolder, FILETIME &fileTime, const std::wstring &archiveName, int order); - DirectoryEntry *getSubDirectory( - const std::wstring &name, bool create, int originID = -1); + DirectoryEntry* getSubDirectory( + std::wstring_view name, bool create, int originID = -1); - DirectoryEntry *getSubDirectoryRecursive( + DirectoryEntry* getSubDirectoryRecursive( const std::wstring &path, bool create, int originID = -1); void removeDirRecursive(); diff --git a/src/shared/util.cpp b/src/shared/util.cpp index aa4ad4b3..74e386a3 100644 --- a/src/shared/util.cpp +++ b/src/shared/util.cpp @@ -130,6 +130,13 @@ std::wstring ToLowerCopy(const std::wstring& text) return result; } +std::wstring ToLowerCopy(std::wstring_view text) +{ + std::wstring result(text.begin(), text.end()); + ToLowerInPlace(result); + return result; +} + bool CaseInsenstiveComparePred(wchar_t lhs, wchar_t rhs) { return std::tolower(lhs, loc) == std::tolower(rhs, loc); diff --git a/src/shared/util.h b/src/shared/util.h index 05522c2d..dc6e72ad 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -41,6 +41,7 @@ std::string ToLowerCopy(const std::string& text); std::wstring& ToLowerInPlace(std::wstring& text); std::wstring ToLowerCopy(const std::wstring& text); +std::wstring ToLowerCopy(std::wstring_view text); bool CaseInsensitiveEqual(const std::wstring &lhs, const std::wstring &rhs); diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp index 59880754..ed6e31ce 100644 --- a/src/usvfsconnector.cpp +++ b/src/usvfsconnector.cpp @@ -70,6 +70,8 @@ LogWorker::~LogWorker() void LogWorker::process() { + MOShared::SetThisThreadName("LogWorker"); + int noLogCycles = 0; while (!m_QuitRequested) { if (GetLogMessages(&m_Buffer[0], m_Buffer.size(), false)) { -- cgit v1.3.1