@@ -1305,23 +1305,77 @@ bool FileModeGuard::HasErrors() const
13051305 return filepath_.empty ();
13061306}
13071307
1308+ std::string cmSystemTools::GetRealPathResolvingWindowsSubst (
1309+ std::string const & path, std::string* errorMessage)
1310+ {
1311+ #ifdef _WIN32
1312+ // uv_fs_realpath uses Windows Vista API so fallback to kwsys if not found
1313+ std::string resolved_path;
1314+ uv_fs_t req;
1315+ int err = uv_fs_realpath (nullptr , &req, path.c_str (), nullptr );
1316+ if (!err) {
1317+ resolved_path = std::string ((char *)req.ptr );
1318+ cmSystemTools::ConvertToUnixSlashes (resolved_path);
1319+ } else if (err == UV_ENOSYS) {
1320+ resolved_path = cmsys::SystemTools::GetRealPath (path, errorMessage);
1321+ } else if (errorMessage) {
1322+ cmsys::Status status =
1323+ cmsys::Status::Windows (uv_fs_get_system_error (&req));
1324+ *errorMessage = status.GetString ();
1325+ resolved_path.clear ();
1326+ } else {
1327+ resolved_path = path;
1328+ }
1329+ // Normalize to upper-case drive letter as cm::PathResolver does.
1330+ if (resolved_path.size () > 1 && resolved_path[1 ] == ' :' ) {
1331+ resolved_path[0 ] = toupper (resolved_path[0 ]);
1332+ }
1333+ return resolved_path;
1334+ #else
1335+ return cmsys::SystemTools::GetRealPath (path, errorMessage);
1336+ #endif
1337+ }
1338+
13081339std::string cmSystemTools::GetRealPath (std::string const & path,
13091340 std::string* errorMessage)
13101341{
13111342#ifdef _WIN32
1312- std::string resolved_path;
1313- using namespace cm ::PathResolver;
1314- // IWYU pragma: no_forward_declare cm::PathResolver::Policies::RealPath
1315- static Resolver<Policies::RealPath> const resolver (RealOS);
1316- cmsys::Status status = resolver.Resolve (path, resolved_path);
1317- if (!status) {
1318- if (errorMessage) {
1319- *errorMessage = status.GetString ();
1320- resolved_path.clear ();
1321- } else {
1322- resolved_path = path;
1343+ std::string resolved_path =
1344+ cmSystemTools::GetRealPathResolvingWindowsSubst (path, errorMessage);
1345+
1346+ // If the original path used a subst drive and the real path starts
1347+ // with the substitution, restore the subst drive prefix. This may
1348+ // incorrectly restore a subst drive if the underlying drive was
1349+ // encountered via an absolute symlink, but this is an acceptable
1350+ // limitation to otherwise preserve susbt drives.
1351+ if (resolved_path.size () >= 2 && resolved_path[1 ] == ' :' &&
1352+ path.size () >= 2 && path[1 ] == ' :' &&
1353+ toupper (resolved_path[0 ]) != toupper (path[0 ])) {
1354+ // FIXME: Add thread_local or mutex if we use threads.
1355+ static std::map<char , std::string> substMap;
1356+ char const drive = static_cast <char >(toupper (path[0 ]));
1357+ std::string maybe_subst = cmStrCat (drive, " :/" );
1358+ auto smi = substMap.find (drive);
1359+ if (smi == substMap.end ()) {
1360+ smi = substMap
1361+ .emplace (
1362+ drive,
1363+ cmSystemTools::GetRealPathResolvingWindowsSubst (maybe_subst))
1364+ .first ;
1365+ }
1366+ std::string const & resolved_subst = smi->second ;
1367+ std::string::size_type const ns = resolved_subst.size ();
1368+ if (ns > 0 ) {
1369+ std::string::size_type const np = resolved_path.size ();
1370+ if (ns == np && resolved_path == resolved_subst) {
1371+ resolved_path = maybe_subst;
1372+ } else if (ns > 0 && ns < np && resolved_path[ns] == ' /' &&
1373+ resolved_path.compare (0 , ns, resolved_subst) == 0 ) {
1374+ resolved_path.replace (0 , ns + 1 , maybe_subst);
1375+ }
13231376 }
13241377 }
1378+
13251379 return resolved_path;
13261380#else
13271381 return cmsys::SystemTools::GetRealPath (path, errorMessage);
0 commit comments