1
0
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:
YunQiang Su
2024-11-20 13:35:10 +08:00
committed by Brad King
parent 6be01c932e
commit 08040ced86
4 changed files with 117 additions and 10 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,