tdf#138615: canonicalize the paths with wildcards, to process long paths

Now that we discontinued support of Windows 7, PathCchCanonicalizeEx is
definitely available.

Change-Id: I38b0ff5b6810dfbd6ee6fe84693f71b8392a1808
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/178086
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
This commit is contained in:
Mike Kaganski 2024-12-08 18:25:48 +05:00
parent 04957a8d32
commit fdd0730052

View file

@ -34,6 +34,10 @@
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp> #include <boost/property_tree/ini_parser.hpp>
// For PathCchCanonicalizeEx
#include <pathcch.h>
#pragma comment(lib, "Pathcch.lib")
namespace { namespace {
void fail() void fail()
@ -249,6 +253,7 @@ int officeloader_impl(bool bAllowConsole)
std::vector<std::wstring> aEscapedArgs; std::vector<std::wstring> aEscapedArgs;
bool bHeadlessMode = false; bool bHeadlessMode = false;
const size_t nPathSize = 32 * 1024;
for (std::wstring_view arg : CommandArgs()) for (std::wstring_view arg : CommandArgs())
{ {
// Check command line arguments for "--headless" parameter. We only set the environment // Check command line arguments for "--headless" parameter. We only set the environment
@ -258,24 +263,37 @@ int officeloader_impl(bool bAllowConsole)
if (arg == L"-headless" || arg == L"--headless") if (arg == L"-headless" || arg == L"--headless")
bHeadlessMode = true; bHeadlessMode = true;
// check for wildcards in arguments - Windows does not expand automatically // check for wildcards in arguments - Windows does not expand automatically
else if (arg.find_first_of(L"*?") != std::wstring_view::npos) else if (arg.size() < nPathSize && arg.find_first_of(L"*?") != std::wstring_view::npos)
{ {
const wchar_t* path(arg.data());
// 1. PathCchCanonicalizeEx only works with backslashes, so preprocess to comply
wchar_t buf1[nPathSize], buf2[nPathSize];
arg.copy(buf1, arg.size());
buf1[arg.size()] = '\0';
std::replace(buf1, buf1 + arg.size(), '/', '\\');
// 2. Canonicalize the path: if needed, drop the .. and . segments; if long, make sure
// that path has \\?\ long path prefix present (required for FindFirstFileW)
if (SUCCEEDED(
PathCchCanonicalizeEx(buf2, std::size(buf1), buf1, PATHCCH_ALLOW_LONG_PATHS)))
path = buf2;
// 3. Expand the wildcards
WIN32_FIND_DATAW aFindData; WIN32_FIND_DATAW aFindData;
HANDLE h = FindFirstFileW(arg.data(), &aFindData); HANDLE h = FindFirstFileW(path, &aFindData);
if (h != INVALID_HANDLE_VALUE) if (h != INVALID_HANDLE_VALUE)
{ {
const int nPathSize = 32 * 1024;
wchar_t drive[3]; wchar_t drive[3];
wchar_t dir[nPathSize]; bool splitted = _wsplitpath_s(path, drive, std::size(drive), buf1, std::size(buf1),
wchar_t path[nPathSize]; nullptr, 0, nullptr, 0) == 0;
_wsplitpath_s(arg.data(), drive, std::size(drive), dir, std::size(dir), nullptr, 0, if (splitted)
nullptr, 0); {
do do
{ {
_wmakepath_s(path, std::size(path), drive, dir, aFindData.cFileName, nullptr); if (_wmakepath_s(buf2, drive, buf1, aFindData.cFileName, nullptr) == 0)
aEscapedArgs.push_back(EscapeArg(path)); aEscapedArgs.push_back(EscapeArg(buf2));
} while (FindNextFileW(h, &aFindData)); } while (FindNextFileW(h, &aFindData));
}
FindClose(h); FindClose(h);
if (splitted)
continue; continue;
} }
} }