diff --git a/src/Corrade/Utility/Path.cpp b/src/Corrade/Utility/Path.cpp index defb657fb..405af4477 100644 --- a/src/Corrade/Utility/Path.cpp +++ b/src/Corrade/Utility/Path.cpp @@ -595,9 +595,15 @@ Containers::Optional homeDirectory() { #elif defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT) /** @todo get rid of MAX_PATH */ wchar_t h[MAX_PATH + 1]; - /* There doesn't seem to be any possibility how this could fail, so just - assert */ - CORRADE_INTERNAL_ASSERT(SHGetFolderPathW(nullptr, CSIDL_PERSONAL, nullptr, 0, h) == S_OK); + /* This could fail for example with E_INVALIDARG for system accounts + without a home folder */ + if(SHGetFolderPathW(nullptr, CSIDL_PERSONAL, nullptr, 0, h) != S_OK) { + Error err; + err << "Utility::Path::homeDirectory(): can't retrieve CSIDL_PERSONAL:"; + Utility::Implementation::printWindowsErrorString(err, GetLastError()); + return {}; + } + return fromNativeSeparators(Unicode::narrow(h)); /* Other */ @@ -641,11 +647,12 @@ Containers::Optional configurationDirectory(const Containers #elif defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT) /** @todo get rid of MAX_PATH */ wchar_t path[MAX_PATH]; - /* There doesn't seem to be any possibility how this could fail, so just - assert */ - CORRADE_INTERNAL_ASSERT(SHGetFolderPathW(nullptr, CSIDL_APPDATA, nullptr, 0, path) == S_OK); - if(path[0] == L'\0') { - Error{} << "Utility::Path::configurationDirectory(): can't retrieve CSIDL_APPDATA"; + /* This could fail for example with E_INVALIDARG for system accounts + without a home folder */ + if(SHGetFolderPathW(nullptr, CSIDL_APPDATA, nullptr, 0, path) != S_OK) { + Error err; + err << "Utility::Path::configurationDirectory(): can't retrieve CSIDL_APPDATA:"; + Utility::Implementation::printWindowsErrorString(err, GetLastError()); return {}; } return join(fromNativeSeparators(Unicode::narrow(path)), applicationName); diff --git a/src/Corrade/Utility/Test/PathTest.cpp b/src/Corrade/Utility/Test/PathTest.cpp index acfc2ec4b..13ba9199f 100644 --- a/src/Corrade/Utility/Test/PathTest.cpp +++ b/src/Corrade/Utility/Test/PathTest.cpp @@ -1530,8 +1530,24 @@ void PathTest::homeDirectory() { } void PathTest::homeDirectoryInvalid() { - /* Could be tested by temporarily removing $HOME, but ... ahem */ + #ifdef CORRADE_TARGET_WINDOWS + /* The query fails for system accounts, and system accounts apparently have + no access to environment, so checking if %HOMEPATH% is missing: + https://serverfault.com/questions/292040/win-service-running-under-localservice-account-cannot-access-environment-variabl */ + if(std::getenv("HOMEPATH")) + CORRADE_SKIP("%HOMEPATH% exists, can't test."); + + std::ostringstream out; + Error redirectError{&out}; + CORRADE_VERIFY(!Path::homeDirectory()); + CORRADE_COMPARE_AS(out.str(), + "Utility::Path::homeDirectory(): can't retrieve CSIDL_PERSONAL: error 666 (", + TestSuite::Compare::StringHasPrefix); + + #else + /* On Unix could be tested by temporarily removing $HOME, but ... ahem */ CORRADE_SKIP("Not sure how to test this."); + #endif } void PathTest::homeDirectoryUtf8() { @@ -1601,9 +1617,25 @@ void PathTest::configurationDirectory() { } void PathTest::configurationDirectoryInvalid() { - /* Could be tested by temporarily removing $XDG_CONFIG_HOME and $HOME, but - ... ahem */ + #ifdef CORRADE_TARGET_WINDOWS + /* The query fails for system accounts, and system accounts apparently have + no access to environment, so checking if %HOMEPATH% is missing: + https://serverfault.com/questions/292040/win-service-running-under-localservice-account-cannot-access-environment-variabl */ + if(std::getenv("APPDATA")) + CORRADE_SKIP("%APPDATA% exists, can't test."); + + std::ostringstream out; + Error redirectError{&out}; + CORRADE_VERIFY(!Path::configurationDirectory("Corrade")); + CORRADE_COMPARE_AS(out.str(), + "Utility::Path::configurationDirectory(): can't retrieve CSIDL_APPDATA: error 666 (", + TestSuite::Compare::StringHasPrefix); + + #else + /* On Unix could be tested by temporarily removing $XDG_CONFIG_HOME and + $HOME, but ... ahem */ CORRADE_SKIP("Not sure how to test this."); + #endif } void PathTest::configurationDirectoryUtf8() {