summaryrefslogtreecommitdiff
path: root/src/common/fs/fs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/fs/fs.cpp')
-rw-r--r--src/common/fs/fs.cpp610
1 files changed, 610 insertions, 0 deletions
diff --git a/src/common/fs/fs.cpp b/src/common/fs/fs.cpp
new file mode 100644
index 000000000..d492480d9
--- /dev/null
+++ b/src/common/fs/fs.cpp
@@ -0,0 +1,610 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/fs/file.h"
6#include "common/fs/fs.h"
7#include "common/fs/path_util.h"
8#include "common/logging/log.h"
9
10namespace Common::FS {
11
12namespace fs = std::filesystem;
13
14// File Operations
15
16bool NewFile(const fs::path& path, u64 size) {
17 if (!ValidatePath(path)) {
18 LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
19 return false;
20 }
21
22 if (!Exists(path.parent_path())) {
23 LOG_ERROR(Common_Filesystem, "Parent directory of path={} does not exist",
24 PathToUTF8String(path));
25 return false;
26 }
27
28 if (Exists(path)) {
29 LOG_ERROR(Common_Filesystem, "Filesystem object at path={} exists", PathToUTF8String(path));
30 return false;
31 }
32
33 IOFile io_file{path, FileAccessMode::Write};
34
35 if (!io_file.IsOpen()) {
36 LOG_ERROR(Common_Filesystem, "Failed to create a file at path={}", PathToUTF8String(path));
37 return false;
38 }
39
40 if (!io_file.SetSize(size)) {
41 LOG_ERROR(Common_Filesystem, "Failed to resize the file at path={} to size={}",
42 PathToUTF8String(path), size);
43 return false;
44 }
45
46 io_file.Close();
47
48 LOG_DEBUG(Common_Filesystem, "Successfully created a file at path={} with size={}",
49 PathToUTF8String(path), size);
50
51 return true;
52}
53
54bool RemoveFile(const fs::path& path) {
55 if (!ValidatePath(path)) {
56 LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
57 return false;
58 }
59
60 if (!Exists(path)) {
61 LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} does not exist",
62 PathToUTF8String(path));
63 return true;
64 }
65
66 if (!IsFile(path)) {
67 LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a file",
68 PathToUTF8String(path));
69 return false;
70 }
71
72 std::error_code ec;
73
74 fs::remove(path, ec);
75
76 if (ec) {
77 LOG_ERROR(Common_Filesystem, "Failed to remove the file at path={}, ec_message={}",
78 PathToUTF8String(path), ec.message());
79 return false;
80 }
81
82 LOG_DEBUG(Common_Filesystem, "Successfully removed the file at path={}",
83 PathToUTF8String(path));
84
85 return true;
86}
87
88bool RenameFile(const fs::path& old_path, const fs::path& new_path) {
89 if (!ValidatePath(old_path) || !ValidatePath(new_path)) {
90 LOG_ERROR(Common_Filesystem,
91 "One or both input path(s) is not valid, old_path={}, new_path={}",
92 PathToUTF8String(old_path), PathToUTF8String(new_path));
93 return false;
94 }
95
96 if (!Exists(old_path)) {
97 LOG_ERROR(Common_Filesystem, "Filesystem object at old_path={} does not exist",
98 PathToUTF8String(old_path));
99 return false;
100 }
101
102 if (!IsFile(old_path)) {
103 LOG_ERROR(Common_Filesystem, "Filesystem object at old_path={} is not a file",
104 PathToUTF8String(old_path));
105 return false;
106 }
107
108 if (Exists(new_path)) {
109 LOG_ERROR(Common_Filesystem, "Filesystem object at new_path={} exists",
110 PathToUTF8String(new_path));
111 return false;
112 }
113
114 std::error_code ec;
115
116 fs::rename(old_path, new_path, ec);
117
118 if (ec) {
119 LOG_ERROR(Common_Filesystem,
120 "Failed to rename the file from old_path={} to new_path={}, ec_message={}",
121 PathToUTF8String(old_path), PathToUTF8String(new_path), ec.message());
122 return false;
123 }
124
125 LOG_DEBUG(Common_Filesystem, "Successfully renamed the file from old_path={} to new_path={}",
126 PathToUTF8String(old_path), PathToUTF8String(new_path));
127
128 return true;
129}
130
131std::shared_ptr<IOFile> FileOpen(const fs::path& path, FileAccessMode mode, FileType type,
132 FileShareFlag flag) {
133 if (!ValidatePath(path)) {
134 LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
135 return nullptr;
136 }
137
138 if (!IsFile(path)) {
139 LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a file",
140 PathToUTF8String(path));
141 return nullptr;
142 }
143
144 auto io_file = std::make_shared<IOFile>(path, mode, type, flag);
145
146 if (!io_file->IsOpen()) {
147 io_file.reset();
148
149 LOG_ERROR(Common_Filesystem,
150 "Failed to open the file at path={} with mode={}, type={}, flag={}",
151 PathToUTF8String(path), mode, type, flag);
152
153 return nullptr;
154 }
155
156 LOG_DEBUG(Common_Filesystem,
157 "Successfully opened the file at path={} with mode={}, type={}, flag={}",
158 PathToUTF8String(path), mode, type, flag);
159
160 return io_file;
161}
162
163// Directory Operations
164
165bool CreateDir(const fs::path& path) {
166 if (!ValidatePath(path)) {
167 LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
168 return false;
169 }
170
171 if (!Exists(path.parent_path())) {
172 LOG_ERROR(Common_Filesystem, "Parent directory of path={} does not exist",
173 PathToUTF8String(path));
174 return false;
175 }
176
177 if (IsDir(path)) {
178 LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} exists and is a directory",
179 PathToUTF8String(path));
180 return true;
181 }
182
183 std::error_code ec;
184
185 fs::create_directory(path, ec);
186
187 if (ec) {
188 LOG_ERROR(Common_Filesystem, "Failed to create the directory at path={}, ec_message={}",
189 PathToUTF8String(path), ec.message());
190 return false;
191 }
192
193 LOG_DEBUG(Common_Filesystem, "Successfully created the directory at path={}",
194 PathToUTF8String(path));
195
196 return true;
197}
198
199bool CreateDirs(const fs::path& path) {
200 if (!ValidatePath(path)) {
201 LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
202 return false;
203 }
204
205 if (IsDir(path)) {
206 LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} exists and is a directory",
207 PathToUTF8String(path));
208 return true;
209 }
210
211 std::error_code ec;
212
213 fs::create_directories(path, ec);
214
215 if (ec) {
216 LOG_ERROR(Common_Filesystem, "Failed to create the directories at path={}, ec_message={}",
217 PathToUTF8String(path), ec.message());
218 return false;
219 }
220
221 LOG_DEBUG(Common_Filesystem, "Successfully created the directories at path={}",
222 PathToUTF8String(path));
223
224 return true;
225}
226
227bool CreateParentDir(const fs::path& path) {
228 return CreateDir(path.parent_path());
229}
230
231bool CreateParentDirs(const fs::path& path) {
232 return CreateDirs(path.parent_path());
233}
234
235bool RemoveDir(const fs::path& path) {
236 if (!ValidatePath(path)) {
237 LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
238 return false;
239 }
240
241 if (!Exists(path)) {
242 LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} does not exist",
243 PathToUTF8String(path));
244 return true;
245 }
246
247 if (!IsDir(path)) {
248 LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
249 PathToUTF8String(path));
250 return false;
251 }
252
253 std::error_code ec;
254
255 fs::remove(path, ec);
256
257 if (ec) {
258 LOG_ERROR(Common_Filesystem, "Failed to remove the directory at path={}, ec_message={}",
259 PathToUTF8String(path), ec.message());
260 return false;
261 }
262
263 LOG_DEBUG(Common_Filesystem, "Successfully removed the directory at path={}",
264 PathToUTF8String(path));
265
266 return true;
267}
268
269bool RemoveDirRecursively(const fs::path& path) {
270 if (!ValidatePath(path)) {
271 LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
272 return false;
273 }
274
275 if (!Exists(path)) {
276 LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} does not exist",
277 PathToUTF8String(path));
278 return true;
279 }
280
281 if (!IsDir(path)) {
282 LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
283 PathToUTF8String(path));
284 return false;
285 }
286
287 std::error_code ec;
288
289 fs::remove_all(path, ec);
290
291 if (ec) {
292 LOG_ERROR(Common_Filesystem,
293 "Failed to remove the directory and its contents at path={}, ec_message={}",
294 PathToUTF8String(path), ec.message());
295 return false;
296 }
297
298 LOG_DEBUG(Common_Filesystem, "Successfully removed the directory and its contents at path={}",
299 PathToUTF8String(path));
300
301 return true;
302}
303
304bool RemoveDirContentsRecursively(const fs::path& path) {
305 if (!ValidatePath(path)) {
306 LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
307 return false;
308 }
309
310 if (!Exists(path)) {
311 LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} does not exist",
312 PathToUTF8String(path));
313 return true;
314 }
315
316 if (!IsDir(path)) {
317 LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
318 PathToUTF8String(path));
319 return false;
320 }
321
322 std::error_code ec;
323
324 for (const auto& entry : fs::recursive_directory_iterator(path, ec)) {
325 if (ec) {
326 LOG_ERROR(Common_Filesystem,
327 "Failed to completely enumerate the directory at path={}, ec_message={}",
328 PathToUTF8String(path), ec.message());
329 break;
330 }
331
332 fs::remove(entry.path(), ec);
333
334 if (ec) {
335 LOG_ERROR(Common_Filesystem,
336 "Failed to remove the filesystem object at path={}, ec_message={}",
337 PathToUTF8String(entry.path()), ec.message());
338 break;
339 }
340 }
341
342 if (ec) {
343 LOG_ERROR(Common_Filesystem,
344 "Failed to remove all the contents of the directory at path={}, ec_message={}",
345 PathToUTF8String(path), ec.message());
346 return false;
347 }
348
349 LOG_DEBUG(Common_Filesystem,
350 "Successfully removed all the contents of the directory at path={}",
351 PathToUTF8String(path));
352
353 return true;
354}
355
356bool RenameDir(const fs::path& old_path, const fs::path& new_path) {
357 if (!ValidatePath(old_path) || !ValidatePath(new_path)) {
358 LOG_ERROR(Common_Filesystem,
359 "One or both input path(s) is not valid, old_path={}, new_path={}",
360 PathToUTF8String(old_path), PathToUTF8String(new_path));
361 return false;
362 }
363
364 if (!Exists(old_path)) {
365 LOG_ERROR(Common_Filesystem, "Filesystem object at old_path={} does not exist",
366 PathToUTF8String(old_path));
367 return false;
368 }
369
370 if (!IsDir(old_path)) {
371 LOG_ERROR(Common_Filesystem, "Filesystem object at old_path={} is not a directory",
372 PathToUTF8String(old_path));
373 return false;
374 }
375
376 if (Exists(new_path)) {
377 LOG_ERROR(Common_Filesystem, "Filesystem object at new_path={} exists",
378 PathToUTF8String(new_path));
379 return false;
380 }
381
382 std::error_code ec;
383
384 fs::rename(old_path, new_path, ec);
385
386 if (ec) {
387 LOG_ERROR(Common_Filesystem,
388 "Failed to rename the file from old_path={} to new_path={}, ec_message={}",
389 PathToUTF8String(old_path), PathToUTF8String(new_path), ec.message());
390 return false;
391 }
392
393 LOG_DEBUG(Common_Filesystem, "Successfully renamed the file from old_path={} to new_path={}",
394 PathToUTF8String(old_path), PathToUTF8String(new_path));
395
396 return true;
397}
398
399void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable& callback,
400 DirEntryFilter filter) {
401 if (!ValidatePath(path)) {
402 LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
403 return;
404 }
405
406 if (!Exists(path)) {
407 LOG_ERROR(Common_Filesystem, "Filesystem object at path={} does not exist",
408 PathToUTF8String(path));
409 return;
410 }
411
412 if (!IsDir(path)) {
413 LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
414 PathToUTF8String(path));
415 return;
416 }
417
418 bool callback_error = false;
419
420 std::error_code ec;
421
422 for (const auto& entry : fs::directory_iterator(path, ec)) {
423 if (ec) {
424 break;
425 }
426
427 if (True(filter & DirEntryFilter::File) &&
428 entry.status().type() == fs::file_type::regular) {
429 if (!callback(entry.path())) {
430 callback_error = true;
431 break;
432 }
433 }
434
435 if (True(filter & DirEntryFilter::Directory) &&
436 entry.status().type() == fs::file_type::directory) {
437 if (!callback(entry.path())) {
438 callback_error = true;
439 break;
440 }
441 }
442 }
443
444 if (callback_error || ec) {
445 LOG_ERROR(Common_Filesystem,
446 "Failed to visit all the directory entries of path={}, ec_message={}",
447 PathToUTF8String(path), ec.message());
448 return;
449 }
450
451 LOG_DEBUG(Common_Filesystem, "Successfully visited all the directory entries of path={}",
452 PathToUTF8String(path));
453}
454
455void IterateDirEntriesRecursively(const std::filesystem::path& path,
456 const DirEntryCallable& callback, DirEntryFilter filter) {
457 if (!ValidatePath(path)) {
458 LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
459 return;
460 }
461
462 if (!Exists(path)) {
463 LOG_ERROR(Common_Filesystem, "Filesystem object at path={} does not exist",
464 PathToUTF8String(path));
465 return;
466 }
467
468 if (!IsDir(path)) {
469 LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
470 PathToUTF8String(path));
471 return;
472 }
473
474 bool callback_error = false;
475
476 std::error_code ec;
477
478 for (const auto& entry : fs::recursive_directory_iterator(path, ec)) {
479 if (ec) {
480 break;
481 }
482
483 if (True(filter & DirEntryFilter::File) &&
484 entry.status().type() == fs::file_type::regular) {
485 if (!callback(entry.path())) {
486 callback_error = true;
487 break;
488 }
489 }
490
491 if (True(filter & DirEntryFilter::Directory) &&
492 entry.status().type() == fs::file_type::directory) {
493 if (!callback(entry.path())) {
494 callback_error = true;
495 break;
496 }
497 }
498 }
499
500 if (callback_error || ec) {
501 LOG_ERROR(Common_Filesystem,
502 "Failed to visit all the directory entries of path={}, ec_message={}",
503 PathToUTF8String(path), ec.message());
504 return;
505 }
506
507 LOG_DEBUG(Common_Filesystem, "Successfully visited all the directory entries of path={}",
508 PathToUTF8String(path));
509}
510
511// Generic Filesystem Operations
512
513bool Exists(const fs::path& path) {
514 return fs::exists(path);
515}
516
517bool IsFile(const fs::path& path) {
518 return fs::is_regular_file(path);
519}
520
521bool IsDir(const fs::path& path) {
522 return fs::is_directory(path);
523}
524
525fs::path GetCurrentDir() {
526 std::error_code ec;
527
528 const auto current_path = fs::current_path(ec);
529
530 if (ec) {
531 LOG_ERROR(Common_Filesystem, "Failed to get the current path, ec_message={}", ec.message());
532 return {};
533 }
534
535 return current_path;
536}
537
538bool SetCurrentDir(const fs::path& path) {
539 std::error_code ec;
540
541 fs::current_path(path, ec);
542
543 if (ec) {
544 LOG_ERROR(Common_Filesystem, "Failed to set the current path to path={}, ec_message={}",
545 PathToUTF8String(path), ec.message());
546 return false;
547 }
548
549 return true;
550}
551
552fs::file_type GetEntryType(const fs::path& path) {
553 std::error_code ec;
554
555 const auto file_status = fs::status(path, ec);
556
557 if (ec) {
558 LOG_ERROR(Common_Filesystem, "Failed to retrieve the entry type of path={}, ec_message={}",
559 PathToUTF8String(path), ec.message());
560 return fs::file_type::not_found;
561 }
562
563 return file_status.type();
564}
565
566u64 GetSize(const fs::path& path) {
567 std::error_code ec;
568
569 const auto file_size = fs::file_size(path, ec);
570
571 if (ec) {
572 LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}",
573 PathToUTF8String(path), ec.message());
574 return 0;
575 }
576
577 return file_size;
578}
579
580u64 GetFreeSpaceSize(const fs::path& path) {
581 std::error_code ec;
582
583 const auto space_info = fs::space(path, ec);
584
585 if (ec) {
586 LOG_ERROR(Common_Filesystem,
587 "Failed to retrieve the available free space of path={}, ec_message={}",
588 PathToUTF8String(path), ec.message());
589 return 0;
590 }
591
592 return space_info.free;
593}
594
595u64 GetTotalSpaceSize(const fs::path& path) {
596 std::error_code ec;
597
598 const auto space_info = fs::space(path, ec);
599
600 if (ec) {
601 LOG_ERROR(Common_Filesystem,
602 "Failed to retrieve the total capacity of path={}, ec_message={}",
603 PathToUTF8String(path), ec.message());
604 return 0;
605 }
606
607 return space_info.capacity;
608}
609
610} // namespace Common::FS