return S_OK;
}
- IFACEMETHODIMP OCOverlay::IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib)
+IFACEMETHODIMP OCOverlay::IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib)
{
RemotePathChecker* checker = getGlobalChecker();
- auto watchedDirectories = checker->WatchedDirectories();
+ std::shared_ptr<const std::vector<std::wstring>> watchedDirectories = checker->WatchedDirectories();
+
+ if (watchedDirectories->empty()) {
+ return MAKE_HRESULT(S_FALSE, 0, 0);
+ }
- wstring wpath(pwszPath);
- wpath.append(L"\\");
- vector<wstring>::iterator it;
bool watched = false;
- for (it = watchedDirectories.begin(); it != watchedDirectories.end(); ++it) {
- if (StringUtil::begins_with(wpath, *it)) {
+ size_t pathLength = wcslen(pwszPath);
+ for (auto it = watchedDirectories->begin(); it != watchedDirectories->end(); ++it) {
+ if (StringUtil::isDescendantOf(pwszPath, pathLength, *it)) {
watched = true;
}
}
return S_OK;
}
-
-
-bool OCOverlay::_IsOverlaysEnabled()
-{
- //int enable;
- bool success = false;
-
- //if(RegistryUtil::ReadRegistry(REGISTRY_ROOT_KEY, REGISTRY_ENABLE_OVERLAY, &enable))
- //{
- // if(enable) {
- // success = true;
- // }
- //}
-
- return success;
-}
-
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
wstring responsePath = response.substr(14); // length of REGISTER_PATH:
- { std::unique_lock<std::mutex> lock(_mutex);
- _watchedDirectories.push_back(responsePath);
- }
- // We don't keep track of all files and can't know which file is currently visible to the user,
- // but at least reload the root dir + itself so that any shortcut to the root is updated without
- // the user needing to navigate.
+ auto sharedPtrCopy = atomic_load(&_watchedDirectories);
+ auto vectorCopy = make_shared<vector<wstring>>(*sharedPtrCopy);
+ vectorCopy->push_back(responsePath);
+ atomic_store(&_watchedDirectories, shared_ptr<const vector<wstring>>(vectorCopy));
+
+ // We don't keep track of all files and can't know which file is currently visible
+ // to the user, but at least reload the root dir so that any shortcut to the root
+ // is updated without the user needing to refresh.
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
} else if (StringUtil::begins_with(response, wstring(L"UNREGISTER_PATH:"))) {
wstring responsePath = response.substr(16); // length of UNREGISTER_PATH:
+ auto sharedPtrCopy = atomic_load(&_watchedDirectories);
+ auto vectorCopy = make_shared<vector<wstring>>(*sharedPtrCopy);
+ vectorCopy->erase(
+ std::remove(vectorCopy->begin(), vectorCopy->end(), responsePath),
+ vectorCopy->end());
+ atomic_store(&_watchedDirectories, shared_ptr<const vector<wstring>>(vectorCopy));
+
vector<wstring> removedPaths;
{ std::unique_lock<std::mutex> lock(_mutex);
- _watchedDirectories.erase(
- std::remove(_watchedDirectories.begin(), _watchedDirectories.end(), responsePath),
- _watchedDirectories.end());
-
// Remove any item from the cache
for (auto it = _cache.begin(); it != _cache.end() ; ) {
- if (StringUtil::begins_with(it->first, responsePath)) {
+ if (StringUtil::isDescendantOf(it->first, responsePath)) {
removedPaths.emplace_back(move(it->first));
it = _cache.erase(it);
} else {
}
if (socket.Event() == INVALID_HANDLE_VALUE) {
+ atomic_store(&_watchedDirectories, make_shared<const vector<wstring>>());
std::unique_lock<std::mutex> lock(_mutex);
- _watchedDirectories.clear();
_connected = connected = false;
// Swap to make a copy of the cache under the mutex and clear the one stored.
RemotePathChecker::RemotePathChecker()
- : _connected(false)
+ : _watchedDirectories(make_shared<const vector<wstring>>())
+ , _connected(false)
, _newQueries(CreateEvent(NULL, true, true, NULL))
, _thread([this]{ this->workerThreadLoop(); })
{
CloseHandle(_newQueries);
}
-vector<wstring> RemotePathChecker::WatchedDirectories()
+std::shared_ptr<const std::vector<std::wstring>> RemotePathChecker::WatchedDirectories() const
{
- std::unique_lock<std::mutex> lock(_mutex);
- return _watchedDirectories;
+ return atomic_load(&_watchedDirectories);
}
bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
#include <unordered_map>
#include <queue>
#include <thread>
+#include <memory>
#include <mutex>
#include <atomic>
#include <condition_variable>
};
RemotePathChecker();
~RemotePathChecker();
- std::vector<std::wstring> WatchedDirectories();
+ std::shared_ptr<const std::vector<std::wstring>> WatchedDirectories() const;
bool IsMonitoredPath(const wchar_t* filePath, int* state);
private:
std::queue<std::wstring> _pending;
std::unordered_map<std::wstring, FileState> _cache;
- std::vector<std::wstring> _watchedDirectories;
+ // The vector is const since it will be accessed from multiple threads through OCOverlay::IsMemberOf.
+ // Each modification needs to be made onto a copy and then atomically replaced in the shared_ptr.
+ std::shared_ptr<const std::vector<std::wstring>> _watchedDirectories;
bool _connected;
return input.size() >= match.size()
&& std::equal(match.begin(), match.end(), input.begin());
}
+
+ static bool isDescendantOf(const std::wstring& child, const std::wstring& parent) {
+ return isDescendantOf(child.c_str(), child.size(), parent.c_str(), parent.size());
+ }
+
+ static bool isDescendantOf(PCWSTR child, size_t childLength, const std::wstring& parent) {
+ return isDescendantOf(child, childLength, parent.c_str(), parent.size());
+ }
+
+ static bool isDescendantOf(PCWSTR child, size_t childLength, PCWSTR parent, size_t parentLength) {
+ if (!parentLength)
+ return false;
+ return (childLength == parentLength || childLength > parentLength && (child[parentLength] == L'\\' || child[parentLength - 1] == L'\\'))
+ && wcsncmp(child, parent, parentLength) == 0;
+ }
};
#endif // STRINGUTIL_H