Serenity Operating System
at master 89 lines 2.6 kB view raw
1/* 2 * Copyright (c) 2021, Max Wipfli <max.wipfli@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Vector.h> 8#include <Kernel/KLexicalPath.h> 9 10namespace Kernel::KLexicalPath { 11 12static StringView const s_single_dot = "."sv; 13 14bool is_absolute(StringView path) 15{ 16 return !path.is_empty() && path[0] == '/'; 17} 18 19bool is_canonical(StringView path) 20{ 21 // FIXME: This can probably be done more efficiently. 22 if (path.is_empty()) 23 return false; 24 if (path.ends_with('/') && path.length() != 1) 25 return false; 26 if (path.starts_with("./"sv) || path.contains("/./"sv) || path.ends_with("/."sv)) 27 return false; 28 if (path.starts_with("../"sv) || path.contains("/../"sv) || path.ends_with("/.."sv)) 29 return false; 30 if (path.contains("//"sv)) 31 return false; 32 return true; 33} 34 35StringView basename(StringView a_path) 36{ 37 if (a_path == "/"sv) 38 return a_path; 39 if (a_path.is_empty()) 40 return s_single_dot; 41 auto path = a_path.trim("/"sv, TrimMode::Right); 42 // NOTE: If it's empty now, it means the path was just a series of slashes. 43 if (path.is_empty()) 44 return a_path.substring_view(0, 1); 45 auto slash_index = path.find_last('/'); 46 if (!slash_index.has_value()) 47 return path; 48 auto basename = path.substring_view(*slash_index + 1); 49 return basename; 50} 51 52StringView dirname(StringView path) 53{ 54 VERIFY(is_canonical(path)); 55 auto slash_index = path.find_last('/'); 56 VERIFY(slash_index.has_value()); 57 return path.substring_view(0, *slash_index); 58} 59 60Vector<StringView> parts(StringView path) 61{ 62 VERIFY(is_canonical(path)); 63 return path.split_view('/'); 64} 65 66ErrorOr<NonnullOwnPtr<KString>> try_join(StringView first, StringView second) 67{ 68 VERIFY(is_canonical(first)); 69 VERIFY(is_canonical(second)); 70 VERIFY(!is_absolute(second)); 71 72 if (first == "/"sv) { 73 char* buffer; 74 auto string = TRY(KString::try_create_uninitialized(1 + second.length(), buffer)); 75 buffer[0] = '/'; 76 __builtin_memcpy(buffer + 1, second.characters_without_null_termination(), second.length()); 77 buffer[string->length()] = 0; 78 return string; 79 } 80 char* buffer; 81 auto string = TRY(KString::try_create_uninitialized(first.length() + 1 + second.length(), buffer)); 82 __builtin_memcpy(buffer, first.characters_without_null_termination(), first.length()); 83 buffer[first.length()] = '/'; 84 __builtin_memcpy(buffer + first.length() + 1, second.characters_without_null_termination(), second.length()); 85 buffer[string->length()] = 0; 86 return string; 87} 88 89}