Skip to content

Commit

Permalink
Merge pull request #46 from zao/fix/bad-userpath
Browse files Browse the repository at this point in the history
fix: harden UserPath against unusable folders
  • Loading branch information
Wires77 authored Mar 27, 2024
2 parents 23a0c59 + ea4ee20 commit 6f8c80b
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 11 deletions.
5 changes: 3 additions & 2 deletions engine/system/sys_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ class sys_IMain {
bool debug = false;
bool debuggerRunning = false;
int processorCount = 0;
std::string basePath;
std::string userPath;
std::string basePath;
std::optional<std::string> userPath;
std::optional<std::string> invalidUserPath;

virtual int GetTime() = 0;
virtual void Sleep(int msec) = 0;
Expand Down
44 changes: 37 additions & 7 deletions engine/system/win/sys_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -712,14 +712,44 @@ std::string FindBasePath()
#endif
}

std::string FindUserPath()
std::optional<std::string> FindUserPath(std::optional<std::string>& invalidPath)
{
#ifdef _WIN32
PWSTR os_path{};
SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, &os_path);
std::filesystem::path path(os_path);
CoTaskMemFree(os_path);
return path.string();
PWSTR osPath{};
HRESULT hr = SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, &osPath);
if (FAILED(hr)) {
// The path may be inaccessible due to malfunctioning cloud providers.
CoTaskMemFree(osPath);
invalidPath.reset();
return {};
}
std::wstring pathStr = osPath;
CoTaskMemFree(osPath);
std::filesystem::path path(pathStr);
try {
return path.string();
}
catch (std::system_error) {
// The path could not be converted into the narrow representation, convert the path
// string lossily for use in an ASCII error message on the Lua side.
invalidPath.reset();
std::wstring pathStr = path.wstring();
char defGlyph = '?';
BOOL defGlyphUsed{};
DWORD convFlags = WC_COMPOSITECHECK | WC_NO_BEST_FIT_CHARS | WC_DEFAULTCHAR;
int cb = WideCharToMultiByte(CP_ACP, 0, pathStr.c_str(), -1, nullptr, 0, &defGlyph, &defGlyphUsed);
if (cb) {
std::vector<char> buf(cb);
WideCharToMultiByte(CP_ACP, 0, pathStr.c_str(), -1, buf.data(), cb, &defGlyph, &defGlyphUsed);
for (auto& ch : buf) {
if ((unsigned char)ch >= 0x80) {
ch = '?'; // Substitute characters that we can represent but can't draw.
}
}
invalidPath = buf.data();
}
return {};
}
#else
if (char const* data_home_path = getenv("XDG_DATA_HOME")) {
return data_home_path;
Expand Down Expand Up @@ -755,7 +785,7 @@ sys_main_c::sys_main_c()

// Set the local system information
basePath = FindBasePath();
userPath = FindUserPath();
userPath = FindUserPath(invalidUserPath);
}

bool sys_main_c::Run(int argc, char** argv)
Expand Down
14 changes: 12 additions & 2 deletions ui_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
** msec = GetTime()
** path = GetScriptPath()
** path = GetRuntimePath()
** path = GetUserPath()
** path, missingPath = GetUserPath() -- may fail, then returns nil and and approximation of the bad path
** SetWorkDir("<path>")
** path = GetWorkDir()
** ssID = LaunchSubScript("<scriptText>", "<funcList>", "<subList>"[, ...])
Expand Down Expand Up @@ -1065,7 +1065,17 @@ static int l_GetRuntimePath(lua_State* L)
static int l_GetUserPath(lua_State* L)
{
ui_main_c* ui = GetUIPtr(L);
lua_pushstring(L, ui->sys->userPath.c_str());
auto& userPath = ui->sys->userPath;
if (userPath) {
lua_pushstring(L, userPath->c_str());
return 1;
}

lua_pushnil(L);
if (auto& invalidUserPath = ui->sys->invalidUserPath) {
lua_pushstring(L, invalidUserPath->c_str());
return 2;
}
return 1;
}

Expand Down

0 comments on commit 6f8c80b

Please sign in to comment.