diff options
| -rw-r--r-- | src/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/directoryrefresher.cpp | 5 | ||||
| -rw-r--r-- | src/envfs.cpp | 303 | ||||
| -rw-r--r-- | src/envfs.h | 17 | ||||
| -rw-r--r-- | src/main.cpp | 2 | ||||
| -rw-r--r-- | src/shared/directoryentry.cpp | 76 | ||||
| -rw-r--r-- | src/shared/directoryentry.h | 20 | ||||
| -rw-r--r-- | src/shared/util.cpp | 7 | ||||
| -rw-r--r-- | src/shared/util.h | 1 | ||||
| -rw-r--r-- | src/usvfsconnector.cpp | 2 |
10 files changed, 403 insertions, 33 deletions
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 <utility.h> +#include <log.h> + +using namespace MOBase; + +struct NtCloser +{ + using pointer = HANDLE; + void operator()(HANDLE h) + { + } +}; + +using NtHandle = std::unique_ptr<HANDLE, NtCloser>; + +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<int>(sv.size())); +} + + +constexpr std::size_t AllocSize = 1024 * 1024; +std::vector<std::unique_ptr<unsigned char[]>> 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<unsigned char> buffer(new unsigned char[AllocSize]); + + unsigned char* buffer; + + if (depth >= g_buffers.size()) { + g_buffers.emplace_back(std::make_unique<unsigned char[]>(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<wchar_t*>(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 <http://www.gnu.org/licenses/>. #include "directoryentry.h"
#include "windows_error.h"
#include "error_report.h"
+#include "envfs.h"
+#include <utility.h>
#include <log.h>
#include <bsatk.h>
#include <boost/bind.hpp>
@@ -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<std::wstring, int>(archive, order);
+ m_Archive = std::pair<std::wstring, int>(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<std::wstring, int>(archive, order);
+ m_Archive = std::pair<std::wstring, int>(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> fileRegister,
boost::shared_ptr<OriginConnection> 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<FileEntry::Index> &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<DirectoryEntry*> 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> fileRegister,
boost::shared_ptr<OriginConnection> 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)) { |
