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