From 88ad59bfb18feead399c5250b426fc3dc3512b95 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 28 Oct 2018 08:54:20 +0100 Subject: [PATCH] Add a simple FileSystemPath class that can canonicalize paths. Also a simple StringBuilder to help him out. --- AK/FileSystemPath.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++ AK/FileSystemPath.h | 24 +++++++++++++++++++++++ AK/Makefile | 4 ++-- AK/String.h | 1 + AK/StringBuilder.cpp | 20 +++++++++++++++++--- AK/test.cpp | 15 ++++++++++++++- 6 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 AK/FileSystemPath.cpp create mode 100644 AK/FileSystemPath.h diff --git a/AK/FileSystemPath.cpp b/AK/FileSystemPath.cpp new file mode 100644 index 0000000000..ab00a61c3c --- /dev/null +++ b/AK/FileSystemPath.cpp @@ -0,0 +1,44 @@ +#include "FileSystemPath.h" +#include "Vector.h" +#include "kstdio.h" +#include "StringBuilder.h" + +namespace AK { + +FileSystemPath::FileSystemPath(const String& s) + : m_string(s) +{ + m_isValid = canonicalize(); +} + +bool FileSystemPath::canonicalize(bool resolveSymbolicLinks) +{ + // FIXME: Implement "resolveSymbolicLinks" + auto parts = m_string.split('/'); + Vector canonicalParts; + + for (auto& part : parts) { + if (part == ".") + continue; + if (part == "..") { + if (!canonicalParts.isEmpty()) + canonicalParts.takeLast(); + continue; + } + canonicalParts.append(part); + } + if (canonicalParts.isEmpty()) { + m_string = "/"; + return true; + } + StringBuilder builder; + for (auto& cpart : canonicalParts) { + builder.append('/'); + builder.append(move(cpart)); + } + m_string = builder.build(); + return true; +} + +} + diff --git a/AK/FileSystemPath.h b/AK/FileSystemPath.h new file mode 100644 index 0000000000..46c9e694c5 --- /dev/null +++ b/AK/FileSystemPath.h @@ -0,0 +1,24 @@ +#pragma once + +#include "String.h" + +namespace AK { + +class FileSystemPath { +public: + FileSystemPath() { } + explicit FileSystemPath(const String&); + + bool isValid() const { return m_isValid; } + String string() const { return m_string; } + +private: + bool canonicalize(bool resolveSymbolicLinks = false); + + String m_string; + bool m_isValid { false }; +}; + +}; + +using AK::FileSystemPath; diff --git a/AK/Makefile b/AK/Makefile index db2dbde8cc..b706a03eef 100644 --- a/AK/Makefile +++ b/AK/Makefile @@ -1,11 +1,11 @@ PROGRAM = akit-test -OBJS = StringImpl.o String.o MappedFile.o TemporaryFile.o SimpleMalloc.o kmalloc.o test.o +OBJS = StringImpl.o String.o MappedFile.o TemporaryFile.o SimpleMalloc.o kmalloc.o FileSystemPath.o StringBuilder.o test.o CXXFLAGS = -std=c++17 -O0 -W -Wall -ggdb3 all: $(PROGRAM) -test.o: Vector.h String.h StringImpl.h MappedFile.h HashTable.h SinglyLinkedList.h Traits.h HashMap.h TemporaryFile.h Buffer.h +test.o: Vector.h String.h StringImpl.h MappedFile.h HashTable.h SinglyLinkedList.h Traits.h HashMap.h TemporaryFile.h Buffer.h FileSystemPath.h StringBuilder.h .cpp.o: $(CXX) $(CXXFLAGS) -o $@ -c $< diff --git a/AK/String.h b/AK/String.h index 8c9984c785..023d9f300e 100644 --- a/AK/String.h +++ b/AK/String.h @@ -61,6 +61,7 @@ public: Vector split(char separator) const; String substring(size_t start, size_t length) const; + bool isNull() const { return !m_impl; } bool isEmpty() const { return length() == 0; } unsigned length() const { return m_impl ? m_impl->length() : 0; } const char* characters() const { return m_impl ? m_impl->characters() : nullptr; } diff --git a/AK/StringBuilder.cpp b/AK/StringBuilder.cpp index 77677217da..a9662710dc 100644 --- a/AK/StringBuilder.cpp +++ b/AK/StringBuilder.cpp @@ -4,7 +4,7 @@ namespace AK { void StringBuilder::append(String&& str) { - m_strings.append(std::move(str)); + m_strings.append(move(str)); } void StringBuilder::append(char ch) @@ -14,11 +14,25 @@ void StringBuilder::append(char ch) String StringBuilder::build() { - auto strings = std::move(m_strings); + auto strings = move(m_strings); if (strings.isEmpty()) return String::empty(); - return String(); + size_t sizeNeeded = 1; + for (auto& string : strings) + sizeNeeded += string.length(); + + char* buffer; + auto impl = StringImpl::createUninitialized(sizeNeeded, buffer); + if (!impl) + return String(); + + for (auto& string : strings) { + memcpy(buffer, string.characters(), string.length()); + buffer += string.length(); + } + *buffer = '\0'; + return String(move(impl)); } } diff --git a/AK/test.cpp b/AK/test.cpp index 0b359d59bc..fa8d87e0ff 100644 --- a/AK/test.cpp +++ b/AK/test.cpp @@ -10,13 +10,26 @@ #include "Weakable.h" #include "WeakPtr.h" #include "CircularQueue.h" +#include "FileSystemPath.h" static void testWeakPtr(); -int main(int, char**) +int main(int c, char** v) { StringImpl::initializeGlobals(); + { + const char* testpath = "/proc/../proc/1/../../proc/1/vm"; + if (c == 2) + testpath = v[1]; + FileSystemPath p(testpath); + if (p.string().isNull()) + printf("canonicalized path is null\n"); + else + printf("%s\n", p.string().characters()); + return 0; + } + { struct entry { String s;