std::shared_ptr<FileWatch> FileMonitorWin::Watch(const std::filesystem::path& path, const t_callbackFunc& callback, FileWatch::State states) { try { if(!std::filesystem::exists(path)) return nullptr; } catch (...) { return nullptr; } std::filesystem::path directory = (std::filesystem::is_directory(path) || !path.has_parent_path()) ? path : path.parent_path(); // Ugh. std::wstring wpath; #if _MSC_VER >= 1900 wpath = directory.wstring(); #else auto str = directory.string(); wpath.assign(str.begin(), str.end()); #endif // Open the handle to the directory we were asked to watch with the // correct permissions so that we can actually conduct asynchronous // read operations. HANDLE hFile = CreateFileW( wpath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_BACKUP_SEMANTICS, nullptr ); if (hFile == INVALID_HANDLE_VALUE) // No such file, what else can we do? return nullptr; // Compose the notification filter based on the user's request DWORD dwNotifyFilter = 0; if(states & FileWatch::State::RENAMED || states & FileWatch::State::DELETED) dwNotifyFilter |= FILE_NOTIFY_CHANGE_FILE_NAME; if(states & FileWatch::State::MODIFIED) dwNotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE; // Need a second-order shared pointer so we can preserve references Entry* pEntry; auto key = m_nextKey++; { std::lock_guard<std::mutex> lk(GetLock()); pEntry = &m_outstanding[key]; pEntry->key = key; } // Need an overlapped structure to track this operation. We'll also be using this to decide // how to notify the true caller. auto watcher = std::shared_ptr<FileWatchWin>( new FileWatchWin(path, callback, dwNotifyFilter, hFile), [this, key](FileWatchWin* fileWatch) { --m_numWatchers; delete fileWatch; m_outstanding.erase(key); } ); pEntry->watcherWeak = watcher; // Attach to the completion port with the FileWatchWin we just constructed if (!CreateIoCompletionPort(hFile, m_hCompletion, key, 0)) { // Something went wrong, can't attach a watcher at this point m_outstanding.erase(key); return nullptr; } // Initial pend, and then return to the controller watcher->ReadDirectoryChanges(); ++m_numWatchers; return watcher; }
// The processPath ends with dotnet.exe or dotnet // like: C:\Program Files\dotnet\dotnet.exe, C:\Program Files\dotnet\dotnet, dotnet.exe, or dotnet. // Get the absolute path to dotnet. If the path is already an absolute path, it will return that path fs::path HOSTFXR_UTILITY::GetAbsolutePathToDotnet( const fs::path & applicationPath, const fs::path & requestedPath ) { LOG_INFOF(L"Resolving absolute path to dotnet.exe from '%ls'", requestedPath.c_str()); auto processPath = requestedPath; if (processPath.is_relative()) { processPath = applicationPath / processPath; } // // If we are given an absolute path to dotnet.exe, we are done // if (is_regular_file(processPath)) { LOG_INFOF(L"Found dotnet.exe at '%ls'", processPath.c_str()); return processPath; } // At this point, we are calling where.exe to find dotnet. // If we encounter any failures, try getting dotnet.exe from the // backup location. // Only do it if no path is specified if (requestedPath.has_parent_path()) { LOG_INFOF(L"Absolute path to dotnet.exe was not found at '%ls'", requestedPath.c_str()); throw InvalidOperationException(format(L"Could not find dotnet.exe at '%s'", processPath.c_str())); } const auto dotnetViaWhere = InvokeWhereToFindDotnet(); if (dotnetViaWhere.has_value()) { LOG_INFOF(L"Found dotnet.exe via where.exe invocation at '%ls'", dotnetViaWhere.value().c_str()); return dotnetViaWhere.value(); } const auto programFilesLocation = GetAbsolutePathToDotnetFromProgramFiles(); if (programFilesLocation.has_value()) { LOG_INFOF(L"Found dotnet.exe in Program Files at '%ls'", programFilesLocation.value().c_str()); return programFilesLocation.value(); } LOG_INFOF(L"dotnet.exe not found"); throw InvalidOperationException(format( L"Could not find dotnet.exe at '%s' or using the system PATH environment variable." " Check that a valid path to dotnet is on the PATH and the bitness of dotnet matches the bitness of the IIS worker process.", processPath.c_str())); }