From 56eaf9b033553d7537f1a22906fcdc7e1404bc26 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 23 Aug 2019 19:55:51 +0200 Subject: [PATCH] AK: Make FileSystemPath better at handling relative paths Relative paths now canonicalize into a string starting with "./" Previously, "foo" would be canonicalized as "/foo" which was clearly not right. --- AK/FileSystemPath.cpp | 27 +++++++++++++++++++++------ AK/Tests/TestFileSystemPath.cpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/AK/FileSystemPath.cpp b/AK/FileSystemPath.cpp index 72c7d1ff0b..8c95da826d 100644 --- a/AK/FileSystemPath.cpp +++ b/AK/FileSystemPath.cpp @@ -14,13 +14,26 @@ FileSystemPath::FileSystemPath(const StringView& s) void FileSystemPath::canonicalize() { + if (m_string.is_empty()) { + m_parts.clear(); + return; + } + + bool is_absolute_path = m_string[0] == '/'; auto parts = m_string.split_view('/'); + + if (!is_absolute_path) + parts.prepend("."); + int approximate_canonical_length = 0; Vector canonical_parts; - for (auto& part : parts) { - if (part == ".") - continue; + for (int i = 0; i < parts.size(); ++i) { + auto& part = parts[i]; + if (is_absolute_path || i != 0) { + if (part == ".") + continue; + } if (part == "..") { if (!canonical_parts.is_empty()) canonical_parts.take_last(); @@ -43,9 +56,11 @@ void FileSystemPath::canonicalize() m_extension = name_parts[1]; StringBuilder builder(approximate_canonical_length); - for (auto& cpart : canonical_parts) { - builder.append('/'); - builder.append(cpart); + for (int i = 0; i < canonical_parts.size(); ++i) { + auto& canonical_part = canonical_parts[i]; + if (is_absolute_path || i != 0) + builder.append('/'); + builder.append(canonical_part); } m_parts = move(canonical_parts); m_string = builder.to_string(); diff --git a/AK/Tests/TestFileSystemPath.cpp b/AK/Tests/TestFileSystemPath.cpp index a3d29344ef..e019f53b16 100644 --- a/AK/Tests/TestFileSystemPath.cpp +++ b/AK/Tests/TestFileSystemPath.cpp @@ -26,4 +26,37 @@ TEST_CASE(dotdot_coalescing) EXPECT_EQ(FileSystemPath("/../../../../").string(), "/"); } +TEST_CASE(relative_paths) +{ + { + FileSystemPath path("simple"); + EXPECT_EQ(path.is_valid(), true); + EXPECT_EQ(path.string(), "./simple"); + EXPECT_EQ(path.parts().size(), 2); + EXPECT_EQ(path.basename(), "simple"); + } + { + FileSystemPath path("a/relative/path"); + EXPECT_EQ(path.is_valid(), true); + EXPECT_EQ(path.string(), "./a/relative/path"); + EXPECT_EQ(path.parts().size(), 4); + EXPECT_EQ(path.basename(), "path"); + } + { + FileSystemPath path("./././foo"); + EXPECT_EQ(path.is_valid(), true); + EXPECT_EQ(path.string(), "./foo"); + EXPECT_EQ(path.parts().size(), 2); + EXPECT_EQ(path.basename(), "foo"); + } + + { + FileSystemPath path("."); + EXPECT_EQ(path.is_valid(), true); + EXPECT_EQ(path.string(), "."); + EXPECT_EQ(path.parts().size(), 1); + EXPECT_EQ(path.basename(), "."); + } +} + TEST_MAIN(FileSystemPath)