From a3e4dfdf9859a9b955bf4728328f740a47de5851 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Fri, 22 May 2020 20:50:01 +0300 Subject: [PATCH] AK: Fix .. handling in FileSystemPath We shouldn't just drop leading ..-s for relative paths. At the same time, we should handle paths like ../foo/../../bar correctly: the first .. after the foo cancels out the foo, but the second one should get treated as a leading one and not get dropped. Note that since this path resolution is purely lexical, it's never going to be completely correct with respect to symlinks and other filesystem magic. Better don't use it when dealing with files. --- AK/FileSystemPath.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/AK/FileSystemPath.cpp b/AK/FileSystemPath.cpp index ef0e824d7b..21bb5fd3b3 100644 --- a/AK/FileSystemPath.cpp +++ b/AK/FileSystemPath.cpp @@ -48,22 +48,26 @@ void FileSystemPath::canonicalize() m_is_absolute = m_string[0] == '/'; auto parts = m_string.split_view('/'); - if (!m_is_absolute) - parts.prepend("."); - size_t approximate_canonical_length = 0; Vector canonical_parts; for (size_t i = 0; i < parts.size(); ++i) { auto& part = parts[i]; - if (m_is_absolute || i != 0) { - if (part == ".") - continue; - } - if (part == "..") { - if (!canonical_parts.is_empty()) - canonical_parts.take_last(); + if (part == ".") continue; + if (part == "..") { + if (canonical_parts.is_empty()) { + if (m_is_absolute) { + // At the root, .. does nothing. + continue; + } + } else { + if (canonical_parts.last() != "..") { + // A .. and a previous non-.. part cancel each other. + canonical_parts.take_last(); + continue; + } + } } if (!part.is_empty()) { approximate_canonical_length += part.length() + 1;