From bfc483804297ce41a45c750d92249179a905f2a7 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 12 May 2021 12:36:11 -0500 Subject: [PATCH] Disable path validation, add warning (#10045) This is primarily being done to unblock #9223. Prior to this, we'd validate that the user's `startingDirectory` existed here. If it was invalid, we'd gracefully fall back to `%USERPROFILE%`. However, that could cause hangs when combined with WSL. When the WSL filesystem is slow to respond, we'll end up waiting indefinitely for their filesystem driver to respond. This can result in the whole terminal becoming unresponsive. Similarly, with #9223 we want users to be able to specify WSL paths in a profile, but this bit of validation logic totally prevents that from working, because it'll just replace the path with `%USERPROFILE%`. If the path is eventually invalid, we'll display warning in the `ConptyConnection`, when the process fails to launch. Closes #9541 Closes #9114 ![image](https://user-images.githubusercontent.com/18356694/117318675-426d2d00-ae50-11eb-9cc0-0b23c397472c.png) --- .../TerminalConnection/ConptyConnection.cpp | 14 +++++++++- .../Resources/en-US/Resources.resw | 6 ++++- .../TerminalSettingsModel/Profile.cpp | 26 ++++++++----------- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/cascadia/TerminalConnection/ConptyConnection.cpp b/src/cascadia/TerminalConnection/ConptyConnection.cpp index f98ef137049..a88fa2ee6b2 100644 --- a/src/cascadia/TerminalConnection/ConptyConnection.cpp +++ b/src/cascadia/TerminalConnection/ConptyConnection.cpp @@ -300,8 +300,20 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation // EXIT POINT const auto hr = wil::ResultFromCaughtException(); - winrt::hstring failureText{ fmt::format(std::wstring_view{ RS_(L"ProcessFailedToLaunch") }, gsl::narrow_cast(hr), _commandline) }; + winrt::hstring failureText{ fmt::format(std::wstring_view{ RS_(L"ProcessFailedToLaunch") }, + gsl::narrow_cast(hr), + _commandline) }; _TerminalOutputHandlers(failureText); + + // If the path was invalid, let's present an informative message to the user + if (hr == HRESULT_FROM_WIN32(ERROR_DIRECTORY)) + { + winrt::hstring badPathText{ fmt::format(std::wstring_view{ RS_(L"BadPathText") }, + _startingDirectory) }; + _TerminalOutputHandlers(L"\r\n"); + _TerminalOutputHandlers(badPathText); + } + _transitionToState(ConnectionState::Failed); // Tear down any state we may have accumulated. diff --git a/src/cascadia/TerminalConnection/Resources/en-US/Resources.resw b/src/cascadia/TerminalConnection/Resources/en-US/Resources.resw index b0abd44a0cb..d32f5926960 100644 --- a/src/cascadia/TerminalConnection/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalConnection/Resources/en-US/Resources.resw @@ -212,4 +212,8 @@ The first argument {0...} is the hexadecimal error code. The second argument {1} is the user-specified path to a program. If this string is broken to multiple lines, it will not be displayed properly. - + + Could not access starting directory "{0}" + The first argument {0} is a path to a directory on the filesystem, as provided by the user. + + \ No newline at end of file diff --git a/src/cascadia/TerminalSettingsModel/Profile.cpp b/src/cascadia/TerminalSettingsModel/Profile.cpp index 5c3e03c8648..c3cb73774f2 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.cpp +++ b/src/cascadia/TerminalSettingsModel/Profile.cpp @@ -413,21 +413,17 @@ std::wstring Profile::EvaluateStartingDirectory(const std::wstring& directory) std::unique_ptr evaluatedPath = std::make_unique(numCharsInput); THROW_LAST_ERROR_IF(0 == ExpandEnvironmentStrings(directory.c_str(), evaluatedPath.get(), numCharsInput)); - // Validate that the resulting path is legitimate - const DWORD dwFileAttributes = GetFileAttributes(evaluatedPath.get()); - if ((dwFileAttributes != INVALID_FILE_ATTRIBUTES) && (WI_IsFlagSet(dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))) - { - return std::wstring(evaluatedPath.get(), numCharsInput); - } - else - { - // In the event where the user supplied a path that can't be resolved, use a reasonable default (in this case, %userprofile%) - const DWORD numCharsDefault = ExpandEnvironmentStrings(DEFAULT_STARTING_DIRECTORY.c_str(), nullptr, 0); - std::unique_ptr defaultPath = std::make_unique(numCharsDefault); - THROW_LAST_ERROR_IF(0 == ExpandEnvironmentStrings(DEFAULT_STARTING_DIRECTORY.c_str(), defaultPath.get(), numCharsDefault)); - - return std::wstring(defaultPath.get(), numCharsDefault); - } + // Prior to GH#9541, we'd validate that the user's startingDirectory existed + // here. If it was invalid, we'd gracefully fall back to %USERPROFILE%. + // + // However, that could cause hangs when combined with WSL. When the WSL + // filesystem is slow to respond, we'll end up waiting indefinitely for + // their filesystem driver to respond. This can result in the whole terminal + // becoming unresponsive. + // + // If the path is eventually invalid, we'll display warning in the + // ConptyConnection when the process fails to launch. + return std::wstring(evaluatedPath.get(), numCharsInput); } // Function Description: