mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-18 08:51:52 +08:00
cmake: Look up on-disk case of input paths on macOS
Follow up commit 1a6015e5fc
(PathResolver: Add helper to compute
normalized paths, 2024-10-30) to cover on-disk case lookup on macOS.
Fixes: #26333
This commit is contained in:
@@ -396,7 +396,7 @@ Control Impl<Policy>::ResolveComponent(Root root,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
bool exists = false;
|
||||
if (Policy::ActualCase == Options::ActualCase::Yes) {
|
||||
std::string name;
|
||||
@@ -418,7 +418,7 @@ Control Impl<Policy>::ResolveComponent(Root root,
|
||||
#endif
|
||||
|
||||
if (Policy::Existence == Options::Existence::Required
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
&& !exists
|
||||
#endif
|
||||
) {
|
||||
@@ -486,7 +486,7 @@ cmsys::Status Impl<Policy>::Resolve(std::string in, std::string& out)
|
||||
namespace Policies {
|
||||
struct NaivePath
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
static constexpr Options::ActualCase ActualCase = Options::ActualCase::No;
|
||||
#endif
|
||||
static constexpr Options::Symlinks Symlinks = Options::Symlinks::None;
|
||||
@@ -494,7 +494,7 @@ struct NaivePath
|
||||
};
|
||||
struct RealPath
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
static constexpr Options::ActualCase ActualCase = Options::ActualCase::Yes;
|
||||
#endif
|
||||
static constexpr Options::Symlinks Symlinks = Options::Symlinks::Eager;
|
||||
@@ -502,7 +502,7 @@ struct RealPath
|
||||
};
|
||||
struct LogicalPath
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
static constexpr Options::ActualCase ActualCase = Options::ActualCase::Yes;
|
||||
#endif
|
||||
static constexpr Options::Symlinks Symlinks = Options::Symlinks::Lazy;
|
||||
|
@@ -64,7 +64,9 @@ public:
|
||||
/** Get the process's working directory on a Windows drive letter.
|
||||
This is a legacy DOS concept supported by 'cmd' shells. */
|
||||
virtual std::string GetWorkingDirectoryOnDrive(char drive_letter) = 0;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
/** Read the on-disk spelling of the last component of a file path. */
|
||||
virtual cmsys::Status ReadName(std::string const& path,
|
||||
std::string& name) = 0;
|
||||
|
@@ -22,7 +22,7 @@
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
# include <unordered_map>
|
||||
#endif
|
||||
|
||||
@@ -191,6 +191,61 @@ cmsys::Status ReadNameOnDisk(std::string const& path, std::string& name)
|
||||
CloseHandle(h);
|
||||
return cmsys::Status::Success();
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
cmsys::Status ReadNameOnDiskIterateDir(std::string const& path,
|
||||
std::string& name)
|
||||
{
|
||||
// Read contents of the parent directory to find the
|
||||
// entry matching the given path.
|
||||
std::string const bn = cmSystemTools::GetFilenameName(path);
|
||||
std::string const dn = cmSystemTools::GetFilenamePath(path);
|
||||
DIR* d = opendir(dn.c_str());
|
||||
while (struct dirent* dr = readdir(d)) {
|
||||
if (strcasecmp(dr->d_name, bn.c_str()) == 0) {
|
||||
name = dr->d_name;
|
||||
closedir(d);
|
||||
return cmsys::Status::Success();
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
return cmsys::Status::POSIX(ENOENT);
|
||||
}
|
||||
|
||||
cmsys::Status ReadNameOnDiskFcntlGetPath(std::string const& path,
|
||||
std::string& name)
|
||||
{
|
||||
// macOS (and *BSD) offer a syscall to get an on-disk path to
|
||||
// a descriptor's file.
|
||||
int fd = open(path.c_str(), O_SYMLINK | O_RDONLY);
|
||||
if (fd == -1) {
|
||||
return cmsys::Status::POSIX(errno);
|
||||
}
|
||||
char out[MAXPATHLEN + 1];
|
||||
if (fcntl(fd, F_GETPATH, out) == -1) {
|
||||
int e = errno;
|
||||
close(fd);
|
||||
return cmsys::Status::POSIX(e);
|
||||
}
|
||||
close(fd);
|
||||
name = cmSystemTools::GetFilenameName(out);
|
||||
return cmsys::Status::Success();
|
||||
}
|
||||
|
||||
cmsys::Status ReadNameOnDisk(std::string const& path, std::string& name)
|
||||
{
|
||||
struct stat stat_path;
|
||||
if (lstat(path.c_str(), &stat_path) != 0) {
|
||||
return cmsys::Status::POSIX(errno);
|
||||
}
|
||||
// macOS (and *BSD) use namei(9) to cache file paths. Use it unless
|
||||
// the inode has multiple hardlinks: if it is opened through multiple
|
||||
// paths, the results may be unpredictable.
|
||||
if (S_ISDIR(stat_path.st_mode) || stat_path.st_nlink < 2) {
|
||||
return ReadNameOnDiskFcntlGetPath(path, name);
|
||||
}
|
||||
// Fall back to reading the parent directory.
|
||||
return ReadNameOnDiskIterateDir(path, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
class RealSystem : public cm::PathResolver::System
|
||||
@@ -215,7 +270,9 @@ public:
|
||||
{
|
||||
return GetDosDriveWorkingDirectory(letter);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
struct NameOnDisk
|
||||
{
|
||||
cmsys::Status Status;
|
||||
|
@@ -8,13 +8,15 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <cctype>
|
||||
#endif
|
||||
|
||||
#include <cmsys/Status.hxx>
|
||||
|
||||
#include "cmPathResolver.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <cctype>
|
||||
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
# include "cmSystemTools.h"
|
||||
#endif
|
||||
|
||||
@@ -46,7 +48,7 @@ public:
|
||||
|
||||
static std::string AdjustCase(std::string const& path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
return cmSystemTools::LowerCase(path);
|
||||
#else
|
||||
return path;
|
||||
@@ -95,7 +97,9 @@ public:
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
cmsys::Status ReadName(std::string const& path, std::string& name) override
|
||||
{
|
||||
auto i = this->Paths.find(AdjustCase(path));
|
||||
@@ -242,6 +246,47 @@ bool posixSymlink()
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
bool macosActualCase()
|
||||
{
|
||||
std::cout << "macosActualCase()\n";
|
||||
MockSystem os;
|
||||
os.SetPaths({
|
||||
{ "/", { {}, {} } },
|
||||
{ "/mixed", { "MiXeD", {} } },
|
||||
{ "/mixed/link-mixed", { "LiNk-MiXeD", "mixed" } },
|
||||
{ "/mixed/mixed", { "MiXeD", {} } },
|
||||
{ "/mixed/link-c-mixed", { "LiNk-C-MiXeD", "/mIxEd" } },
|
||||
{ "/upper", { "UPPER", {} } },
|
||||
{ "/upper/link-upper", { "LINK-UPPER", "upper" } },
|
||||
{ "/upper/upper", { "UPPER", {} } },
|
||||
{ "/upper/link-c-upper", { "LINK-C-UPPER", "/upper" } },
|
||||
});
|
||||
|
||||
{
|
||||
Resolver<Policies::LogicalPath> const r(os);
|
||||
EXPECT_RESOLVE("/mIxEd/MiSsInG", "/MiXeD/MiSsInG");
|
||||
EXPECT_RESOLVE("/mIxEd/link-MiXeD", "/MiXeD/LiNk-MiXeD");
|
||||
EXPECT_RESOLVE("/mIxEd/link-c-MiXeD", "/MiXeD/LiNk-C-MiXeD");
|
||||
EXPECT_RESOLVE("/upper/mIsSiNg", "/UPPER/mIsSiNg");
|
||||
EXPECT_RESOLVE("/upper/link-upper", "/UPPER/LINK-UPPER");
|
||||
EXPECT_RESOLVE("/upper/link-c-upper", "/UPPER/LINK-C-UPPER");
|
||||
}
|
||||
|
||||
{
|
||||
Resolver<Policies::RealPath> const r(os);
|
||||
EXPECT_ENOENT("/mIxEd/MiSsInG", "/MiXeD/MiSsInG");
|
||||
EXPECT_RESOLVE("/mIxEd/link-MiXeD", "/MiXeD/MiXeD");
|
||||
EXPECT_RESOLVE("/mIxEd/link-c-MiXeD", "/MiXeD");
|
||||
EXPECT_ENOENT("/upper/mIsSiNg", "/UPPER/mIsSiNg");
|
||||
EXPECT_RESOLVE("/upper/link-upper", "/UPPER/UPPER");
|
||||
EXPECT_RESOLVE("/upper/link-c-upper", "/UPPER");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
bool windowsRoot()
|
||||
{
|
||||
@@ -464,6 +509,9 @@ int testPathResolver(int /*unused*/, char* /*unused*/[])
|
||||
posixAbsolutePath,
|
||||
posixWorkingDirectory,
|
||||
posixSymlink,
|
||||
#ifdef __APPLE__
|
||||
macosActualCase,
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
windowsRoot,
|
||||
windowsAbsolutePath,
|
||||
|
Reference in New Issue
Block a user