From 203f098d267237eeecb651b74971059e5088ea08 Mon Sep 17 00:00:00 2001 From: Daniel Brondani Date: Thu, 7 Sep 2023 17:44:32 +0200 Subject: [PATCH] Fix check of filename length --- CMakeLists.txt | 3 ++- src/disk_interface.cc | 23 ++++++++++++++++++++++- src/disk_interface.h | 14 +++++++++----- src/disk_interface_test.cc | 19 +++++++++++++++++++ 4 files changed, 52 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac62a490b3..d0c62f9005 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -246,7 +246,8 @@ if(BUILD_TESTING) src/util_test.cc ) if(WIN32) - target_sources(ninja_test PRIVATE src/includes_normalize_test.cc src/msvc_helper_test.cc) + target_sources(ninja_test PRIVATE src/includes_normalize_test.cc src/msvc_helper_test.cc + windows/ninja.manifest) endif() target_link_libraries(ninja_test PRIVATE libninja libninja-re2c) diff --git a/src/disk_interface.cc b/src/disk_interface.cc index 1157463432..ed064e1555 100644 --- a/src/disk_interface.cc +++ b/src/disk_interface.cc @@ -26,6 +26,7 @@ #include #include #include // _mkdir +#include #else #include #endif @@ -157,13 +158,27 @@ bool DiskInterface::MakeDirs(const string& path) { } // RealDiskInterface ----------------------------------------------------------- +RealDiskInterface::RealDiskInterface() +#ifdef _WIN32 +: use_cache_(false), long_paths_enabled_(false) { + setlocale(LC_ALL, ""); + IFDYNAMICGETCACHEDFUNCTIONTYPEDEF(L"ntdll", BOOLEAN(WINAPI*)(), + "RtlAreLongPathsEnabled", + RtlAreLongPathsEnabled) { + long_paths_enabled_ = RtlAreLongPathsEnabled(); + } +} +#else +{} +#endif TimeStamp RealDiskInterface::Stat(const string& path, string* err) const { METRIC_RECORD("node stat"); #ifdef _WIN32 // MSDN: "Naming Files, Paths, and Namespaces" // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx - if (!path.empty() && path[0] != '\\' && path.size() > MAX_PATH) { + if (!path.empty() && !AreLongPathsEnabled() && path[0] != '\\' && + path.size() > MAX_PATH) { ostringstream err_stream; err_stream << "Stat(" << path << "): Filename longer than " << MAX_PATH << " characters"; @@ -333,3 +348,9 @@ void RealDiskInterface::AllowStatCache(bool allow) { cache_.clear(); #endif } + +#ifdef _WIN32 +bool RealDiskInterface::AreLongPathsEnabled(void) const { + return long_paths_enabled_; +} +#endif diff --git a/src/disk_interface.h b/src/disk_interface.h index bc29ab78ec..74200b8f5b 100644 --- a/src/disk_interface.h +++ b/src/disk_interface.h @@ -69,11 +69,7 @@ struct DiskInterface: public FileReader { /// Implementation of DiskInterface that actually hits the disk. struct RealDiskInterface : public DiskInterface { - RealDiskInterface() -#ifdef _WIN32 - : use_cache_(false) -#endif - {} + RealDiskInterface(); virtual ~RealDiskInterface() {} virtual TimeStamp Stat(const std::string& path, std::string* err) const; virtual bool MakeDir(const std::string& path); @@ -85,11 +81,19 @@ struct RealDiskInterface : public DiskInterface { /// Whether stat information can be cached. Only has an effect on Windows. void AllowStatCache(bool allow); +#ifdef _WIN32 + /// Whether long paths are enabled. Only has an effect on Windows. + bool AreLongPathsEnabled() const; +#endif + private: #ifdef _WIN32 /// Whether stat information can be cached. bool use_cache_; + /// Whether long paths are enabled. + bool long_paths_enabled_; + typedef std::map DirCache; // TODO: Neither a map nor a hashmap seems ideal here. If the statcache // works out, come up with a better data structure. diff --git a/src/disk_interface_test.cc b/src/disk_interface_test.cc index 294df72ea7..e8d869c871 100644 --- a/src/disk_interface_test.cc +++ b/src/disk_interface_test.cc @@ -17,6 +17,7 @@ #ifdef _WIN32 #include #include +#include #endif #include "disk_interface.h" @@ -96,6 +97,24 @@ TEST_F(DiskInterfaceTest, StatExistingFile) { EXPECT_EQ("", err); } +#ifdef _WIN32 +TEST_F(DiskInterfaceTest, StatExistingFileWithLongPath) { + string err; + char currentdir[32767]; + _getcwd(currentdir, sizeof(currentdir)); + const string filename = string(currentdir) + +"\\filename_with_256_characters_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\ +xxxxxxxxxxxxxxxxxxxxx"; + const string prefixed = "\\\\?\\" + filename; + ASSERT_TRUE(Touch(prefixed.c_str())); + EXPECT_GT(disk_.Stat(disk_.AreLongPathsEnabled() ? + filename : prefixed, &err), 1); + EXPECT_EQ("", err); +} +#endif + TEST_F(DiskInterfaceTest, StatExistingDir) { string err; ASSERT_TRUE(disk_.MakeDir("subdir"));