StandardPaths.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2023, Linus Groh <linusg@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/ByteString.h>
  8. #include <AK/LexicalPath.h>
  9. #include <AK/Platform.h>
  10. #include <AK/String.h>
  11. #include <AK/StringBuilder.h>
  12. #include <AK/StringUtils.h>
  13. #include <LibCore/Environment.h>
  14. #include <LibCore/SessionManagement.h>
  15. #include <LibCore/StandardPaths.h>
  16. #include <LibCore/System.h>
  17. #include <pwd.h>
  18. #include <stdlib.h>
  19. #include <unistd.h>
  20. #if defined(AK_OS_HAIKU)
  21. # include <FindDirectory.h>
  22. #endif
  23. namespace Core {
  24. ByteString StandardPaths::home_directory()
  25. {
  26. if (auto* home_env = getenv("HOME"))
  27. return LexicalPath::canonicalized_path(home_env);
  28. auto* pwd = getpwuid(getuid());
  29. ByteString path = pwd ? pwd->pw_dir : "/";
  30. endpwent();
  31. return LexicalPath::canonicalized_path(path);
  32. }
  33. ByteString StandardPaths::desktop_directory()
  34. {
  35. if (auto* desktop_directory = getenv("XDG_DESKTOP_DIR"))
  36. return LexicalPath::canonicalized_path(desktop_directory);
  37. StringBuilder builder;
  38. builder.append(home_directory());
  39. builder.append("/Desktop"sv);
  40. return LexicalPath::canonicalized_path(builder.to_byte_string());
  41. }
  42. ByteString StandardPaths::documents_directory()
  43. {
  44. if (auto* documents_directory = getenv("XDG_DOCUMENTS_DIR"))
  45. return LexicalPath::canonicalized_path(documents_directory);
  46. StringBuilder builder;
  47. builder.append(home_directory());
  48. builder.append("/Documents"sv);
  49. return LexicalPath::canonicalized_path(builder.to_byte_string());
  50. }
  51. ByteString StandardPaths::downloads_directory()
  52. {
  53. if (auto* downloads_directory = getenv("XDG_DOWNLOAD_DIR"))
  54. return LexicalPath::canonicalized_path(downloads_directory);
  55. StringBuilder builder;
  56. builder.append(home_directory());
  57. builder.append("/Downloads"sv);
  58. return LexicalPath::canonicalized_path(builder.to_byte_string());
  59. }
  60. ByteString StandardPaths::music_directory()
  61. {
  62. if (auto* music_directory = getenv("XDG_MUSIC_DIR"))
  63. return LexicalPath::canonicalized_path(music_directory);
  64. StringBuilder builder;
  65. builder.append(home_directory());
  66. builder.append("/Music"sv);
  67. return LexicalPath::canonicalized_path(builder.to_byte_string());
  68. }
  69. ByteString StandardPaths::pictures_directory()
  70. {
  71. if (auto* pictures_directory = getenv("XDG_PICTURES_DIR"))
  72. return LexicalPath::canonicalized_path(pictures_directory);
  73. StringBuilder builder;
  74. builder.append(home_directory());
  75. builder.append("/Pictures"sv);
  76. return LexicalPath::canonicalized_path(builder.to_byte_string());
  77. }
  78. ByteString StandardPaths::videos_directory()
  79. {
  80. if (auto* videos_directory = getenv("XDG_VIDEOS_DIR"))
  81. return LexicalPath::canonicalized_path(videos_directory);
  82. StringBuilder builder;
  83. builder.append(home_directory());
  84. #if defined(AK_OS_MACOS)
  85. builder.append("/Movies"sv);
  86. #else
  87. builder.append("/Videos"sv);
  88. #endif
  89. return LexicalPath::canonicalized_path(builder.to_byte_string());
  90. }
  91. ByteString StandardPaths::config_directory()
  92. {
  93. if (auto* config_directory = getenv("XDG_CONFIG_HOME"))
  94. return LexicalPath::canonicalized_path(config_directory);
  95. StringBuilder builder;
  96. builder.append(home_directory());
  97. #if defined(AK_OS_MACOS)
  98. builder.append("/Library/Preferences"sv);
  99. #elif defined(AK_OS_HAIKU)
  100. builder.append("/config/settings"sv);
  101. #else
  102. builder.append("/.config"sv);
  103. #endif
  104. return LexicalPath::canonicalized_path(builder.to_byte_string());
  105. }
  106. ByteString StandardPaths::data_directory()
  107. {
  108. if (auto* data_directory = getenv("XDG_DATA_HOME"))
  109. return LexicalPath::canonicalized_path(data_directory);
  110. StringBuilder builder;
  111. builder.append(home_directory());
  112. #if defined(AK_OS_SERENITY)
  113. builder.append("/.data"sv);
  114. #elif defined(AK_OS_MACOS)
  115. builder.append("/Library/Application Support"sv);
  116. #elif defined(AK_OS_HAIKU)
  117. builder.append("/config/non-packaged/data"sv);
  118. #else
  119. builder.append("/.local/share"sv);
  120. #endif
  121. return LexicalPath::canonicalized_path(builder.to_byte_string());
  122. }
  123. ErrorOr<ByteString> StandardPaths::runtime_directory()
  124. {
  125. if (auto* data_directory = getenv("XDG_RUNTIME_DIR"))
  126. return LexicalPath::canonicalized_path(data_directory);
  127. StringBuilder builder;
  128. #if defined(AK_OS_SERENITY)
  129. auto sid = TRY(Core::SessionManagement::root_session_id());
  130. builder.appendff("/tmp/session/{}", sid);
  131. #elif defined(AK_OS_MACOS)
  132. builder.append(home_directory());
  133. builder.append("/Library/Application Support"sv);
  134. #elif defined(AK_OS_HAIKU)
  135. builder.append("/boot/system/var/shared_memory"sv);
  136. #elif defined(AK_OS_LINUX)
  137. auto uid = getuid();
  138. builder.appendff("/run/user/{}", uid);
  139. #else
  140. // Just create a directory in /tmp that's owned by us with 0700
  141. auto uid = getuid();
  142. builder.appendff("/tmp/runtime_{}", uid);
  143. auto error_or_stat = System::stat(builder.string_view());
  144. if (error_or_stat.is_error()) {
  145. MUST(System::mkdir(builder.string_view(), 0700));
  146. } else {
  147. auto stat = error_or_stat.release_value();
  148. VERIFY(S_ISDIR(stat.st_mode));
  149. if ((stat.st_mode & 0777) != 0700)
  150. warnln("{} has unexpected mode flags {}", builder.string_view(), stat.st_mode);
  151. }
  152. #endif
  153. return LexicalPath::canonicalized_path(builder.to_byte_string());
  154. }
  155. ByteString StandardPaths::tempfile_directory()
  156. {
  157. return "/tmp";
  158. }
  159. ErrorOr<Vector<String>> StandardPaths::font_directories()
  160. {
  161. #if defined(AK_OS_HAIKU)
  162. Vector<String> paths_vector;
  163. char** paths;
  164. size_t paths_count;
  165. if (find_paths(B_FIND_PATH_FONTS_DIRECTORY, NULL, &paths, &paths_count) == B_OK) {
  166. for (size_t i = 0; i < paths_count; ++i) {
  167. StringBuilder builder;
  168. builder.append(paths[i], strlen(paths[i]));
  169. paths_vector.append(TRY(builder.to_string()));
  170. }
  171. }
  172. return paths_vector;
  173. #else
  174. auto paths = Vector { {
  175. # if defined(AK_OS_SERENITY)
  176. "/res/fonts"_string,
  177. # elif defined(AK_OS_MACOS)
  178. "/System/Library/Fonts"_string,
  179. "/Library/Fonts"_string,
  180. TRY(String::formatted("{}/Library/Fonts"sv, home_directory())),
  181. # elif defined(AK_OS_ANDROID)
  182. // FIXME: We should be using the ASystemFontIterator NDK API here.
  183. // There is no guarantee that this will continue to exist on future versions of Android.
  184. "/system/fonts"_string,
  185. # else
  186. TRY(String::formatted("{}/fonts"sv, data_directory())),
  187. TRY(String::formatted("{}/X11/fonts"sv, data_directory())),
  188. # endif
  189. } };
  190. # if !(defined(AK_OS_SERENITY) || defined(AK_OS_MACOS))
  191. auto data_directories = Core::Environment::get("XDG_DATA_DIRS"sv).value_or("/usr/local/share:/usr/share"sv);
  192. TRY(data_directories.for_each_split_view(':', SplitBehavior::Nothing, [&paths](auto data_directory) -> ErrorOr<void> {
  193. paths.append(TRY(String::formatted("{}/fonts"sv, data_directory)));
  194. paths.append(TRY(String::formatted("{}/X11/fonts"sv, data_directory)));
  195. return {};
  196. }));
  197. # endif
  198. return paths;
  199. #endif
  200. }
  201. }