KLexicalPath.cpp 2.7 KB

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