summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt2
-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
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp5
-rw-r--r--src/core/hle/service/filesystem/filesystem.h1
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp102
12 files changed, 329 insertions, 48 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 0a25a52e4..39cdb55f1 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -22,6 +22,8 @@ add_library(core STATIC
22 file_sys/romfs_filesystem.h 22 file_sys/romfs_filesystem.h
23 file_sys/savedata_factory.cpp 23 file_sys/savedata_factory.cpp
24 file_sys/savedata_factory.h 24 file_sys/savedata_factory.h
25 file_sys/sdmc_factory.cpp
26 file_sys/sdmc_factory.h
25 file_sys/storage.h 27 file_sys/storage.h
26 frontend/emu_window.cpp 28 frontend/emu_window.cpp
27 frontend/emu_window.h 29 frontend/emu_window.h
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
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index ef05955b9..945832e98 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -6,6 +6,7 @@
6#include "common/file_util.h" 6#include "common/file_util.h"
7#include "core/file_sys/filesystem.h" 7#include "core/file_sys/filesystem.h"
8#include "core/file_sys/savedata_factory.h" 8#include "core/file_sys/savedata_factory.h"
9#include "core/file_sys/sdmc_factory.h"
9#include "core/hle/service/filesystem/filesystem.h" 10#include "core/hle/service/filesystem/filesystem.h"
10#include "core/hle/service/filesystem/fsp_srv.h" 11#include "core/hle/service/filesystem/fsp_srv.h"
11 12
@@ -60,9 +61,13 @@ void RegisterFileSystems() {
60 filesystem_map.clear(); 61 filesystem_map.clear();
61 62
62 std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); 63 std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX);
64 std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX);
63 65
64 auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory)); 66 auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory));
65 RegisterFileSystem(std::move(savedata), Type::SaveData); 67 RegisterFileSystem(std::move(savedata), Type::SaveData);
68
69 auto sdcard = std::make_unique<FileSys::SDMC_Factory>(std::move(sd_directory));
70 RegisterFileSystem(std::move(sdcard), Type::SDMC);
66} 71}
67 72
68void InstallInterfaces(SM::ServiceManager& service_manager) { 73void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 8d30e94a1..56d26146e 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -26,6 +26,7 @@ namespace FileSystem {
26enum class Type { 26enum class Type {
27 RomFS = 1, 27 RomFS = 1,
28 SaveData = 2, 28 SaveData = 2,
29 SDMC = 3,
29}; 30};
30 31
31/** 32/**
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index e5ce41671..41b8cbfd2 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -5,6 +5,7 @@
5#include <cinttypes> 5#include <cinttypes>
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/file_sys/directory.h"
8#include "core/file_sys/filesystem.h" 9#include "core/file_sys/filesystem.h"
9#include "core/file_sys/storage.h" 10#include "core/file_sys/storage.h"
10#include "core/hle/ipc_helpers.h" 11#include "core/hle/ipc_helpers.h"
@@ -151,14 +152,66 @@ private:
151 } 152 }
152}; 153};
153 154
155class IDirectory final : public ServiceFramework<IDirectory> {
156public:
157 explicit IDirectory(std::unique_ptr<FileSys::DirectoryBackend>&& backend)
158 : ServiceFramework("IDirectory"), backend(std::move(backend)) {
159 static const FunctionInfo functions[] = {
160 {0, &IDirectory::Read, "Read"},
161 {1, &IDirectory::GetEntryCount, "GetEntryCount"},
162 };
163 RegisterHandlers(functions);
164 }
165
166private:
167 std::unique_ptr<FileSys::DirectoryBackend> backend;
168
169 void Read(Kernel::HLERequestContext& ctx) {
170 IPC::RequestParser rp{ctx};
171 const u64 unk = rp.Pop<u64>();
172
173 LOG_DEBUG(Service_FS, "called, unk=0x%llx", unk);
174
175 // Calculate how many entries we can fit in the output buffer
176 u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry);
177
178 // Read the data from the Directory backend
179 std::vector<FileSys::Entry> entries(count_entries);
180 u64 read_entries = backend->Read(count_entries, entries.data());
181
182 // Convert the data into a byte array
183 std::vector<u8> output(entries.size() * sizeof(FileSys::Entry));
184 std::memcpy(output.data(), entries.data(), output.size());
185
186 // Write the data to memory
187 ctx.WriteBuffer(output);
188
189 IPC::ResponseBuilder rb{ctx, 4};
190 rb.Push(RESULT_SUCCESS);
191 rb.Push(read_entries);
192 }
193
194 void GetEntryCount(Kernel::HLERequestContext& ctx) {
195 LOG_DEBUG(Service_FS, "called");
196
197 u64 count = backend->GetEntryCount();
198
199 IPC::ResponseBuilder rb{ctx, 4};
200 rb.Push(RESULT_SUCCESS);
201 rb.Push(count);
202 }
203};
204
154class IFileSystem final : public ServiceFramework<IFileSystem> { 205class IFileSystem final : public ServiceFramework<IFileSystem> {
155public: 206public:
156 explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend) 207 explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend)
157 : ServiceFramework("IFileSystem"), backend(std::move(backend)) { 208 : ServiceFramework("IFileSystem"), backend(std::move(backend)) {
158 static const FunctionInfo functions[] = { 209 static const FunctionInfo functions[] = {
159 {0, &IFileSystem::CreateFile, "CreateFile"}, 210 {0, &IFileSystem::CreateFile, "CreateFile"},
211 {2, &IFileSystem::CreateDirectory, "CreateDirectory"},
160 {7, &IFileSystem::GetEntryType, "GetEntryType"}, 212 {7, &IFileSystem::GetEntryType, "GetEntryType"},
161 {8, &IFileSystem::OpenFile, "OpenFile"}, 213 {8, &IFileSystem::OpenFile, "OpenFile"},
214 {9, &IFileSystem::OpenDirectory, "OpenDirectory"},
162 {10, &IFileSystem::Commit, "Commit"}, 215 {10, &IFileSystem::Commit, "Commit"},
163 }; 216 };
164 RegisterHandlers(functions); 217 RegisterHandlers(functions);
@@ -182,6 +235,20 @@ public:
182 rb.Push(backend->CreateFile(name, size)); 235 rb.Push(backend->CreateFile(name, size));
183 } 236 }
184 237
238 void CreateDirectory(Kernel::HLERequestContext& ctx) {
239 IPC::RequestParser rp{ctx};
240
241 auto file_buffer = ctx.ReadBuffer();
242 auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
243
244 std::string name(file_buffer.begin(), end);
245
246 LOG_DEBUG(Service_FS, "called directory %s", name.c_str());
247
248 IPC::ResponseBuilder rb{ctx, 2};
249 rb.Push(backend->CreateDirectory(name));
250 }
251
185 void OpenFile(Kernel::HLERequestContext& ctx) { 252 void OpenFile(Kernel::HLERequestContext& ctx) {
186 IPC::RequestParser rp{ctx}; 253 IPC::RequestParser rp{ctx};
187 254
@@ -208,6 +275,33 @@ public:
208 rb.PushIpcInterface<IFile>(std::move(file)); 275 rb.PushIpcInterface<IFile>(std::move(file));
209 } 276 }
210 277
278 void OpenDirectory(Kernel::HLERequestContext& ctx) {
279 IPC::RequestParser rp{ctx};
280
281 auto file_buffer = ctx.ReadBuffer();
282 auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
283
284 std::string name(file_buffer.begin(), end);
285
286 // TODO(Subv): Implement this filter.
287 u32 filter_flags = rp.Pop<u32>();
288
289 LOG_DEBUG(Service_FS, "called directory %s filter %u", name.c_str(), filter_flags);
290
291 auto result = backend->OpenDirectory(name);
292 if (result.Failed()) {
293 IPC::ResponseBuilder rb{ctx, 2};
294 rb.Push(result.Code());
295 return;
296 }
297
298 auto directory = std::move(result.Unwrap());
299
300 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
301 rb.Push(RESULT_SUCCESS);
302 rb.PushIpcInterface<IDirectory>(std::move(directory));
303 }
304
211 void GetEntryType(Kernel::HLERequestContext& ctx) { 305 void GetEntryType(Kernel::HLERequestContext& ctx) {
212 IPC::RequestParser rp{ctx}; 306 IPC::RequestParser rp{ctx};
213 307
@@ -274,10 +368,14 @@ void FSP_SRV::Initalize(Kernel::HLERequestContext& ctx) {
274} 368}
275 369
276void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { 370void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) {
277 LOG_WARNING(Service_FS, "(STUBBED) called"); 371 LOG_DEBUG(Service_FS, "called");
278 372
279 IPC::ResponseBuilder rb{ctx, 2}; 373 FileSys::Path unused;
374 auto filesystem = OpenFileSystem(Type::SDMC, unused).Unwrap();
375
376 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
280 rb.Push(RESULT_SUCCESS); 377 rb.Push(RESULT_SUCCESS);
378 rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
281} 379}
282 380
283void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) { 381void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) {