summaryrefslogtreecommitdiff
path: root/src/core/file_sys
diff options
context:
space:
mode:
authorGravatar bunnei2018-03-23 20:48:26 -0400
committerGravatar GitHub2018-03-23 20:48:26 -0400
commita397a9e9a4bad1ed03229082408b7fa424295530 (patch)
tree3f4766c0bc490d10cf89377475c23fa237e2bba2 /src/core/file_sys
parentMerge pull request #268 from mailwl/ssl (diff)
parentFS: Move the file open mode calculation to a separate function. (diff)
downloadyuzu-a397a9e9a4bad1ed03229082408b7fa424295530.tar.gz
yuzu-a397a9e9a4bad1ed03229082408b7fa424295530.tar.xz
yuzu-a397a9e9a4bad1ed03229082408b7fa424295530.zip
Merge pull request #255 from Subv/sd_card
FS: Implemented access to the SD card
Diffstat (limited to 'src/core/file_sys')
-rw-r--r--src/core/file_sys/directory.h37
-rw-r--r--src/core/file_sys/disk_filesystem.cpp109
-rw-r--r--src/core/file_sys/disk_filesystem.h27
-rw-r--r--src/core/file_sys/filesystem.h8
-rw-r--r--src/core/file_sys/romfs_filesystem.cpp5
-rw-r--r--src/core/file_sys/romfs_filesystem.h10
-rw-r--r--src/core/file_sys/sdmc_factory.cpp40
-rw-r--r--src/core/file_sys/sdmc_factory.h31
8 files changed, 221 insertions, 46 deletions
diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h
index 5a40bf472..c7639795e 100644
--- a/src/core/file_sys/directory.h
+++ b/src/core/file_sys/directory.h
@@ -6,34 +6,28 @@
6 6
7#include <array> 7#include <array>
8#include <cstddef> 8#include <cstddef>
9#include "common/common_funcs.h"
9#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/file_sys/filesystem.h"
10 12
11//////////////////////////////////////////////////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////////////////////////////////////////////////
12// FileSys namespace 14// FileSys namespace
13 15
14namespace FileSys { 16namespace FileSys {
15 17
16// Structure of a directory entry, from http://3dbrew.org/wiki/FSDir:Read#Entry_format 18// Structure of a directory entry, from
17const size_t FILENAME_LENGTH = 0x20C / 2; 19// http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry
20const size_t FILENAME_LENGTH = 0x300;
18struct Entry { 21struct Entry {
19 char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated) 22 char filename[FILENAME_LENGTH];
20 std::array<char, 9> short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated) 23 INSERT_PADDING_BYTES(4);
21 char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD) 24 EntryType type;
22 std::array<char, 4> 25 INSERT_PADDING_BYTES(3);
23 extension; // 8.3 file extension (set to spaces for directories, null-terminated) 26 u64 file_size;
24 char unknown2; // unknown (always 0x01)
25 char unknown3; // unknown (0x00 or 0x08)
26 char is_directory; // directory flag
27 char is_hidden; // hidden flag
28 char is_archive; // archive flag
29 char is_read_only; // read-only flag
30 u64 file_size; // file size (for files only)
31}; 27};
32static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!"); 28static_assert(sizeof(Entry) == 0x310, "Directory Entry struct isn't exactly 0x310 bytes long!");
33static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry."); 29static_assert(offsetof(Entry, type) == 0x304, "Wrong offset for type in Entry.");
34static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension in Entry."); 30static_assert(offsetof(Entry, file_size) == 0x308, "Wrong offset for file_size in Entry.");
35static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry.");
36static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry.");
37 31
38class DirectoryBackend : NonCopyable { 32class DirectoryBackend : NonCopyable {
39public: 33public:
@@ -46,7 +40,10 @@ public:
46 * @param entries Buffer to read data into 40 * @param entries Buffer to read data into
47 * @return Number of entries listed 41 * @return Number of entries listed
48 */ 42 */
49 virtual u32 Read(const u32 count, Entry* entries) = 0; 43 virtual u64 Read(const u64 count, Entry* entries) = 0;
44
45 /// Returns the number of entries still left to read.
46 virtual u64 GetEntryCount() const = 0;
50 47
51 /** 48 /**
52 * Close the directory 49 * Close the directory
diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp
index 22b17ba04..3a4b45721 100644
--- a/src/core/file_sys/disk_filesystem.cpp
+++ b/src/core/file_sys/disk_filesystem.cpp
@@ -11,16 +11,43 @@
11 11
12namespace FileSys { 12namespace FileSys {
13 13
14static std::string ModeFlagsToString(Mode mode) {
15 std::string mode_str;
16 u32 mode_flags = static_cast<u32>(mode);
17
18 // Calculate the correct open mode for the file.
19 if ((mode_flags & static_cast<u32>(Mode::Read)) &&
20 (mode_flags & static_cast<u32>(Mode::Write))) {
21 if (mode_flags & static_cast<u32>(Mode::Append))
22 mode_str = "a+";
23 else
24 mode_str = "r+";
25 } else {
26 if (mode_flags & static_cast<u32>(Mode::Read))
27 mode_str = "r";
28 else if (mode_flags & static_cast<u32>(Mode::Append))
29 mode_str = "a";
30 else if (mode_flags & static_cast<u32>(Mode::Write))
31 mode_str = "w";
32 }
33
34 mode_str += "b";
35
36 return mode_str;
37}
38
14std::string Disk_FileSystem::GetName() const { 39std::string Disk_FileSystem::GetName() const {
15 return "Disk"; 40 return "Disk";
16} 41}
17 42
18ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::string& path, 43ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::string& path,
19 Mode mode) const { 44 Mode mode) const {
20 ASSERT_MSG(mode == Mode::Read || mode == Mode::Write, "Other file modes are not supported"); 45
46 // Calculate the correct open mode for the file.
47 std::string mode_str = ModeFlagsToString(mode);
21 48
22 std::string full_path = base_directory + path; 49 std::string full_path = base_directory + path;
23 auto file = std::make_shared<FileUtil::IOFile>(full_path, mode == Mode::Read ? "rb" : "wb"); 50 auto file = std::make_shared<FileUtil::IOFile>(full_path, mode_str.c_str());
24 51
25 if (!file->IsOpen()) { 52 if (!file->IsOpen()) {
26 return ERROR_PATH_NOT_FOUND; 53 return ERROR_PATH_NOT_FOUND;
@@ -75,8 +102,15 @@ ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const
75 return ResultCode(-1); 102 return ResultCode(-1);
76} 103}
77 104
78ResultCode Disk_FileSystem::CreateDirectory(const Path& path) const { 105ResultCode Disk_FileSystem::CreateDirectory(const std::string& path) const {
79 LOG_WARNING(Service_FS, "(STUBBED) called"); 106 // TODO(Subv): Perform path validation to prevent escaping the emulator sandbox.
107 std::string full_path = base_directory + path;
108
109 if (FileUtil::CreateDir(full_path)) {
110 return RESULT_SUCCESS;
111 }
112
113 LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", full_path.c_str());
80 // TODO(wwylele): Use correct error code 114 // TODO(wwylele): Use correct error code
81 return ResultCode(-1); 115 return ResultCode(-1);
82} 116}
@@ -88,8 +122,17 @@ ResultCode Disk_FileSystem::RenameDirectory(const Path& src_path, const Path& de
88} 122}
89 123
90ResultVal<std::unique_ptr<DirectoryBackend>> Disk_FileSystem::OpenDirectory( 124ResultVal<std::unique_ptr<DirectoryBackend>> Disk_FileSystem::OpenDirectory(
91 const Path& path) const { 125 const std::string& path) const {
92 return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<Disk_Directory>()); 126
127 std::string full_path = base_directory + path;
128
129 if (!FileUtil::IsDirectory(full_path)) {
130 // TODO(Subv): Find the correct error code for this.
131 return ResultCode(-1);
132 }
133
134 auto directory = std::make_unique<Disk_Directory>(full_path);
135 return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory));
93} 136}
94 137
95u64 Disk_FileSystem::GetFreeSpaceSize() const { 138u64 Disk_FileSystem::GetFreeSpaceSize() const {
@@ -103,8 +146,10 @@ ResultVal<FileSys::EntryType> Disk_FileSystem::GetEntryType(const std::string& p
103 return ERROR_PATH_NOT_FOUND; 146 return ERROR_PATH_NOT_FOUND;
104 } 147 }
105 148
106 // TODO(Subv): Find out the EntryType values 149 if (FileUtil::IsDirectory(full_path))
107 UNIMPLEMENTED_MSG("Unimplemented GetEntryType"); 150 return MakeResult(EntryType::Directory);
151
152 return MakeResult(EntryType::File);
108} 153}
109 154
110ResultVal<size_t> Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { 155ResultVal<size_t> Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const {
@@ -133,14 +178,50 @@ bool Disk_Storage::SetSize(const u64 size) const {
133 return false; 178 return false;
134} 179}
135 180
136u32 Disk_Directory::Read(const u32 count, Entry* entries) { 181Disk_Directory::Disk_Directory(const std::string& path) : directory() {
137 LOG_WARNING(Service_FS, "(STUBBED) called"); 182 unsigned size = FileUtil::ScanDirectoryTree(path, directory);
138 return 0; 183 directory.size = size;
184 directory.isDirectory = true;
185 children_iterator = directory.children.begin();
139} 186}
140 187
141bool Disk_Directory::Close() const { 188u64 Disk_Directory::Read(const u64 count, Entry* entries) {
142 LOG_WARNING(Service_FS, "(STUBBED) called"); 189 u64 entries_read = 0;
143 return true; 190
191 while (entries_read < count && children_iterator != directory.children.cend()) {
192 const FileUtil::FSTEntry& file = *children_iterator;
193 const std::string& filename = file.virtualName;
194 Entry& entry = entries[entries_read];
195
196 LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size,
197 file.isDirectory);
198
199 // TODO(Link Mauve): use a proper conversion to UTF-16.
200 for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
201 entry.filename[j] = filename[j];
202 if (!filename[j])
203 break;
204 }
205
206 if (file.isDirectory) {
207 entry.file_size = 0;
208 entry.type = EntryType::Directory;
209 } else {
210 entry.file_size = file.size;
211 entry.type = EntryType::File;
212 }
213
214 ++entries_read;
215 ++children_iterator;
216 }
217 return entries_read;
218}
219
220u64 Disk_Directory::GetEntryCount() const {
221 // We convert the children iterator into a const_iterator to allow template argument deduction
222 // in std::distance.
223 std::vector<FileUtil::FSTEntry>::const_iterator current = children_iterator;
224 return std::distance(current, directory.children.end());
144} 225}
145 226
146} // namespace FileSys 227} // namespace FileSys
diff --git a/src/core/file_sys/disk_filesystem.h b/src/core/file_sys/disk_filesystem.h
index 53767b949..742d7db1a 100644
--- a/src/core/file_sys/disk_filesystem.h
+++ b/src/core/file_sys/disk_filesystem.h
@@ -30,9 +30,10 @@ public:
30 ResultCode DeleteDirectory(const Path& path) const override; 30 ResultCode DeleteDirectory(const Path& path) const override;
31 ResultCode DeleteDirectoryRecursively(const Path& path) const override; 31 ResultCode DeleteDirectoryRecursively(const Path& path) const override;
32 ResultCode CreateFile(const std::string& path, u64 size) const override; 32 ResultCode CreateFile(const std::string& path, u64 size) const override;
33 ResultCode CreateDirectory(const Path& path) const override; 33 ResultCode CreateDirectory(const std::string& path) const override;
34 ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; 34 ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
35 ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; 35 ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(
36 const std::string& path) const override;
36 u64 GetFreeSpaceSize() const override; 37 u64 GetFreeSpaceSize() const override;
37 ResultVal<EntryType> GetEntryType(const std::string& path) const override; 38 ResultVal<EntryType> GetEntryType(const std::string& path) const override;
38 39
@@ -59,8 +60,26 @@ private:
59 60
60class Disk_Directory : public DirectoryBackend { 61class Disk_Directory : public DirectoryBackend {
61public: 62public:
62 u32 Read(const u32 count, Entry* entries) override; 63 Disk_Directory(const std::string& path);
63 bool Close() const override; 64
65 ~Disk_Directory() override {
66 Close();
67 }
68
69 u64 Read(const u64 count, Entry* entries) override;
70 u64 GetEntryCount() const override;
71
72 bool Close() const override {
73 return true;
74 }
75
76protected:
77 u32 total_entries_in_directory;
78 FileUtil::FSTEntry directory;
79
80 // We need to remember the last entry we returned, so a subsequent call to Read will continue
81 // from the next one. This iterator will always point to the next unread entry.
82 std::vector<FileUtil::FSTEntry>::iterator children_iterator;
64}; 83};
65 84
66} // namespace FileSys 85} // namespace FileSys
diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h
index 94ad2abf2..399427ca2 100644
--- a/src/core/file_sys/filesystem.h
+++ b/src/core/file_sys/filesystem.h
@@ -27,7 +27,7 @@ enum LowPathType : u32 {
27 Wchar = 4, 27 Wchar = 4,
28}; 28};
29 29
30enum EntryType : u32 { 30enum EntryType : u8 {
31 Directory = 0, 31 Directory = 0,
32 File = 1, 32 File = 1,
33}; 33};
@@ -35,6 +35,7 @@ enum EntryType : u32 {
35enum class Mode : u32 { 35enum class Mode : u32 {
36 Read = 1, 36 Read = 1,
37 Write = 2, 37 Write = 2,
38 Append = 4,
38}; 39};
39 40
40class Path { 41class Path {
@@ -103,7 +104,7 @@ public:
103 * @param path Path relative to the archive 104 * @param path Path relative to the archive
104 * @return Result of the operation 105 * @return Result of the operation
105 */ 106 */
106 virtual ResultCode CreateDirectory(const Path& path) const = 0; 107 virtual ResultCode CreateDirectory(const std::string& path) const = 0;
107 108
108 /** 109 /**
109 * Delete a directory specified by its path 110 * Delete a directory specified by its path
@@ -149,7 +150,8 @@ public:
149 * @param path Path relative to the archive 150 * @param path Path relative to the archive
150 * @return Opened directory, or error code 151 * @return Opened directory, or error code
151 */ 152 */
152 virtual ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const = 0; 153 virtual ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(
154 const std::string& path) const = 0;
153 155
154 /** 156 /**
155 * Get the free space 157 * Get the free space
diff --git a/src/core/file_sys/romfs_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp
index f1f9b4d04..0c6cc3157 100644
--- a/src/core/file_sys/romfs_filesystem.cpp
+++ b/src/core/file_sys/romfs_filesystem.cpp
@@ -55,7 +55,7 @@ ResultCode RomFS_FileSystem::CreateFile(const std::string& path, u64 size) const
55 return ResultCode(-1); 55 return ResultCode(-1);
56} 56}
57 57
58ResultCode RomFS_FileSystem::CreateDirectory(const Path& path) const { 58ResultCode RomFS_FileSystem::CreateDirectory(const std::string& path) const {
59 LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive (%s).", 59 LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive (%s).",
60 GetName().c_str()); 60 GetName().c_str());
61 // TODO(wwylele): Use correct error code 61 // TODO(wwylele): Use correct error code
@@ -70,7 +70,8 @@ ResultCode RomFS_FileSystem::RenameDirectory(const Path& src_path, const Path& d
70} 70}
71 71
72ResultVal<std::unique_ptr<DirectoryBackend>> RomFS_FileSystem::OpenDirectory( 72ResultVal<std::unique_ptr<DirectoryBackend>> RomFS_FileSystem::OpenDirectory(
73 const Path& path) const { 73 const std::string& path) const {
74 LOG_WARNING(Service_FS, "Opening Directory in a ROMFS archive");
74 return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<ROMFSDirectory>()); 75 return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<ROMFSDirectory>());
75} 76}
76 77
diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h
index cedd70645..3f94c04d0 100644
--- a/src/core/file_sys/romfs_filesystem.h
+++ b/src/core/file_sys/romfs_filesystem.h
@@ -36,9 +36,10 @@ public:
36 ResultCode DeleteDirectory(const Path& path) const override; 36 ResultCode DeleteDirectory(const Path& path) const override;
37 ResultCode DeleteDirectoryRecursively(const Path& path) const override; 37 ResultCode DeleteDirectoryRecursively(const Path& path) const override;
38 ResultCode CreateFile(const std::string& path, u64 size) const override; 38 ResultCode CreateFile(const std::string& path, u64 size) const override;
39 ResultCode CreateDirectory(const Path& path) const override; 39 ResultCode CreateDirectory(const std::string& path) const override;
40 ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; 40 ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
41 ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; 41 ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(
42 const std::string& path) const override;
42 u64 GetFreeSpaceSize() const override; 43 u64 GetFreeSpaceSize() const override;
43 ResultVal<EntryType> GetEntryType(const std::string& path) const override; 44 ResultVal<EntryType> GetEntryType(const std::string& path) const override;
44 45
@@ -70,7 +71,10 @@ private:
70 71
71class ROMFSDirectory : public DirectoryBackend { 72class ROMFSDirectory : public DirectoryBackend {
72public: 73public:
73 u32 Read(const u32 count, Entry* entries) override { 74 u64 Read(const u64 count, Entry* entries) override {
75 return 0;
76 }
77 u64 GetEntryCount() const override {
74 return 0; 78 return 0;
75 } 79 }
76 bool Close() const override { 80 bool Close() const override {
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp
new file mode 100644
index 000000000..00e80d2a7
--- /dev/null
+++ b/src/core/file_sys/sdmc_factory.cpp
@@ -0,0 +1,40 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cinttypes>
6#include <memory>
7#include "common/common_types.h"
8#include "common/logging/log.h"
9#include "common/string_util.h"
10#include "core/core.h"
11#include "core/file_sys/disk_filesystem.h"
12#include "core/file_sys/sdmc_factory.h"
13
14namespace FileSys {
15
16SDMC_Factory::SDMC_Factory(std::string sd_directory) : sd_directory(std::move(sd_directory)) {}
17
18ResultVal<std::unique_ptr<FileSystemBackend>> SDMC_Factory::Open(const Path& path) {
19 // Create the SD Card directory if it doesn't already exist.
20 if (!FileUtil::IsDirectory(sd_directory)) {
21 FileUtil::CreateFullPath(sd_directory);
22 }
23
24 auto archive = std::make_unique<Disk_FileSystem>(sd_directory);
25 return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive));
26}
27
28ResultCode SDMC_Factory::Format(const Path& path) {
29 LOG_ERROR(Service_FS, "Unimplemented Format archive %s", GetName().c_str());
30 // TODO(Subv): Find the right error code for this
31 return ResultCode(-1);
32}
33
34ResultVal<ArchiveFormatInfo> SDMC_Factory::GetFormatInfo(const Path& path) const {
35 LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str());
36 // TODO(bunnei): Find the right error code for this
37 return ResultCode(-1);
38}
39
40} // namespace FileSys
diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h
new file mode 100644
index 000000000..93becda25
--- /dev/null
+++ b/src/core/file_sys/sdmc_factory.h
@@ -0,0 +1,31 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <string>
9#include "common/common_types.h"
10#include "core/file_sys/filesystem.h"
11#include "core/hle/result.h"
12
13namespace FileSys {
14
15/// File system interface to the SDCard archive
16class SDMC_Factory final : public FileSystemFactory {
17public:
18 explicit SDMC_Factory(std::string sd_directory);
19
20 std::string GetName() const override {
21 return "SDMC_Factory";
22 }
23 ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override;
24 ResultCode Format(const Path& path) override;
25 ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
26
27private:
28 std::string sd_directory;
29};
30
31} // namespace FileSys