tdf#151117: Process non-existent long paths correctly
Regression after commit 92e835dbf0
Author Kunal Pawar <hellokunalpawar@gmail.com>
Date Fri Feb 18 19:15:04 2022 +0530
tdf#98705 Replace GetCaseCorrectPathName with GetLongPathNameW
The fix tries to keep the performance improvement, and when the path
exists, it will only call GetLongPathNameW once. Anyway, for unclear
reason, this normalization only happens on long paths.
Change-Id: I1cf9a47dfc35046ec1b5eebbbcaca09edb1c471a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140516
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
This commit is contained in:
parent
d991134f55
commit
b60dc48bb4
1 changed files with 81 additions and 20 deletions
|
@ -41,14 +41,14 @@
|
|||
|
||||
#include "path_helper.hxx"
|
||||
|
||||
#define WSTR_SYSTEM_ROOT_PATH u"\\\\.\\"
|
||||
#define WSTR_LONG_PATH_PREFIX u"\\\\?\\"
|
||||
#define WSTR_LONG_PATH_PREFIX_UNC u"\\\\?\\UNC\\"
|
||||
|
||||
// FileURL functions
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr std::u16string_view WSTR_SYSTEM_ROOT_PATH = u"\\\\.\\";
|
||||
constexpr std::u16string_view WSTR_LONG_PATH_PREFIX = u"\\\\?\\";
|
||||
constexpr std::u16string_view WSTR_LONG_PATH_PREFIX_UNC = u"\\\\?\\UNC\\";
|
||||
|
||||
// Internal functions that expect only backslashes as path separators
|
||||
|
||||
bool startsWithDriveColon(std::u16string_view s)
|
||||
|
@ -308,13 +308,13 @@ DWORD IsValidFilePath(const OUString& path, DWORD dwFlags, OUString* corrected)
|
|||
if (path.matchIgnoreAsciiCase(WSTR_LONG_PATH_PREFIX_UNC))
|
||||
{
|
||||
/* This is long path in UNC notation */
|
||||
oComponent = path.subView(SAL_N_ELEMENTS(WSTR_LONG_PATH_PREFIX_UNC) - 1);
|
||||
oComponent = path.subView(WSTR_LONG_PATH_PREFIX_UNC.size());
|
||||
dwCandidatPathType = PATHTYPE_ABSOLUTE_UNC | PATHTYPE_IS_LONGPATH;
|
||||
}
|
||||
else if (path.matchIgnoreAsciiCase(WSTR_LONG_PATH_PREFIX))
|
||||
{
|
||||
/* This is long path */
|
||||
oComponent = path.subView(SAL_N_ELEMENTS(WSTR_LONG_PATH_PREFIX) - 1);
|
||||
oComponent = path.subView(WSTR_LONG_PATH_PREFIX.size());
|
||||
|
||||
if (startsWithDriveColon(*oComponent))
|
||||
{
|
||||
|
@ -567,6 +567,71 @@ static OUString osl_encodeURL_(std::u16string_view sURL)
|
|||
return sEncodedURL.makeStringAndClear();
|
||||
}
|
||||
|
||||
// A helper that makes sure that for existing part of the path, the case is correct.
|
||||
// Unlike GetLongPathNameW that it wraps, this function does not require the path to exist.
|
||||
static OUString GetCaseCorrectPathName(std::u16string_view sysPath)
|
||||
{
|
||||
// Prepare a null-terminated string first.
|
||||
// Neither OUString, nor u16string_view are guaranteed to be null-terminated
|
||||
osl::LongPathBuffer<wchar_t> szPath(sysPath.size() + WSTR_LONG_PATH_PREFIX_UNC.size() + 1);
|
||||
wchar_t* const pPath = szPath;
|
||||
wchar_t* pEnd = pPath;
|
||||
size_t sysPathOffset = 0;
|
||||
if (sysPath.size() >= MAX_PATH && isAbsolute(sysPath)
|
||||
&& !o3tl::starts_with(sysPath, WSTR_LONG_PATH_PREFIX))
|
||||
{
|
||||
// Allow GetLongPathNameW consume long paths
|
||||
std::u16string_view prefix = WSTR_LONG_PATH_PREFIX;
|
||||
if (startsWithSlashSlash(sysPath))
|
||||
{
|
||||
sysPathOffset = 2; // skip leading "\\"
|
||||
prefix = WSTR_LONG_PATH_PREFIX_UNC;
|
||||
}
|
||||
pEnd = std::copy(prefix.begin(), prefix.end(), pEnd);
|
||||
}
|
||||
wchar_t* const pStart = pEnd;
|
||||
pEnd = std::copy(sysPath.begin() + sysPathOffset, sysPath.end(), pStart);
|
||||
*pEnd = 0;
|
||||
osl::LongPathBuffer<wchar_t> aBuf(MAX_LONG_PATH);
|
||||
while (pEnd > pStart)
|
||||
{
|
||||
std::u16string_view curPath(o3tl::toU(pPath), pEnd - pPath);
|
||||
if (curPath == u"\\\\" || curPath == WSTR_SYSTEM_ROOT_PATH
|
||||
|| curPath == WSTR_LONG_PATH_PREFIX
|
||||
|| o3tl::equalsIgnoreAsciiCase(curPath, WSTR_LONG_PATH_PREFIX_UNC))
|
||||
break; // Do not check if the special path prefix exists itself
|
||||
|
||||
DWORD nNewLen = GetLongPathNameW(pPath, aBuf, aBuf.getBufSizeInSymbols());
|
||||
if (nNewLen == 0)
|
||||
{
|
||||
// Error?
|
||||
const DWORD err = GetLastError();
|
||||
if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
|
||||
{
|
||||
// Check the base path; skip possible trailing separator
|
||||
size_t sepPos = curPath.substr(0, curPath.size() - 1).rfind(u'\\');
|
||||
if (sepPos != std::u16string_view::npos)
|
||||
{
|
||||
pEnd = pPath + sepPos;
|
||||
*pEnd = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SAL_WARN("sal.osl", "GetLongPathNameW: Windows error code "
|
||||
<< err << " processing path " << OUString(curPath));
|
||||
}
|
||||
break; // All other errors, or no separators left
|
||||
}
|
||||
assert(nNewLen < aBuf.getBufSizeInSymbols());
|
||||
// Combine the case-correct leading part with the non-existing trailing part
|
||||
return OUString::Concat(std::u16string_view(o3tl::toU(aBuf), nNewLen))
|
||||
+ sysPath.substr(pEnd - pStart + sysPathOffset);
|
||||
};
|
||||
return OUString(sysPath); // We found no existing parts - just assume it's OK
|
||||
}
|
||||
|
||||
oslFileError osl_getSystemPathFromFileURL_(const OUString& strURL, rtl_uString **pustrPath, bool bAllowRelative)
|
||||
{
|
||||
OUString sTempPath;
|
||||
|
@ -622,25 +687,21 @@ oslFileError osl_getSystemPathFromFileURL_(const OUString& strURL, rtl_uString *
|
|||
}
|
||||
else
|
||||
{
|
||||
::osl::LongPathBuffer< sal_Unicode > aBuf( MAX_LONG_PATH );
|
||||
sal_uInt32 nNewLen = GetLongPathNameW( o3tl::toW(sDecodedURL->getStr()) + nSkip,
|
||||
o3tl::toW(aBuf),
|
||||
aBuf.getBufSizeInSymbols() );
|
||||
|
||||
if ( nNewLen <= MAX_PATH - 12
|
||||
|| sDecodedURL->matchIgnoreAsciiCase(WSTR_SYSTEM_ROOT_PATH, nSkip)
|
||||
|| sDecodedURL->matchIgnoreAsciiCase(WSTR_LONG_PATH_PREFIX, nSkip) )
|
||||
sDecodedURL = GetCaseCorrectPathName(sDecodedURL->subView(nSkip));
|
||||
if (sDecodedURL->getLength() <= MAX_PATH - 12
|
||||
|| sDecodedURL->startsWith(WSTR_SYSTEM_ROOT_PATH)
|
||||
|| sDecodedURL->startsWith(WSTR_LONG_PATH_PREFIX))
|
||||
{
|
||||
sTempPath = std::u16string_view(aBuf, nNewLen);
|
||||
sTempPath = *sDecodedURL;
|
||||
}
|
||||
else if ( sDecodedURL->match("\\\\", nSkip) )
|
||||
else if (sDecodedURL->startsWith("\\\\"))
|
||||
{
|
||||
/* it should be an UNC path, use the according prefix */
|
||||
sTempPath = OUString::Concat(WSTR_LONG_PATH_PREFIX_UNC) + std::u16string_view(aBuf + 2, nNewLen - 2);
|
||||
sTempPath = OUString::Concat(WSTR_LONG_PATH_PREFIX_UNC) + sDecodedURL->subView(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
sTempPath = OUString::Concat(WSTR_LONG_PATH_PREFIX) + std::u16string_view(aBuf, nNewLen);
|
||||
sTempPath = WSTR_LONG_PATH_PREFIX + *sDecodedURL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -691,7 +752,7 @@ oslFileError osl_getFileURLFromSystemPath( rtl_uString* strPath, rtl_uString** p
|
|||
switch ( dwPathType & PATHTYPE_MASK_TYPE )
|
||||
{
|
||||
case PATHTYPE_ABSOLUTE_UNC:
|
||||
static_assert(SAL_N_ELEMENTS(WSTR_LONG_PATH_PREFIX_UNC) - 1 == 8,
|
||||
static_assert(WSTR_LONG_PATH_PREFIX_UNC.size() == 8,
|
||||
"Unexpected long path UNC prefix!");
|
||||
|
||||
/* generate the normal UNC path */
|
||||
|
@ -699,7 +760,7 @@ oslFileError osl_getFileURLFromSystemPath( rtl_uString* strPath, rtl_uString** p
|
|||
break;
|
||||
|
||||
case PATHTYPE_ABSOLUTE_LOCAL:
|
||||
static_assert(SAL_N_ELEMENTS(WSTR_LONG_PATH_PREFIX) - 1 == 4,
|
||||
static_assert(WSTR_LONG_PATH_PREFIX.size() == 4,
|
||||
"Unexpected long path prefix!");
|
||||
|
||||
/* generate the normal path */
|
||||
|
|
Loading…
Reference in a new issue