mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-14 19:08:07 +08:00
cmSystemTools: Fix GetRealPath implementation on Windows
In commit823e1df54c
(cmSystemTools: Implement GetRealPath on Windows, 2024-11-04, v4.0.0-rc1~521^2~1) we implemented the POSIX behavior that resolves symlinks followed by '..' components. However, Windows just removes them lexically. Also, we were not handling all junction types. Instead, use `GetFinalPathNameByHandleW` via `uv_fs_realpath`. Note that we previously attempted this in commit640709e7db
(cmSystemTools: Implement GetRealPath on Windows, 2017-10-02, v3.11.0-rc1~445^2~1) but reverted it in commit83630d4918
(cmSystemTools: Revert GetRealPath implementation on Windows, 2018-05-29, v3.11.3~3^2) due to resolving `subst` drives. This time, add code to re-`subst`itute the drive in the resolved path. Fixes: #26750 Issue: #17206
This commit is contained in:
@@ -1340,19 +1340,42 @@ std::string cmSystemTools::GetRealPath(std::string const& path,
|
||||
std::string* errorMessage)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::string resolved_path;
|
||||
using namespace cm::PathResolver;
|
||||
// IWYU pragma: no_forward_declare cm::PathResolver::Policies::RealPath
|
||||
static Resolver<Policies::RealPath> const resolver(RealOS);
|
||||
cmsys::Status status = resolver.Resolve(path, resolved_path);
|
||||
if (!status) {
|
||||
if (errorMessage) {
|
||||
*errorMessage = status.GetString();
|
||||
resolved_path.clear();
|
||||
} else {
|
||||
resolved_path = path;
|
||||
std::string resolved_path =
|
||||
cmSystemTools::GetRealPathResolvingWindowsSubst(path, errorMessage);
|
||||
|
||||
// If the original path used a subst drive and the real path starts
|
||||
// with the substitution, restore the subst drive prefix. This may
|
||||
// incorrectly restore a subst drive if the underlying drive was
|
||||
// encountered via an absolute symlink, but this is an acceptable
|
||||
// limitation to otherwise preserve susbt drives.
|
||||
if (resolved_path.size() >= 2 && resolved_path[1] == ':' &&
|
||||
path.size() >= 2 && path[1] == ':' &&
|
||||
toupper(resolved_path[0]) != toupper(path[0])) {
|
||||
// FIXME: Add thread_local or mutex if we use threads.
|
||||
static std::map<char, std::string> substMap;
|
||||
char const drive = static_cast<char>(toupper(path[0]));
|
||||
std::string maybe_subst = cmStrCat(drive, ":/");
|
||||
auto smi = substMap.find(drive);
|
||||
if (smi == substMap.end()) {
|
||||
smi = substMap
|
||||
.emplace(
|
||||
drive,
|
||||
cmSystemTools::GetRealPathResolvingWindowsSubst(maybe_subst))
|
||||
.first;
|
||||
}
|
||||
std::string const& resolved_subst = smi->second;
|
||||
std::string::size_type const ns = resolved_subst.size();
|
||||
if (ns > 0) {
|
||||
std::string::size_type const np = resolved_path.size();
|
||||
if (ns == np && resolved_path == resolved_subst) {
|
||||
resolved_path = maybe_subst;
|
||||
} else if (ns > 0 && ns < np && resolved_path[ns] == '/' &&
|
||||
resolved_path.compare(0, ns, resolved_subst) == 0) {
|
||||
resolved_path.replace(0, ns + 1, maybe_subst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resolved_path;
|
||||
#else
|
||||
return cmsys::SystemTools::GetRealPath(path, errorMessage);
|
||||
|
Reference in New Issue
Block a user