diff --git a/includes/win32/Watcher.h b/includes/win32/Watcher.h index a7944770..ab63c8b0 100644 --- a/includes/win32/Watcher.h +++ b/includes/win32/Watcher.h @@ -14,7 +14,7 @@ class Watcher { public: - Watcher(std::shared_ptr queue, HANDLE dirHandle, const std::wstring &path); + Watcher(std::shared_ptr queue, HANDLE dirHandle, const std::wstring &path, bool pathWasNtPrefixed); ~Watcher(); bool isRunning() const { return mRunning; } @@ -42,6 +42,7 @@ class Watcher const std::wstring mPath; std::shared_ptr mQueue; HANDLE mDirectoryHandle; + bool mPathWasNtPrefixed; std::vector mReadBuffer, mWriteBuffer; OVERLAPPED mOverlapped; diff --git a/src/win32/Controller.cpp b/src/win32/Controller.cpp index b0efcd56..98e5066a 100644 --- a/src/win32/Controller.cpp +++ b/src/win32/Controller.cpp @@ -1,5 +1,26 @@ #include "../includes/win32/Controller.h" +static bool isNtPath(const std::wstring &path) { + return path.rfind(L"\\\\?\\", 0) == 0 || path.rfind(L"\\??\\", 0) == 0; +} + +static std::wstring prefixWithNtPath(const std::wstring &path) { + const ULONG widePathLength = GetFullPathNameW(path.c_str(), 0, nullptr, nullptr); + if (widePathLength == 0) { + return path; + } + + std::wstring ntPathString; + ntPathString.resize(widePathLength - 1); + if (GetFullPathNameW(path.c_str(), widePathLength, &(ntPathString[0]), nullptr) != widePathLength - 1) { + return path; + } + + return ntPathString.rfind(L"\\\\", 0) == 0 + ? ntPathString.replace(0, 2, L"\\\\?\\UNC\\") + : ntPathString.replace(0, 0, L"\\\\?\\"); +} + static std::wstring convertMultiByteToWideChar(const std::string &multiByte) { const int wlen = MultiByteToWideChar(CP_UTF8, 0, multiByte.data(), -1, 0, 0); @@ -8,11 +29,13 @@ static std::wstring convertMultiByteToWideChar(const std::string &multiByte) { } std::wstring wideString; - wideString.resize(wlen-1); + wideString.resize(wlen - 1); + int failureToResolveUTF8 = MultiByteToWideChar(CP_UTF8, 0, multiByte.data(), -1, &(wideString[0]), wlen); if (failureToResolveUTF8 == 0) { return std::wstring(); } + return wideString; } @@ -35,13 +58,18 @@ Controller::Controller(std::shared_ptr queue, const std::string &pat : mDirectoryHandle(INVALID_HANDLE_VALUE) { auto widePath = convertMultiByteToWideChar(path); + const bool isNt = isNtPath(widePath); + if (!isNt) { + // We convert to an NT Path to support paths > MAX_PATH + widePath = prefixWithNtPath(widePath); + } mDirectoryHandle = openDirectory(widePath); if (mDirectoryHandle == INVALID_HANDLE_VALUE) { return; } - mWatcher.reset(new Watcher(queue, mDirectoryHandle, widePath)); + mWatcher.reset(new Watcher(queue, mDirectoryHandle, widePath, isNt)); } Controller::~Controller() { @@ -63,5 +91,5 @@ bool Controller::hasErrored() { } bool Controller::isWatching() { - return mWatcher->isRunning(); + return !hasErrored() && mWatcher->isRunning(); } diff --git a/src/win32/Watcher.cpp b/src/win32/Watcher.cpp index 8a504ea9..145abcd6 100644 --- a/src/win32/Watcher.cpp +++ b/src/win32/Watcher.cpp @@ -2,6 +2,15 @@ #include +static +void stripNTPrefix(std::wstring &path) { + if (path.rfind(L"\\\\?\\UNC\\", 0) != std::wstring::npos) { + path.replace(0, 7, L"\\"); + } else if (path.rfind(L"\\\\?\\", 0) != std::wstring::npos) { + path.erase(0, 4); + } +} + static std::wstring getWStringFileName(LPWSTR cFileName, DWORD length) { LPWSTR nullTerminatedFileName = new WCHAR[length + 1](); @@ -24,6 +33,12 @@ std::string Watcher::getUTF8Directory(std::wstring path) { } std::wstring uft16DirectoryString = utf16DirectoryStream.str(); + if (!mPathWasNtPrefixed) { + // If we were the ones that prefixed the path, we should strip it + // before returning it to the user + stripNTPrefix(uft16DirectoryString); + } + int utf8length = WideCharToMultiByte( CP_UTF8, 0, @@ -89,11 +104,12 @@ std::string getUTF8FileName(std::wstring path) { return utf8Directory; } -Watcher::Watcher(std::shared_ptr queue, HANDLE dirHandle, const std::wstring &path) +Watcher::Watcher(std::shared_ptr queue, HANDLE dirHandle, const std::wstring &path, bool pathWasNtPrefixed) : mRunning(false), mDirectoryHandle(dirHandle), mQueue(queue), - mPath(path) + mPath(path), + mPathWasNtPrefixed(pathWasNtPrefixed) { ZeroMemory(&mOverlapped, sizeof(OVERLAPPED)); mOverlapped.hEvent = this;