Squash consecutive path separators on Windows (#2268)

This avoids ERROR_INVALID_NAME ("The filename, directory name, or volume
label syntax is incorrect") errors since such normalization doesn't
happen automatically for "\\?\"-prefixed paths.

Fixes: #1791
This commit is contained in:
Mike Gelfand 2021-12-05 13:32:39 +00:00 committed by GitHub
parent c656bee061
commit ff7564dc23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 22 additions and 4 deletions

View File

@ -150,7 +150,7 @@ static bool is_valid_path(std::string_view path)
return path.find_first_of("<>:\"|?*"sv) == path.npos;
}
static wchar_t* path_to_native_path_ex(char const* path, int extra_chars_after, int* real_result_size)
static wchar_t* path_to_native_path_ex(char const* path, int extra_chars_after, int* setme_real_result_size)
{
if (path == nullptr)
{
@ -170,13 +170,16 @@ static wchar_t* path_to_native_path_ex(char const* path, int extra_chars_after,
/* TODO (?): TR_ASSERT(!is_relative); */
wchar_t* const wide_path = tr_win32_utf8_to_native_ex(path, -1, extra_chars_before, extra_chars_after, real_result_size);
int real_result_size = 0;
wchar_t* const wide_path = tr_win32_utf8_to_native_ex(path, -1, extra_chars_before, extra_chars_after, &real_result_size);
if (wide_path == nullptr)
{
return nullptr;
}
real_result_size += extra_chars_before;
/* Relative paths cannot be used with "\\?\" prefixes. This also means that relative paths are
limited to ~260 chars... but we should rarely work with relative paths in the first place */
if (!is_relative)
@ -201,9 +204,24 @@ static wchar_t* path_to_native_path_ex(char const* path, int extra_chars_after,
*p++ = L'\\';
}
if (real_result_size != nullptr)
/* Squash multiple consecutive path separators into one to avoid ERROR_INVALID_NAME */
wchar_t* first_conseq_sep = wide_path + extra_chars_before;
while ((first_conseq_sep = std::wcsstr(first_conseq_sep, L"\\\\")) != nullptr)
{
*real_result_size += extra_chars_before;
wchar_t const* last_conseq_sep = first_conseq_sep + 1;
while (*(last_conseq_sep + 1) == L'\\')
{
++last_conseq_sep;
}
std::copy_n(last_conseq_sep, real_result_size - (last_conseq_sep - wide_path) + 1, first_conseq_sep);
real_result_size -= last_conseq_sep - first_conseq_sep;
}
if (setme_real_result_size != nullptr)
{
*setme_real_result_size = real_result_size;
}
return wide_path;