From: Joel Rosdahl Date: Tue, 5 Nov 2024 20:22:06 +0000 (+0100) Subject: fix: Ignore trailing slash in prefix in util::path_starts_with X-Git-Tag: v4.11~53 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4fdc633d0b52d5e51d0cdf3bd5c44ffb8776d198;p=thirdparty%2Fccache.git fix: Ignore trailing slash in prefix in util::path_starts_with Fixes #1265. --- diff --git a/src/ccache/util/path.cpp b/src/ccache/util/path.cpp index 282cca0c..93f703b9 100644 --- a/src/ccache/util/path.cpp +++ b/src/ccache/util/path.cpp @@ -128,14 +128,24 @@ path_starts_with(const fs::path& path, const fs::path& prefix) // Note: Not all paths on Windows are case insensitive, but for our purposes // (checking whether a path is below the base directory) users will expect // them to be. - fs::path p1 = util::to_lowercase(path.string()); - fs::path p2 = util::to_lowercase(prefix.string()); + fs::path p1 = util::to_lowercase(path.lexically_normal().string()); + fs::path p2 = util::to_lowercase(prefix.lexically_normal().string()); #else const fs::path& p1 = path; const fs::path& p2 = prefix; #endif - return std::mismatch(p1.begin(), p1.end(), p2.begin(), p2.end()).second - == p2.end(); + + // Skip empty part at the end that originates from a trailing slash. + auto p2_end = p2.end(); + if (!p2.empty()) { + --p2_end; + if (!p2_end->empty()) { + ++p2_end; + } + } + + return std::mismatch(p1.begin(), p1.end(), p2.begin(), p2_end).second + == p2_end; } } // namespace util diff --git a/unittest/test_util_path.cpp b/unittest/test_util_path.cpp index a3cbbaf1..83425c4c 100644 --- a/unittest/test_util_path.cpp +++ b/unittest/test_util_path.cpp @@ -103,6 +103,17 @@ TEST_CASE("util::make_relative_path") { CHECK(make_relative_path(actual_cwd, apparent_cwd, actual_cwd + "/x") == "x"); + CHECK(make_relative_path(actual_cwd, apparent_cwd, actual_cwd + "/d") + == "d"); + CHECK(make_relative_path( + actual_cwd + "/", apparent_cwd + "/", actual_cwd + "/d") + == "d"); + CHECK(make_relative_path( + actual_cwd + "/", apparent_cwd + "/", actual_cwd + "/d/") + == "d"); + CHECK(make_relative_path( + actual_cwd + "/", apparent_cwd + "/", actual_cwd + "/d/.") + == "d"); #ifdef _WIN32 CHECK(make_relative_path(actual_cwd, apparent_cwd, actual_cwd + "\\x") == "x"); @@ -131,16 +142,22 @@ TEST_CASE("util::path_starts_with") CHECK(util::path_starts_with("", "")); CHECK(!util::path_starts_with("", "/")); CHECK(util::path_starts_with("/foo/bar", "/foo")); + CHECK(util::path_starts_with("/foo/bar/", "/foo")); + CHECK(util::path_starts_with("/foo/bar", "/foo/")); CHECK(!util::path_starts_with("/batz/bar", "/foo")); CHECK(!util::path_starts_with("/foo/bar", "/foo/baz")); CHECK(!util::path_starts_with("/beh/foo", "/foo")); #ifdef _WIN32 CHECK(util::path_starts_with("C:/foo/bar", "C:\\foo")); + CHECK(util::path_starts_with("C:/foo/bar\\", "C:\\foo")); + CHECK(util::path_starts_with("C:/foo/bar", "C:\\foo\\")); CHECK(util::path_starts_with("C:/foo/bar", "C:\\\\foo")); CHECK(util::path_starts_with("C:\\foo\\bar", "C:/foo")); CHECK(util::path_starts_with("C:\\\\foo\\\\bar", "C:/foo")); CHECK(util::path_starts_with("C:/FOO/BAR", "c:\\foo")); CHECK(util::path_starts_with("c:/foo/bar", "C:\\FOO")); + CHECK(util::path_starts_with("c:/foo/bar/", "C:\\FOO")); + CHECK(util::path_starts_with("c:/foo/bar", "C:\\FOO\\")); CHECK(!util::path_starts_with("C:\\foo\\bar", "/foo/baz")); CHECK(!util::path_starts_with("C:\\foo\\bar", "C:/foo/baz")); CHECK(!util::path_starts_with("C:\\beh\\foo", "/foo"));