fs.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <filesystem>
  5. #include <memory>
  6. #include "common/fs/fs_types.h"
  7. #include "common/fs/fs_util.h"
  8. namespace Common::FS {
  9. class IOFile;
  10. // File Operations
  11. /**
  12. * Creates a new file at path with the specified size.
  13. *
  14. * Failures occur when:
  15. * - Input path is not valid
  16. * - The input path's parent directory does not exist
  17. * - Filesystem object at path exists
  18. * - Filesystem at path is read only
  19. *
  20. * @param path Filesystem path
  21. * @param size File size
  22. *
  23. * @returns True if the file creation succeeds, false otherwise.
  24. */
  25. [[nodiscard]] bool NewFile(const std::filesystem::path& path, u64 size = 0);
  26. #ifdef _WIN32
  27. template <typename Path>
  28. [[nodiscard]] bool NewFile(const Path& path, u64 size = 0) {
  29. if constexpr (IsChar<typename Path::value_type>) {
  30. return NewFile(ToU8String(path), size);
  31. } else {
  32. return NewFile(std::filesystem::path{path}, size);
  33. }
  34. }
  35. #endif
  36. /**
  37. * Removes a file at path.
  38. *
  39. * Failures occur when:
  40. * - Input path is not valid
  41. * - Filesystem object at path is not a regular file
  42. * - Filesystem at path is read only
  43. *
  44. * @param path Filesystem path
  45. *
  46. * @returns True if file removal succeeds or file does not exist, false otherwise.
  47. */
  48. bool RemoveFile(const std::filesystem::path& path);
  49. #ifdef _WIN32
  50. template <typename Path>
  51. bool RemoveFile(const Path& path) {
  52. if constexpr (IsChar<typename Path::value_type>) {
  53. return RemoveFile(ToU8String(path));
  54. } else {
  55. return RemoveFile(std::filesystem::path{path});
  56. }
  57. }
  58. #endif
  59. /**
  60. * Renames a file from old_path to new_path.
  61. *
  62. * Failures occur when:
  63. * - One or both input path(s) is not valid
  64. * - Filesystem object at old_path does not exist
  65. * - Filesystem object at old_path is not a regular file
  66. * - Filesystem object at new_path exists
  67. * - Filesystem at either path is read only
  68. *
  69. * @param old_path Old filesystem path
  70. * @param new_path New filesystem path
  71. *
  72. * @returns True if file rename succeeds, false otherwise.
  73. */
  74. [[nodiscard]] bool RenameFile(const std::filesystem::path& old_path,
  75. const std::filesystem::path& new_path);
  76. #ifdef _WIN32
  77. template <typename Path1, typename Path2>
  78. [[nodiscard]] bool RenameFile(const Path1& old_path, const Path2& new_path) {
  79. using ValueType1 = typename Path1::value_type;
  80. using ValueType2 = typename Path2::value_type;
  81. if constexpr (IsChar<ValueType1> && IsChar<ValueType2>) {
  82. return RenameFile(ToU8String(old_path), ToU8String(new_path));
  83. } else if constexpr (IsChar<ValueType1> && !IsChar<ValueType2>) {
  84. return RenameFile(ToU8String(old_path), new_path);
  85. } else if constexpr (!IsChar<ValueType1> && IsChar<ValueType2>) {
  86. return RenameFile(old_path, ToU8String(new_path));
  87. } else {
  88. return RenameFile(std::filesystem::path{old_path}, std::filesystem::path{new_path});
  89. }
  90. }
  91. #endif
  92. /**
  93. * Opens a file at path with the specified file access mode.
  94. * This function behaves differently depending on the FileAccessMode.
  95. * These behaviors are documented in each enum value of FileAccessMode.
  96. *
  97. * Failures occur when:
  98. * - Input path is not valid
  99. * - Filesystem object at path exists and is not a regular file
  100. * - The file is not open
  101. *
  102. * @param path Filesystem path
  103. * @param mode File access mode
  104. * @param type File type, default is BinaryFile. Use TextFile to open the file as a text file
  105. * @param flag (Windows only) File-share access flag, default is ShareReadOnly
  106. *
  107. * @returns A shared pointer to the opened file. Returns nullptr on failure.
  108. */
  109. [[nodiscard]] std::shared_ptr<IOFile> FileOpen(const std::filesystem::path& path,
  110. FileAccessMode mode,
  111. FileType type = FileType::BinaryFile,
  112. FileShareFlag flag = FileShareFlag::ShareReadOnly);
  113. #ifdef _WIN32
  114. template <typename Path>
  115. [[nodiscard]] std::shared_ptr<IOFile> FileOpen(const Path& path, FileAccessMode mode,
  116. FileType type = FileType::BinaryFile,
  117. FileShareFlag flag = FileShareFlag::ShareReadOnly) {
  118. if constexpr (IsChar<typename Path::value_type>) {
  119. return FileOpen(ToU8String(path), mode, type, flag);
  120. } else {
  121. return FileOpen(std::filesystem::path{path}, mode, type, flag);
  122. }
  123. }
  124. #endif
  125. // Directory Operations
  126. /**
  127. * Creates a directory at path.
  128. * Note that this function will *always* assume that the input path is a directory. For example,
  129. * if the input path is /path/to/directory/file.txt, it will create a directory called "file.txt".
  130. * If you intend to create the parent directory of a file, use CreateParentDir instead.
  131. *
  132. * Failures occur when:
  133. * - Input path is not valid
  134. * - The input path's parent directory does not exist
  135. * - Filesystem at path is read only
  136. *
  137. * @param path Filesystem path
  138. *
  139. * @returns True if directory creation succeeds or directory already exists, false otherwise.
  140. */
  141. [[nodiscard]] bool CreateDir(const std::filesystem::path& path);
  142. #ifdef _WIN32
  143. template <typename Path>
  144. [[nodiscard]] bool CreateDir(const Path& path) {
  145. if constexpr (IsChar<typename Path::value_type>) {
  146. return CreateDir(ToU8String(path));
  147. } else {
  148. return CreateDir(std::filesystem::path{path});
  149. }
  150. }
  151. #endif
  152. /**
  153. * Recursively creates a directory at path.
  154. * Note that this function will *always* assume that the input path is a directory. For example,
  155. * if the input path is /path/to/directory/file.txt, it will create a directory called "file.txt".
  156. * If you intend to create the parent directory of a file, use CreateParentDirs instead.
  157. * Unlike CreateDir, this creates all of input path's parent directories if they do not exist.
  158. *
  159. * Failures occur when:
  160. * - Input path is not valid
  161. * - Filesystem at path is read only
  162. *
  163. * @param path Filesystem path
  164. *
  165. * @returns True if directory creation succeeds or directory already exists, false otherwise.
  166. */
  167. [[nodiscard]] bool CreateDirs(const std::filesystem::path& path);
  168. #ifdef _WIN32
  169. template <typename Path>
  170. [[nodiscard]] bool CreateDirs(const Path& path) {
  171. if constexpr (IsChar<typename Path::value_type>) {
  172. return CreateDirs(ToU8String(path));
  173. } else {
  174. return CreateDirs(std::filesystem::path{path});
  175. }
  176. }
  177. #endif
  178. /**
  179. * Creates the parent directory of a given path.
  180. * This function calls CreateDir(path.parent_path()), see CreateDir for more details.
  181. *
  182. * @param path Filesystem path
  183. *
  184. * @returns True if directory creation succeeds or directory already exists, false otherwise.
  185. */
  186. [[nodiscard]] bool CreateParentDir(const std::filesystem::path& path);
  187. #ifdef _WIN32
  188. template <typename Path>
  189. [[nodiscard]] bool CreateParentDir(const Path& path) {
  190. if constexpr (IsChar<typename Path::value_type>) {
  191. return CreateParentDir(ToU8String(path));
  192. } else {
  193. return CreateParentDir(std::filesystem::path{path});
  194. }
  195. }
  196. #endif
  197. /**
  198. * Recursively creates the parent directory of a given path.
  199. * This function calls CreateDirs(path.parent_path()), see CreateDirs for more details.
  200. *
  201. * @param path Filesystem path
  202. *
  203. * @returns True if directory creation succeeds or directory already exists, false otherwise.
  204. */
  205. [[nodiscard]] bool CreateParentDirs(const std::filesystem::path& path);
  206. #ifdef _WIN32
  207. template <typename Path>
  208. [[nodiscard]] bool CreateParentDirs(const Path& path) {
  209. if constexpr (IsChar<typename Path::value_type>) {
  210. return CreateParentDirs(ToU8String(path));
  211. } else {
  212. return CreateParentDirs(std::filesystem::path{path});
  213. }
  214. }
  215. #endif
  216. /**
  217. * Removes a directory at path.
  218. *
  219. * Failures occur when:
  220. * - Input path is not valid
  221. * - Filesystem object at path is not a directory
  222. * - The given directory is not empty
  223. * - Filesystem at path is read only
  224. *
  225. * @param path Filesystem path
  226. *
  227. * @returns True if directory removal succeeds or directory does not exist, false otherwise.
  228. */
  229. bool RemoveDir(const std::filesystem::path& path);
  230. #ifdef _WIN32
  231. template <typename Path>
  232. bool RemoveDir(const Path& path) {
  233. if constexpr (IsChar<typename Path::value_type>) {
  234. return RemoveDir(ToU8String(path));
  235. } else {
  236. return RemoveDir(std::filesystem::path{path});
  237. }
  238. }
  239. #endif
  240. /**
  241. * Removes all the contents within the given directory and removes the directory itself.
  242. *
  243. * Failures occur when:
  244. * - Input path is not valid
  245. * - Filesystem object at path is not a directory
  246. * - Filesystem at path is read only
  247. *
  248. * @param path Filesystem path
  249. *
  250. * @returns True if the directory and all of its contents are removed successfully, false otherwise.
  251. */
  252. bool RemoveDirRecursively(const std::filesystem::path& path);
  253. #ifdef _WIN32
  254. template <typename Path>
  255. bool RemoveDirRecursively(const Path& path) {
  256. if constexpr (IsChar<typename Path::value_type>) {
  257. return RemoveDirRecursively(ToU8String(path));
  258. } else {
  259. return RemoveDirRecursively(std::filesystem::path{path});
  260. }
  261. }
  262. #endif
  263. /**
  264. * Removes all the contents within the given directory without removing the directory itself.
  265. *
  266. * Failures occur when:
  267. * - Input path is not valid
  268. * - Filesystem object at path is not a directory
  269. * - Filesystem at path is read only
  270. *
  271. * @param path Filesystem path
  272. *
  273. * @returns True if all of the directory's contents are removed successfully, false otherwise.
  274. */
  275. bool RemoveDirContentsRecursively(const std::filesystem::path& path);
  276. #ifdef _WIN32
  277. template <typename Path>
  278. bool RemoveDirContentsRecursively(const Path& path) {
  279. if constexpr (IsChar<typename Path::value_type>) {
  280. return RemoveDirContentsRecursively(ToU8String(path));
  281. } else {
  282. return RemoveDirContentsRecursively(std::filesystem::path{path});
  283. }
  284. }
  285. #endif
  286. /**
  287. * Renames a directory from old_path to new_path.
  288. *
  289. * Failures occur when:
  290. * - One or both input path(s) is not valid
  291. * - Filesystem object at old_path does not exist
  292. * - Filesystem object at old_path is not a directory
  293. * - Filesystem object at new_path exists
  294. * - Filesystem at either path is read only
  295. *
  296. * @param old_path Old filesystem path
  297. * @param new_path New filesystem path
  298. *
  299. * @returns True if directory rename succeeds, false otherwise.
  300. */
  301. [[nodiscard]] bool RenameDir(const std::filesystem::path& old_path,
  302. const std::filesystem::path& new_path);
  303. #ifdef _WIN32
  304. template <typename Path1, typename Path2>
  305. [[nodiscard]] bool RenameDir(const Path1& old_path, const Path2& new_path) {
  306. using ValueType1 = typename Path1::value_type;
  307. using ValueType2 = typename Path2::value_type;
  308. if constexpr (IsChar<ValueType1> && IsChar<ValueType2>) {
  309. return RenameDir(ToU8String(old_path), ToU8String(new_path));
  310. } else if constexpr (IsChar<ValueType1> && !IsChar<ValueType2>) {
  311. return RenameDir(ToU8String(old_path), new_path);
  312. } else if constexpr (!IsChar<ValueType1> && IsChar<ValueType2>) {
  313. return RenameDir(old_path, ToU8String(new_path));
  314. } else {
  315. return RenameDir(std::filesystem::path{old_path}, std::filesystem::path{new_path});
  316. }
  317. }
  318. #endif
  319. /**
  320. * Iterates over the directory entries of a given directory.
  321. * This does not iterate over the sub-directories of the given directory.
  322. * The DirEntryCallable callback is called for each visited directory entry.
  323. * A filter can be set to control which directory entries are visited based on their type.
  324. * By default, both files and directories are visited.
  325. * If the callback returns false or there is an error, the iteration is immediately halted.
  326. *
  327. * Failures occur when:
  328. * - Input path is not valid
  329. * - Filesystem object at path is not a directory
  330. *
  331. * @param path Filesystem path
  332. * @param callback Callback to be called for each visited directory entry
  333. * @param filter Directory entry type filter
  334. */
  335. void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable& callback,
  336. DirEntryFilter filter = DirEntryFilter::All);
  337. #ifdef _WIN32
  338. template <typename Path>
  339. void IterateDirEntries(const Path& path, const DirEntryCallable& callback,
  340. DirEntryFilter filter = DirEntryFilter::All) {
  341. if constexpr (IsChar<typename Path::value_type>) {
  342. IterateDirEntries(ToU8String(path), callback, filter);
  343. } else {
  344. IterateDirEntries(std::filesystem::path{path}, callback, filter);
  345. }
  346. }
  347. #endif
  348. /**
  349. * Iterates over the directory entries of a given directory and its sub-directories.
  350. * The DirEntryCallable callback is called for each visited directory entry.
  351. * A filter can be set to control which directory entries are visited based on their type.
  352. * By default, both files and directories are visited.
  353. * If the callback returns false or there is an error, the iteration is immediately halted.
  354. *
  355. * Failures occur when:
  356. * - Input path is not valid
  357. * - Filesystem object at path does not exist
  358. * - Filesystem object at path is not a directory
  359. *
  360. * @param path Filesystem path
  361. * @param callback Callback to be called for each visited directory entry
  362. * @param filter Directory entry type filter
  363. */
  364. void IterateDirEntriesRecursively(const std::filesystem::path& path,
  365. const DirEntryCallable& callback,
  366. DirEntryFilter filter = DirEntryFilter::All);
  367. #ifdef _WIN32
  368. template <typename Path>
  369. void IterateDirEntriesRecursively(const Path& path, const DirEntryCallable& callback,
  370. DirEntryFilter filter = DirEntryFilter::All) {
  371. if constexpr (IsChar<typename Path::value_type>) {
  372. IterateDirEntriesRecursively(ToU8String(path), callback, filter);
  373. } else {
  374. IterateDirEntriesRecursively(std::filesystem::path{path}, callback, filter);
  375. }
  376. }
  377. #endif
  378. // Generic Filesystem Operations
  379. /**
  380. * Returns whether a filesystem object at path exists.
  381. *
  382. * @param path Filesystem path
  383. *
  384. * @returns True if a filesystem object at path exists, false otherwise.
  385. */
  386. [[nodiscard]] bool Exists(const std::filesystem::path& path);
  387. #ifdef _WIN32
  388. template <typename Path>
  389. [[nodiscard]] bool Exists(const Path& path) {
  390. if constexpr (IsChar<typename Path::value_type>) {
  391. return Exists(ToU8String(path));
  392. } else {
  393. return Exists(std::filesystem::path{path});
  394. }
  395. }
  396. #endif
  397. /**
  398. * Returns whether a filesystem object at path is a regular file.
  399. * A regular file is a file that stores text or binary data.
  400. * It is not a directory, symlink, FIFO, socket, block device, or character device.
  401. *
  402. * @param path Filesystem path
  403. *
  404. * @returns True if a filesystem object at path is a regular file, false otherwise.
  405. */
  406. [[nodiscard]] bool IsFile(const std::filesystem::path& path);
  407. #ifdef _WIN32
  408. template <typename Path>
  409. [[nodiscard]] bool IsFile(const Path& path) {
  410. if constexpr (IsChar<typename Path::value_type>) {
  411. return IsFile(ToU8String(path));
  412. } else {
  413. return IsFile(std::filesystem::path{path});
  414. }
  415. }
  416. #endif
  417. /**
  418. * Returns whether a filesystem object at path is a directory.
  419. *
  420. * @param path Filesystem path
  421. *
  422. * @returns True if a filesystem object at path is a directory, false otherwise.
  423. */
  424. [[nodiscard]] bool IsDir(const std::filesystem::path& path);
  425. #ifdef _WIN32
  426. template <typename Path>
  427. [[nodiscard]] bool IsDir(const Path& path) {
  428. if constexpr (IsChar<typename Path::value_type>) {
  429. return IsDir(ToU8String(path));
  430. } else {
  431. return IsDir(std::filesystem::path{path});
  432. }
  433. }
  434. #endif
  435. /**
  436. * Gets the current working directory.
  437. *
  438. * @returns The current working directory. Returns an empty path on failure.
  439. */
  440. [[nodiscard]] std::filesystem::path GetCurrentDir();
  441. /**
  442. * Sets the current working directory to path.
  443. *
  444. * @returns True if the current working directory is successfully set, false otherwise.
  445. */
  446. [[nodiscard]] bool SetCurrentDir(const std::filesystem::path& path);
  447. #ifdef _WIN32
  448. template <typename Path>
  449. [[nodiscard]] bool SetCurrentDir(const Path& path) {
  450. if constexpr (IsChar<typename Path::value_type>) {
  451. return SetCurrentDir(ToU8String(path));
  452. } else {
  453. return SetCurrentDir(std::filesystem::path{path});
  454. }
  455. }
  456. #endif
  457. /**
  458. * Gets the entry type of the filesystem object at path.
  459. *
  460. * @param path Filesystem path
  461. *
  462. * @returns The entry type of the filesystem object. Returns file_type::not_found on failure.
  463. */
  464. [[nodiscard]] std::filesystem::file_type GetEntryType(const std::filesystem::path& path);
  465. #ifdef _WIN32
  466. template <typename Path>
  467. [[nodiscard]] std::filesystem::file_type GetEntryType(const Path& path) {
  468. if constexpr (IsChar<typename Path::value_type>) {
  469. return GetEntryType(ToU8String(path));
  470. } else {
  471. return GetEntryType(std::filesystem::path{path});
  472. }
  473. }
  474. #endif
  475. /**
  476. * Gets the size of the filesystem object at path.
  477. *
  478. * @param path Filesystem path
  479. *
  480. * @returns The size in bytes of the filesystem object. Returns 0 on failure.
  481. */
  482. [[nodiscard]] u64 GetSize(const std::filesystem::path& path);
  483. #ifdef _WIN32
  484. template <typename Path>
  485. [[nodiscard]] u64 GetSize(const Path& path) {
  486. if constexpr (IsChar<typename Path::value_type>) {
  487. return GetSize(ToU8String(path));
  488. } else {
  489. return GetSize(std::filesystem::path{path});
  490. }
  491. }
  492. #endif
  493. /**
  494. * Gets the free space size of the filesystem at path.
  495. *
  496. * @param path Filesystem path
  497. *
  498. * @returns The free space size in bytes of the filesystem at path. Returns 0 on failure.
  499. */
  500. [[nodiscard]] u64 GetFreeSpaceSize(const std::filesystem::path& path);
  501. #ifdef _WIN32
  502. template <typename Path>
  503. [[nodiscard]] u64 GetFreeSpaceSize(const Path& path) {
  504. if constexpr (IsChar<typename Path::value_type>) {
  505. return GetFreeSpaceSize(ToU8String(path));
  506. } else {
  507. return GetFreeSpaceSize(std::filesystem::path{path});
  508. }
  509. }
  510. #endif
  511. /**
  512. * Gets the total capacity of the filesystem at path.
  513. *
  514. * @param path Filesystem path
  515. *
  516. * @returns The total capacity in bytes of the filesystem at path. Returns 0 on failure.
  517. */
  518. [[nodiscard]] u64 GetTotalSpaceSize(const std::filesystem::path& path);
  519. #ifdef _WIN32
  520. template <typename Path>
  521. [[nodiscard]] u64 GetTotalSpaceSize(const Path& path) {
  522. if constexpr (IsChar<typename Path::value_type>) {
  523. return GetTotalSpaceSize(ToU8String(path));
  524. } else {
  525. return GetTotalSpaceSize(std::filesystem::path{path});
  526. }
  527. }
  528. #endif
  529. } // namespace Common::FS