filesystem_utils.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // Copyright (c) 2017-2025 The Khronos Group Inc.
  2. // Copyright (c) 2017 Valve Corporation
  3. // Copyright (c) 2017 LunarG, Inc.
  4. //
  5. // SPDX-License-Identifier: Apache-2.0 OR MIT
  6. //
  7. // Initial Authors: Mark Young <[email protected]>
  8. // Nat Brown <[email protected]>
  9. //
  10. #include "filesystem_utils.hpp"
  11. #include "platform_utils.hpp"
  12. #include <cstring>
  13. #include <string>
  14. #if defined DISABLE_STD_FILESYSTEM
  15. #define USE_EXPERIMENTAL_FS 0
  16. #define USE_FINAL_FS 0
  17. #else
  18. #include "stdfs_conditions.h"
  19. #endif
  20. #if USE_FINAL_FS == 1
  21. #include <filesystem>
  22. #define FS_PREFIX std::filesystem
  23. #elif USE_EXPERIMENTAL_FS == 1
  24. #include <experimental/filesystem>
  25. #define FS_PREFIX std::experimental::filesystem
  26. #elif defined(XR_USE_PLATFORM_WIN32)
  27. // Windows fallback includes
  28. #include <stdint.h>
  29. #include <direct.h>
  30. #else
  31. // Linux/Apple fallback includes
  32. #include <sys/stat.h>
  33. #include <unistd.h>
  34. #include <limits.h>
  35. #include <stdlib.h>
  36. #include <dirent.h>
  37. #endif
  38. #if defined(XR_USE_PLATFORM_WIN32)
  39. #define PATH_SEPARATOR ';'
  40. #define DIRECTORY_SYMBOL '\\'
  41. #define ALTERNATE_DIRECTORY_SYMBOL '/'
  42. #else
  43. #define PATH_SEPARATOR ':'
  44. #define DIRECTORY_SYMBOL '/'
  45. #endif
  46. #if (USE_FINAL_FS == 1) || (USE_EXPERIMENTAL_FS == 1)
  47. // We can use one of the C++ filesystem packages
  48. bool FileSysUtilsIsRegularFile(const std::string& path) { return FS_PREFIX::is_regular_file(path); }
  49. bool FileSysUtilsIsDirectory(const std::string& path) { return FS_PREFIX::is_directory(path); }
  50. bool FileSysUtilsPathExists(const std::string& path) { return FS_PREFIX::exists(path); }
  51. bool FileSysUtilsIsAbsolutePath(const std::string& path) {
  52. FS_PREFIX::path file_path(path);
  53. return file_path.is_absolute();
  54. }
  55. bool FileSysUtilsGetCurrentPath(std::string& path) {
  56. FS_PREFIX::path cur_path = FS_PREFIX::current_path();
  57. path = cur_path.string();
  58. return true;
  59. }
  60. bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
  61. FS_PREFIX::path path_var(file_path);
  62. parent_path = path_var.parent_path().string();
  63. return true;
  64. }
  65. bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
  66. absolute = FS_PREFIX::absolute(path).string();
  67. return true;
  68. }
  69. bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& canonical) {
  70. #if defined(XR_USE_PLATFORM_WIN32)
  71. // std::filesystem::canonical fails on UWP and must be avoided. Further, PathCchCanonicalize is not available on Windows 7 and
  72. // PathCanonicalizeW is not available on UWP. However, symbolic links are not important on Windows since the loader uses the
  73. // registry for indirection instead, and so this function can be a no-op on Windows.
  74. canonical = path;
  75. #else
  76. canonical = FS_PREFIX::canonical(path).string();
  77. #endif
  78. return true;
  79. }
  80. bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
  81. FS_PREFIX::path parent_path(parent);
  82. FS_PREFIX::path child_path(child);
  83. FS_PREFIX::path full_path = parent_path / child_path;
  84. combined = full_path.string();
  85. return true;
  86. }
  87. bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
  88. std::string::size_type start = 0;
  89. std::string::size_type location = path_list.find(PATH_SEPARATOR);
  90. while (location != std::string::npos) {
  91. paths.push_back(path_list.substr(start, location));
  92. start = location + 1;
  93. location = path_list.find(PATH_SEPARATOR, start);
  94. }
  95. paths.push_back(path_list.substr(start, location));
  96. return true;
  97. }
  98. bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
  99. for (auto& dir_iter : FS_PREFIX::directory_iterator(path)) {
  100. files.push_back(dir_iter.path().filename().string());
  101. }
  102. return true;
  103. }
  104. #elif defined(XR_OS_WINDOWS)
  105. // For pre C++17 compiler that doesn't support experimental filesystem
  106. bool FileSysUtilsIsRegularFile(const std::string& path) {
  107. const DWORD attr = GetFileAttributesW(utf8_to_wide(path).c_str());
  108. return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY);
  109. }
  110. bool FileSysUtilsIsDirectory(const std::string& path) {
  111. const DWORD attr = GetFileAttributesW(utf8_to_wide(path).c_str());
  112. return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY);
  113. }
  114. bool FileSysUtilsPathExists(const std::string& path) {
  115. return (GetFileAttributesW(utf8_to_wide(path).c_str()) != INVALID_FILE_ATTRIBUTES);
  116. }
  117. bool FileSysUtilsIsAbsolutePath(const std::string& path) {
  118. bool pathStartsWithDir = (path.size() >= 1) && ((path[0] == DIRECTORY_SYMBOL) || (path[0] == ALTERNATE_DIRECTORY_SYMBOL));
  119. bool pathStartsWithDrive =
  120. (path.size() >= 3) && (path[1] == ':' && (path[2] == DIRECTORY_SYMBOL || path[2] == ALTERNATE_DIRECTORY_SYMBOL));
  121. return pathStartsWithDir || pathStartsWithDrive;
  122. }
  123. bool FileSysUtilsGetCurrentPath(std::string& path) {
  124. wchar_t tmp_path[MAX_PATH];
  125. if (nullptr != _wgetcwd(tmp_path, MAX_PATH - 1)) {
  126. path = wide_to_utf8(tmp_path);
  127. return true;
  128. }
  129. return false;
  130. }
  131. bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
  132. std::string full_path;
  133. if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
  134. std::string::size_type lastSeparator = full_path.find_last_of(DIRECTORY_SYMBOL);
  135. parent_path = (lastSeparator == 0) ? full_path : full_path.substr(0, lastSeparator);
  136. return true;
  137. }
  138. return false;
  139. }
  140. bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
  141. wchar_t tmp_path[MAX_PATH];
  142. if (0 != GetFullPathNameW(utf8_to_wide(path).c_str(), MAX_PATH, tmp_path, NULL)) {
  143. absolute = wide_to_utf8(tmp_path);
  144. return true;
  145. }
  146. return false;
  147. }
  148. bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& absolute) {
  149. // PathCchCanonicalize is not available on Windows 7 and PathCanonicalizeW is not available on UWP. However, symbolic links are
  150. // not important on Windows since the loader uses the registry for indirection instead, and so this function can be a no-op on
  151. // Windows.
  152. absolute = path;
  153. return true;
  154. }
  155. bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
  156. std::string::size_type parent_len = parent.length();
  157. if (0 == parent_len || "." == parent || ".\\" == parent || "./" == parent) {
  158. combined = child;
  159. return true;
  160. }
  161. char last_char = parent[parent_len - 1];
  162. if ((last_char == DIRECTORY_SYMBOL) || (last_char == ALTERNATE_DIRECTORY_SYMBOL)) {
  163. parent_len--;
  164. }
  165. combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
  166. return true;
  167. }
  168. bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
  169. std::string::size_type start = 0;
  170. std::string::size_type location = path_list.find(PATH_SEPARATOR);
  171. while (location != std::string::npos) {
  172. paths.push_back(path_list.substr(start, location));
  173. start = location + 1;
  174. location = path_list.find(PATH_SEPARATOR, start);
  175. }
  176. paths.push_back(path_list.substr(start, location));
  177. return true;
  178. }
  179. bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
  180. std::string searchPath;
  181. FileSysUtilsCombinePaths(path, "*", searchPath);
  182. WIN32_FIND_DATAW file_data;
  183. HANDLE file_handle = FindFirstFileW(utf8_to_wide(searchPath).c_str(), &file_data);
  184. if (file_handle != INVALID_HANDLE_VALUE) {
  185. do {
  186. if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  187. files.push_back(wide_to_utf8(file_data.cFileName));
  188. }
  189. } while (FindNextFileW(file_handle, &file_data));
  190. return true;
  191. }
  192. return false;
  193. }
  194. #else // XR_OS_LINUX/XR_OS_APPLE fallback
  195. // simple POSIX-compatible implementation of the <filesystem> pieces used by OpenXR
  196. bool FileSysUtilsIsRegularFile(const std::string& path) {
  197. struct stat path_stat;
  198. stat(path.c_str(), &path_stat);
  199. return S_ISREG(path_stat.st_mode);
  200. }
  201. bool FileSysUtilsIsDirectory(const std::string& path) {
  202. struct stat path_stat;
  203. stat(path.c_str(), &path_stat);
  204. return S_ISDIR(path_stat.st_mode);
  205. }
  206. bool FileSysUtilsPathExists(const std::string& path) { return (access(path.c_str(), F_OK) != -1); }
  207. bool FileSysUtilsIsAbsolutePath(const std::string& path) { return (path[0] == DIRECTORY_SYMBOL); }
  208. bool FileSysUtilsGetCurrentPath(std::string& path) {
  209. char tmp_path[PATH_MAX];
  210. if (nullptr != getcwd(tmp_path, PATH_MAX - 1)) {
  211. path = tmp_path;
  212. return true;
  213. }
  214. return false;
  215. }
  216. bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
  217. std::string full_path;
  218. if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
  219. std::string::size_type lastSeparator = full_path.find_last_of(DIRECTORY_SYMBOL);
  220. parent_path = (lastSeparator == 0) ? full_path : full_path.substr(0, lastSeparator);
  221. return true;
  222. }
  223. return false;
  224. }
  225. bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
  226. // canonical path is absolute
  227. return FileSysUtilsGetCanonicalPath(path, absolute);
  228. }
  229. bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& canonical) {
  230. char buf[PATH_MAX];
  231. if (nullptr != realpath(path.c_str(), buf)) {
  232. canonical = buf;
  233. return true;
  234. }
  235. return false;
  236. }
  237. bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
  238. std::string::size_type parent_len = parent.length();
  239. if (0 == parent_len || "." == parent || "./" == parent) {
  240. combined = child;
  241. return true;
  242. }
  243. char last_char = parent[parent_len - 1];
  244. if (last_char == DIRECTORY_SYMBOL) {
  245. parent_len--;
  246. }
  247. combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
  248. return true;
  249. }
  250. bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
  251. std::string::size_type start = 0;
  252. std::string::size_type location = path_list.find(PATH_SEPARATOR);
  253. while (location != std::string::npos) {
  254. paths.push_back(path_list.substr(start, location));
  255. start = location + 1;
  256. location = path_list.find(PATH_SEPARATOR, start);
  257. }
  258. paths.push_back(path_list.substr(start, location));
  259. return true;
  260. }
  261. bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
  262. DIR* dir = opendir(path.c_str());
  263. if (dir == nullptr) {
  264. return false;
  265. }
  266. struct dirent* entry;
  267. while ((entry = readdir(dir)) != nullptr) {
  268. files.emplace_back(entry->d_name);
  269. }
  270. closedir(dir);
  271. return true;
  272. }
  273. #endif