Update directory name sanitization

Only ASCII spaces have to be handles specially, and leading spaces are
also disallowed.
This commit is contained in:
ShadowNinja 2022-01-31 21:11:51 -05:00 committed by rubenwardy
parent 65fdc7ae50
commit dae6fe91a1
3 changed files with 23 additions and 30 deletions

@ -636,8 +636,12 @@ void TestUtilities::testBase64()
void TestUtilities::testSanitizeDirName() void TestUtilities::testSanitizeDirName()
{ {
UASSERT(sanitizeDirName("a", "_") == "a"); UASSERT(sanitizeDirName("a", "~") == "a");
UASSERT(sanitizeDirName("COM1", "_") == "_COM1"); UASSERT(sanitizeDirName(" ", "~") == "__");
UASSERT(sanitizeDirName("cOm\u00B2 .txt:a", "_") == "cOm\u00B2 _txt_a"); UASSERT(sanitizeDirName(" a ", "~") == "_a_");
UASSERT(sanitizeDirName("cOnIn$ ", "_") == "_cOnIn$ "); UASSERT(sanitizeDirName("COM1", "~") == "~COM1");
UASSERT(sanitizeDirName("COM1", ":") == "_COM1");
UASSERT(sanitizeDirName("cOm\u00B2", "~") == "~cOm\u00B2");
UASSERT(sanitizeDirName("cOnIn$", "~") == "~cOnIn$");
UASSERT(sanitizeDirName(" cOnIn$ ", "~") == "_cOnIn$_");
} }

@ -864,40 +864,29 @@ static const std::array<std::wstring, 30> disallowed_dir_names = {
static const std::wstring disallowed_path_chars = L"<>:\"/\\|?*."; static const std::wstring disallowed_path_chars = L"<>:\"/\\|?*.";
/**
* @param str
* @return A copy of \p str with trailing whitespace removed.
*/
static std::wstring wrtrim(const std::wstring &str)
{
size_t back = str.size();
while (back > 0 && std::isspace(str[back - 1]))
--back;
return str.substr(0, back);
}
/**
* Sanitize the name of a new directory. This consists of two stages:
* 1. Check for 'reserved filenames' that can't be used on some filesystems
* and add a prefix to them
* 2. Remove 'unsafe' characters from the name by replacing them with '_'
*/
std::string sanitizeDirName(const std::string &str, const std::string &optional_prefix) std::string sanitizeDirName(const std::string &str, const std::string &optional_prefix)
{ {
std::wstring safe_name = utf8_to_wide(str); std::wstring safe_name = utf8_to_wide(str);
std::wstring dev_name = wrtrim(safe_name);
for (std::wstring disallowed_name : disallowed_dir_names) { for (std::wstring disallowed_name : disallowed_dir_names) {
if (str_equal(dev_name, disallowed_name, true)) { if (str_equal(safe_name, disallowed_name, true)) {
safe_name = utf8_to_wide(optional_prefix) + safe_name; safe_name = utf8_to_wide(optional_prefix) + safe_name;
break; break;
} }
} }
for (unsigned long i = 0; i < safe_name.length(); i++) { // Replace leading and trailing spaces with underscores.
size_t start = safe_name.find_first_not_of(L' ');
size_t end = safe_name.find_last_not_of(L' ');
if (start == std::wstring::npos || end == std::wstring::npos)
start = end = safe_name.size();
for (size_t i = 0; i < start; i++)
safe_name[i] = L'_';
for (size_t i = end + 1; i < safe_name.size(); i++)
safe_name[i] = L'_';
// Replace other disallowed characters with underscores
for (size_t i = 0; i < safe_name.length(); i++) {
bool is_valid = true; bool is_valid = true;
// Unlikely, but control characters should always be blacklisted // Unlikely, but control characters should always be blacklisted
@ -909,7 +898,7 @@ std::string sanitizeDirName(const std::string &str, const std::string &optional_
} }
if (!is_valid) if (!is_valid)
safe_name[i] = '_'; safe_name[i] = L'_';
} }
return wide_to_utf8(safe_name); return wide_to_utf8(safe_name);

@ -749,7 +749,7 @@ inline irr::core::stringw utf8_to_stringw(const std::string &input)
/** /**
* Sanitize the name of a new directory. This consists of two stages: * Sanitize the name of a new directory. This consists of two stages:
* 1. Check for 'reserved filenames' that can't be used on some filesystems * 1. Check for 'reserved filenames' that can't be used on some filesystems
* and prefix them * and add a prefix to them
* 2. Remove 'unsafe' characters from the name by replacing them with '_' * 2. Remove 'unsafe' characters from the name by replacing them with '_'
*/ */
std::string sanitizeDirName(const std::string &str, const std::string &optional_prefix); std::string sanitizeDirName(const std::string &str, const std::string &optional_prefix);