mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +00:00 
			
		
		
		
	Merge pull request #255 from Subv/sd_card
FS: Implemented access to the SD card
This commit is contained in:
		
						commit
						a397a9e9a4
					
				| @ -22,6 +22,8 @@ add_library(core STATIC | |||||||
|     file_sys/romfs_filesystem.h |     file_sys/romfs_filesystem.h | ||||||
|     file_sys/savedata_factory.cpp |     file_sys/savedata_factory.cpp | ||||||
|     file_sys/savedata_factory.h |     file_sys/savedata_factory.h | ||||||
|  |     file_sys/sdmc_factory.cpp | ||||||
|  |     file_sys/sdmc_factory.h | ||||||
|     file_sys/storage.h |     file_sys/storage.h | ||||||
|     frontend/emu_window.cpp |     frontend/emu_window.cpp | ||||||
|     frontend/emu_window.h |     frontend/emu_window.h | ||||||
|  | |||||||
| @ -6,34 +6,28 @@ | |||||||
| 
 | 
 | ||||||
| #include <array> | #include <array> | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
|  | #include "common/common_funcs.h" | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  | #include "core/file_sys/filesystem.h" | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // FileSys namespace
 | // FileSys namespace
 | ||||||
| 
 | 
 | ||||||
| namespace FileSys { | namespace FileSys { | ||||||
| 
 | 
 | ||||||
| // Structure of a directory entry, from http://3dbrew.org/wiki/FSDir:Read#Entry_format
 | // Structure of a directory entry, from
 | ||||||
| const size_t FILENAME_LENGTH = 0x20C / 2; | // http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry
 | ||||||
|  | const size_t FILENAME_LENGTH = 0x300; | ||||||
| struct Entry { | struct Entry { | ||||||
|     char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated)
 |     char filename[FILENAME_LENGTH]; | ||||||
|     std::array<char, 9> short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated)
 |     INSERT_PADDING_BYTES(4); | ||||||
|     char unknown1;                  // unknown (observed values: 0x0A, 0x70, 0xFD)
 |     EntryType type; | ||||||
|     std::array<char, 4> |     INSERT_PADDING_BYTES(3); | ||||||
|         extension;     // 8.3 file extension (set to spaces for directories, null-terminated)
 |     u64 file_size; | ||||||
|     char unknown2;     // unknown (always 0x01)
 |  | ||||||
|     char unknown3;     // unknown (0x00 or 0x08)
 |  | ||||||
|     char is_directory; // directory flag
 |  | ||||||
|     char is_hidden;    // hidden flag
 |  | ||||||
|     char is_archive;   // archive flag
 |  | ||||||
|     char is_read_only; // read-only flag
 |  | ||||||
|     u64 file_size;     // file size (for files only)
 |  | ||||||
| }; | }; | ||||||
| static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!"); | static_assert(sizeof(Entry) == 0x310, "Directory Entry struct isn't exactly 0x310 bytes long!"); | ||||||
| static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry."); | static_assert(offsetof(Entry, type) == 0x304, "Wrong offset for type in Entry."); | ||||||
| static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension in Entry."); | static_assert(offsetof(Entry, file_size) == 0x308, "Wrong offset for file_size in Entry."); | ||||||
| static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry."); |  | ||||||
| static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry."); |  | ||||||
| 
 | 
 | ||||||
| class DirectoryBackend : NonCopyable { | class DirectoryBackend : NonCopyable { | ||||||
| public: | public: | ||||||
| @ -46,7 +40,10 @@ public: | |||||||
|      * @param entries Buffer to read data into |      * @param entries Buffer to read data into | ||||||
|      * @return Number of entries listed |      * @return Number of entries listed | ||||||
|      */ |      */ | ||||||
|     virtual u32 Read(const u32 count, Entry* entries) = 0; |     virtual u64 Read(const u64 count, Entry* entries) = 0; | ||||||
|  | 
 | ||||||
|  |     /// Returns the number of entries still left to read.
 | ||||||
|  |     virtual u64 GetEntryCount() const = 0; | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Close the directory |      * Close the directory | ||||||
|  | |||||||
| @ -11,16 +11,43 @@ | |||||||
| 
 | 
 | ||||||
| namespace FileSys { | namespace FileSys { | ||||||
| 
 | 
 | ||||||
|  | static std::string ModeFlagsToString(Mode mode) { | ||||||
|  |     std::string mode_str; | ||||||
|  |     u32 mode_flags = static_cast<u32>(mode); | ||||||
|  | 
 | ||||||
|  |     // Calculate the correct open mode for the file.
 | ||||||
|  |     if ((mode_flags & static_cast<u32>(Mode::Read)) && | ||||||
|  |         (mode_flags & static_cast<u32>(Mode::Write))) { | ||||||
|  |         if (mode_flags & static_cast<u32>(Mode::Append)) | ||||||
|  |             mode_str = "a+"; | ||||||
|  |         else | ||||||
|  |             mode_str = "r+"; | ||||||
|  |     } else { | ||||||
|  |         if (mode_flags & static_cast<u32>(Mode::Read)) | ||||||
|  |             mode_str = "r"; | ||||||
|  |         else if (mode_flags & static_cast<u32>(Mode::Append)) | ||||||
|  |             mode_str = "a"; | ||||||
|  |         else if (mode_flags & static_cast<u32>(Mode::Write)) | ||||||
|  |             mode_str = "w"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     mode_str += "b"; | ||||||
|  | 
 | ||||||
|  |     return mode_str; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| std::string Disk_FileSystem::GetName() const { | std::string Disk_FileSystem::GetName() const { | ||||||
|     return "Disk"; |     return "Disk"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::string& path, | ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::string& path, | ||||||
|                                                                      Mode mode) const { |                                                                      Mode mode) const { | ||||||
|     ASSERT_MSG(mode == Mode::Read || mode == Mode::Write, "Other file modes are not supported"); | 
 | ||||||
|  |     // Calculate the correct open mode for the file.
 | ||||||
|  |     std::string mode_str = ModeFlagsToString(mode); | ||||||
| 
 | 
 | ||||||
|     std::string full_path = base_directory + path; |     std::string full_path = base_directory + path; | ||||||
|     auto file = std::make_shared<FileUtil::IOFile>(full_path, mode == Mode::Read ? "rb" : "wb"); |     auto file = std::make_shared<FileUtil::IOFile>(full_path, mode_str.c_str()); | ||||||
| 
 | 
 | ||||||
|     if (!file->IsOpen()) { |     if (!file->IsOpen()) { | ||||||
|         return ERROR_PATH_NOT_FOUND; |         return ERROR_PATH_NOT_FOUND; | ||||||
| @ -75,8 +102,15 @@ ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const | |||||||
|     return ResultCode(-1); |     return ResultCode(-1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode Disk_FileSystem::CreateDirectory(const Path& path) const { | ResultCode Disk_FileSystem::CreateDirectory(const std::string& path) const { | ||||||
|     LOG_WARNING(Service_FS, "(STUBBED) called"); |     // TODO(Subv): Perform path validation to prevent escaping the emulator sandbox.
 | ||||||
|  |     std::string full_path = base_directory + path; | ||||||
|  | 
 | ||||||
|  |     if (FileUtil::CreateDir(full_path)) { | ||||||
|  |         return RESULT_SUCCESS; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", full_path.c_str()); | ||||||
|     // TODO(wwylele): Use correct error code
 |     // TODO(wwylele): Use correct error code
 | ||||||
|     return ResultCode(-1); |     return ResultCode(-1); | ||||||
| } | } | ||||||
| @ -88,8 +122,17 @@ ResultCode Disk_FileSystem::RenameDirectory(const Path& src_path, const Path& de | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<std::unique_ptr<DirectoryBackend>> Disk_FileSystem::OpenDirectory( | ResultVal<std::unique_ptr<DirectoryBackend>> Disk_FileSystem::OpenDirectory( | ||||||
|     const Path& path) const { |     const std::string& path) const { | ||||||
|     return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<Disk_Directory>()); | 
 | ||||||
|  |     std::string full_path = base_directory + path; | ||||||
|  | 
 | ||||||
|  |     if (!FileUtil::IsDirectory(full_path)) { | ||||||
|  |         // TODO(Subv): Find the correct error code for this.
 | ||||||
|  |         return ResultCode(-1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto directory = std::make_unique<Disk_Directory>(full_path); | ||||||
|  |     return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| u64 Disk_FileSystem::GetFreeSpaceSize() const { | u64 Disk_FileSystem::GetFreeSpaceSize() const { | ||||||
| @ -103,8 +146,10 @@ ResultVal<FileSys::EntryType> Disk_FileSystem::GetEntryType(const std::string& p | |||||||
|         return ERROR_PATH_NOT_FOUND; |         return ERROR_PATH_NOT_FOUND; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // TODO(Subv): Find out the EntryType values
 |     if (FileUtil::IsDirectory(full_path)) | ||||||
|     UNIMPLEMENTED_MSG("Unimplemented GetEntryType"); |         return MakeResult(EntryType::Directory); | ||||||
|  | 
 | ||||||
|  |     return MakeResult(EntryType::File); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<size_t> Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { | ResultVal<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 { | |||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| u32 Disk_Directory::Read(const u32 count, Entry* entries) { | Disk_Directory::Disk_Directory(const std::string& path) : directory() { | ||||||
|     LOG_WARNING(Service_FS, "(STUBBED) called"); |     unsigned size = FileUtil::ScanDirectoryTree(path, directory); | ||||||
|     return 0; |     directory.size = size; | ||||||
|  |     directory.isDirectory = true; | ||||||
|  |     children_iterator = directory.children.begin(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool Disk_Directory::Close() const { | u64 Disk_Directory::Read(const u64 count, Entry* entries) { | ||||||
|     LOG_WARNING(Service_FS, "(STUBBED) called"); |     u64 entries_read = 0; | ||||||
|     return true; | 
 | ||||||
|  |     while (entries_read < count && children_iterator != directory.children.cend()) { | ||||||
|  |         const FileUtil::FSTEntry& file = *children_iterator; | ||||||
|  |         const std::string& filename = file.virtualName; | ||||||
|  |         Entry& entry = entries[entries_read]; | ||||||
|  | 
 | ||||||
|  |         LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, | ||||||
|  |                   file.isDirectory); | ||||||
|  | 
 | ||||||
|  |         // TODO(Link Mauve): use a proper conversion to UTF-16.
 | ||||||
|  |         for (size_t j = 0; j < FILENAME_LENGTH; ++j) { | ||||||
|  |             entry.filename[j] = filename[j]; | ||||||
|  |             if (!filename[j]) | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (file.isDirectory) { | ||||||
|  |             entry.file_size = 0; | ||||||
|  |             entry.type = EntryType::Directory; | ||||||
|  |         } else { | ||||||
|  |             entry.file_size = file.size; | ||||||
|  |             entry.type = EntryType::File; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ++entries_read; | ||||||
|  |         ++children_iterator; | ||||||
|  |     } | ||||||
|  |     return entries_read; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | u64 Disk_Directory::GetEntryCount() const { | ||||||
|  |     // We convert the children iterator into a const_iterator to allow template argument deduction
 | ||||||
|  |     // in std::distance.
 | ||||||
|  |     std::vector<FileUtil::FSTEntry>::const_iterator current = children_iterator; | ||||||
|  |     return std::distance(current, directory.children.end()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace FileSys
 | } // namespace FileSys
 | ||||||
|  | |||||||
| @ -30,9 +30,10 @@ public: | |||||||
|     ResultCode DeleteDirectory(const Path& path) const override; |     ResultCode DeleteDirectory(const Path& path) const override; | ||||||
|     ResultCode DeleteDirectoryRecursively(const Path& path) const override; |     ResultCode DeleteDirectoryRecursively(const Path& path) const override; | ||||||
|     ResultCode CreateFile(const std::string& path, u64 size) const override; |     ResultCode CreateFile(const std::string& path, u64 size) const override; | ||||||
|     ResultCode CreateDirectory(const Path& path) const override; |     ResultCode CreateDirectory(const std::string& path) const override; | ||||||
|     ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; |     ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; | ||||||
|     ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; |     ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory( | ||||||
|  |         const std::string& path) const override; | ||||||
|     u64 GetFreeSpaceSize() const override; |     u64 GetFreeSpaceSize() const override; | ||||||
|     ResultVal<EntryType> GetEntryType(const std::string& path) const override; |     ResultVal<EntryType> GetEntryType(const std::string& path) const override; | ||||||
| 
 | 
 | ||||||
| @ -59,8 +60,26 @@ private: | |||||||
| 
 | 
 | ||||||
| class Disk_Directory : public DirectoryBackend { | class Disk_Directory : public DirectoryBackend { | ||||||
| public: | public: | ||||||
|     u32 Read(const u32 count, Entry* entries) override; |     Disk_Directory(const std::string& path); | ||||||
|     bool Close() const override; | 
 | ||||||
|  |     ~Disk_Directory() override { | ||||||
|  |         Close(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     u64 Read(const u64 count, Entry* entries) override; | ||||||
|  |     u64 GetEntryCount() const override; | ||||||
|  | 
 | ||||||
|  |     bool Close() const override { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  |     u32 total_entries_in_directory; | ||||||
|  |     FileUtil::FSTEntry directory; | ||||||
|  | 
 | ||||||
|  |     // We need to remember the last entry we returned, so a subsequent call to Read will continue
 | ||||||
|  |     // from the next one. This iterator will always point to the next unread entry.
 | ||||||
|  |     std::vector<FileUtil::FSTEntry>::iterator children_iterator; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace FileSys
 | } // namespace FileSys
 | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ enum LowPathType : u32 { | |||||||
|     Wchar = 4, |     Wchar = 4, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| enum EntryType : u32 { | enum EntryType : u8 { | ||||||
|     Directory = 0, |     Directory = 0, | ||||||
|     File = 1, |     File = 1, | ||||||
| }; | }; | ||||||
| @ -35,6 +35,7 @@ enum EntryType : u32 { | |||||||
| enum class Mode : u32 { | enum class Mode : u32 { | ||||||
|     Read = 1, |     Read = 1, | ||||||
|     Write = 2, |     Write = 2, | ||||||
|  |     Append = 4, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class Path { | class Path { | ||||||
| @ -103,7 +104,7 @@ public: | |||||||
|      * @param path Path relative to the archive |      * @param path Path relative to the archive | ||||||
|      * @return Result of the operation |      * @return Result of the operation | ||||||
|      */ |      */ | ||||||
|     virtual ResultCode CreateDirectory(const Path& path) const = 0; |     virtual ResultCode CreateDirectory(const std::string& path) const = 0; | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Delete a directory specified by its path |      * Delete a directory specified by its path | ||||||
| @ -149,7 +150,8 @@ public: | |||||||
|      * @param path Path relative to the archive |      * @param path Path relative to the archive | ||||||
|      * @return Opened directory, or error code |      * @return Opened directory, or error code | ||||||
|      */ |      */ | ||||||
|     virtual ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const = 0; |     virtual ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory( | ||||||
|  |         const std::string& path) const = 0; | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Get the free space |      * Get the free space | ||||||
|  | |||||||
| @ -55,7 +55,7 @@ ResultCode RomFS_FileSystem::CreateFile(const std::string& path, u64 size) const | |||||||
|     return ResultCode(-1); |     return ResultCode(-1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode RomFS_FileSystem::CreateDirectory(const Path& path) const { | ResultCode RomFS_FileSystem::CreateDirectory(const std::string& path) const { | ||||||
|     LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive (%s).", |     LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive (%s).", | ||||||
|                  GetName().c_str()); |                  GetName().c_str()); | ||||||
|     // TODO(wwylele): Use correct error code
 |     // TODO(wwylele): Use correct error code
 | ||||||
| @ -70,7 +70,8 @@ ResultCode RomFS_FileSystem::RenameDirectory(const Path& src_path, const Path& d | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<std::unique_ptr<DirectoryBackend>> RomFS_FileSystem::OpenDirectory( | ResultVal<std::unique_ptr<DirectoryBackend>> RomFS_FileSystem::OpenDirectory( | ||||||
|     const Path& path) const { |     const std::string& path) const { | ||||||
|  |     LOG_WARNING(Service_FS, "Opening Directory in a ROMFS archive"); | ||||||
|     return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<ROMFSDirectory>()); |     return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<ROMFSDirectory>()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -36,9 +36,10 @@ public: | |||||||
|     ResultCode DeleteDirectory(const Path& path) const override; |     ResultCode DeleteDirectory(const Path& path) const override; | ||||||
|     ResultCode DeleteDirectoryRecursively(const Path& path) const override; |     ResultCode DeleteDirectoryRecursively(const Path& path) const override; | ||||||
|     ResultCode CreateFile(const std::string& path, u64 size) const override; |     ResultCode CreateFile(const std::string& path, u64 size) const override; | ||||||
|     ResultCode CreateDirectory(const Path& path) const override; |     ResultCode CreateDirectory(const std::string& path) const override; | ||||||
|     ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; |     ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; | ||||||
|     ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; |     ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory( | ||||||
|  |         const std::string& path) const override; | ||||||
|     u64 GetFreeSpaceSize() const override; |     u64 GetFreeSpaceSize() const override; | ||||||
|     ResultVal<EntryType> GetEntryType(const std::string& path) const override; |     ResultVal<EntryType> GetEntryType(const std::string& path) const override; | ||||||
| 
 | 
 | ||||||
| @ -70,7 +71,10 @@ private: | |||||||
| 
 | 
 | ||||||
| class ROMFSDirectory : public DirectoryBackend { | class ROMFSDirectory : public DirectoryBackend { | ||||||
| public: | public: | ||||||
|     u32 Read(const u32 count, Entry* entries) override { |     u64 Read(const u64 count, Entry* entries) override { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |     u64 GetEntryCount() const override { | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|     bool Close() const override { |     bool Close() const override { | ||||||
|  | |||||||
							
								
								
									
										40
									
								
								src/core/file_sys/sdmc_factory.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/core/file_sys/sdmc_factory.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | // Copyright 2018 yuzu emulator team
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include <cinttypes> | ||||||
|  | #include <memory> | ||||||
|  | #include "common/common_types.h" | ||||||
|  | #include "common/logging/log.h" | ||||||
|  | #include "common/string_util.h" | ||||||
|  | #include "core/core.h" | ||||||
|  | #include "core/file_sys/disk_filesystem.h" | ||||||
|  | #include "core/file_sys/sdmc_factory.h" | ||||||
|  | 
 | ||||||
|  | namespace FileSys { | ||||||
|  | 
 | ||||||
|  | SDMC_Factory::SDMC_Factory(std::string sd_directory) : sd_directory(std::move(sd_directory)) {} | ||||||
|  | 
 | ||||||
|  | ResultVal<std::unique_ptr<FileSystemBackend>> SDMC_Factory::Open(const Path& path) { | ||||||
|  |     // Create the SD Card directory if it doesn't already exist.
 | ||||||
|  |     if (!FileUtil::IsDirectory(sd_directory)) { | ||||||
|  |         FileUtil::CreateFullPath(sd_directory); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto archive = std::make_unique<Disk_FileSystem>(sd_directory); | ||||||
|  |     return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode SDMC_Factory::Format(const Path& path) { | ||||||
|  |     LOG_ERROR(Service_FS, "Unimplemented Format archive %s", GetName().c_str()); | ||||||
|  |     // TODO(Subv): Find the right error code for this
 | ||||||
|  |     return ResultCode(-1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultVal<ArchiveFormatInfo> SDMC_Factory::GetFormatInfo(const Path& path) const { | ||||||
|  |     LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); | ||||||
|  |     // TODO(bunnei): Find the right error code for this
 | ||||||
|  |     return ResultCode(-1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace FileSys
 | ||||||
							
								
								
									
										31
									
								
								src/core/file_sys/sdmc_factory.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/core/file_sys/sdmc_factory.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | |||||||
|  | // Copyright 2018 yuzu emulator team
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <memory> | ||||||
|  | #include <string> | ||||||
|  | #include "common/common_types.h" | ||||||
|  | #include "core/file_sys/filesystem.h" | ||||||
|  | #include "core/hle/result.h" | ||||||
|  | 
 | ||||||
|  | namespace FileSys { | ||||||
|  | 
 | ||||||
|  | /// File system interface to the SDCard archive
 | ||||||
|  | class SDMC_Factory final : public FileSystemFactory { | ||||||
|  | public: | ||||||
|  |     explicit SDMC_Factory(std::string sd_directory); | ||||||
|  | 
 | ||||||
|  |     std::string GetName() const override { | ||||||
|  |         return "SDMC_Factory"; | ||||||
|  |     } | ||||||
|  |     ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override; | ||||||
|  |     ResultCode Format(const Path& path) override; | ||||||
|  |     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     std::string sd_directory; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace FileSys
 | ||||||
| @ -6,6 +6,7 @@ | |||||||
| #include "common/file_util.h" | #include "common/file_util.h" | ||||||
| #include "core/file_sys/filesystem.h" | #include "core/file_sys/filesystem.h" | ||||||
| #include "core/file_sys/savedata_factory.h" | #include "core/file_sys/savedata_factory.h" | ||||||
|  | #include "core/file_sys/sdmc_factory.h" | ||||||
| #include "core/hle/service/filesystem/filesystem.h" | #include "core/hle/service/filesystem/filesystem.h" | ||||||
| #include "core/hle/service/filesystem/fsp_srv.h" | #include "core/hle/service/filesystem/fsp_srv.h" | ||||||
| 
 | 
 | ||||||
| @ -60,9 +61,13 @@ void RegisterFileSystems() { | |||||||
|     filesystem_map.clear(); |     filesystem_map.clear(); | ||||||
| 
 | 
 | ||||||
|     std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); |     std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); | ||||||
|  |     std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX); | ||||||
| 
 | 
 | ||||||
|     auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory)); |     auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory)); | ||||||
|     RegisterFileSystem(std::move(savedata), Type::SaveData); |     RegisterFileSystem(std::move(savedata), Type::SaveData); | ||||||
|  | 
 | ||||||
|  |     auto sdcard = std::make_unique<FileSys::SDMC_Factory>(std::move(sd_directory)); | ||||||
|  |     RegisterFileSystem(std::move(sdcard), Type::SDMC); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void InstallInterfaces(SM::ServiceManager& service_manager) { | void InstallInterfaces(SM::ServiceManager& service_manager) { | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ namespace FileSystem { | |||||||
| enum class Type { | enum class Type { | ||||||
|     RomFS = 1, |     RomFS = 1, | ||||||
|     SaveData = 2, |     SaveData = 2, | ||||||
|  |     SDMC = 3, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| #include <cinttypes> | #include <cinttypes> | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
|  | #include "core/file_sys/directory.h" | ||||||
| #include "core/file_sys/filesystem.h" | #include "core/file_sys/filesystem.h" | ||||||
| #include "core/file_sys/storage.h" | #include "core/file_sys/storage.h" | ||||||
| #include "core/hle/ipc_helpers.h" | #include "core/hle/ipc_helpers.h" | ||||||
| @ -151,14 +152,66 @@ private: | |||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | class IDirectory final : public ServiceFramework<IDirectory> { | ||||||
|  | public: | ||||||
|  |     explicit IDirectory(std::unique_ptr<FileSys::DirectoryBackend>&& backend) | ||||||
|  |         : ServiceFramework("IDirectory"), backend(std::move(backend)) { | ||||||
|  |         static const FunctionInfo functions[] = { | ||||||
|  |             {0, &IDirectory::Read, "Read"}, | ||||||
|  |             {1, &IDirectory::GetEntryCount, "GetEntryCount"}, | ||||||
|  |         }; | ||||||
|  |         RegisterHandlers(functions); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     std::unique_ptr<FileSys::DirectoryBackend> backend; | ||||||
|  | 
 | ||||||
|  |     void Read(Kernel::HLERequestContext& ctx) { | ||||||
|  |         IPC::RequestParser rp{ctx}; | ||||||
|  |         const u64 unk = rp.Pop<u64>(); | ||||||
|  | 
 | ||||||
|  |         LOG_DEBUG(Service_FS, "called, unk=0x%llx", unk); | ||||||
|  | 
 | ||||||
|  |         // Calculate how many entries we can fit in the output buffer
 | ||||||
|  |         u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry); | ||||||
|  | 
 | ||||||
|  |         // Read the data from the Directory backend
 | ||||||
|  |         std::vector<FileSys::Entry> entries(count_entries); | ||||||
|  |         u64 read_entries = backend->Read(count_entries, entries.data()); | ||||||
|  | 
 | ||||||
|  |         // Convert the data into a byte array
 | ||||||
|  |         std::vector<u8> output(entries.size() * sizeof(FileSys::Entry)); | ||||||
|  |         std::memcpy(output.data(), entries.data(), output.size()); | ||||||
|  | 
 | ||||||
|  |         // Write the data to memory
 | ||||||
|  |         ctx.WriteBuffer(output); | ||||||
|  | 
 | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|  |         rb.Push(RESULT_SUCCESS); | ||||||
|  |         rb.Push(read_entries); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void GetEntryCount(Kernel::HLERequestContext& ctx) { | ||||||
|  |         LOG_DEBUG(Service_FS, "called"); | ||||||
|  | 
 | ||||||
|  |         u64 count = backend->GetEntryCount(); | ||||||
|  | 
 | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|  |         rb.Push(RESULT_SUCCESS); | ||||||
|  |         rb.Push(count); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| class IFileSystem final : public ServiceFramework<IFileSystem> { | class IFileSystem final : public ServiceFramework<IFileSystem> { | ||||||
| public: | public: | ||||||
|     explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend) |     explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend) | ||||||
|         : ServiceFramework("IFileSystem"), backend(std::move(backend)) { |         : ServiceFramework("IFileSystem"), backend(std::move(backend)) { | ||||||
|         static const FunctionInfo functions[] = { |         static const FunctionInfo functions[] = { | ||||||
|             {0, &IFileSystem::CreateFile, "CreateFile"}, |             {0, &IFileSystem::CreateFile, "CreateFile"}, | ||||||
|  |             {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, | ||||||
|             {7, &IFileSystem::GetEntryType, "GetEntryType"}, |             {7, &IFileSystem::GetEntryType, "GetEntryType"}, | ||||||
|             {8, &IFileSystem::OpenFile, "OpenFile"}, |             {8, &IFileSystem::OpenFile, "OpenFile"}, | ||||||
|  |             {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, | ||||||
|             {10, &IFileSystem::Commit, "Commit"}, |             {10, &IFileSystem::Commit, "Commit"}, | ||||||
|         }; |         }; | ||||||
|         RegisterHandlers(functions); |         RegisterHandlers(functions); | ||||||
| @ -182,6 +235,20 @@ public: | |||||||
|         rb.Push(backend->CreateFile(name, size)); |         rb.Push(backend->CreateFile(name, size)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void CreateDirectory(Kernel::HLERequestContext& ctx) { | ||||||
|  |         IPC::RequestParser rp{ctx}; | ||||||
|  | 
 | ||||||
|  |         auto file_buffer = ctx.ReadBuffer(); | ||||||
|  |         auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); | ||||||
|  | 
 | ||||||
|  |         std::string name(file_buffer.begin(), end); | ||||||
|  | 
 | ||||||
|  |         LOG_DEBUG(Service_FS, "called directory %s", name.c_str()); | ||||||
|  | 
 | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(backend->CreateDirectory(name)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     void OpenFile(Kernel::HLERequestContext& ctx) { |     void OpenFile(Kernel::HLERequestContext& ctx) { | ||||||
|         IPC::RequestParser rp{ctx}; |         IPC::RequestParser rp{ctx}; | ||||||
| 
 | 
 | ||||||
| @ -208,6 +275,33 @@ public: | |||||||
|         rb.PushIpcInterface<IFile>(std::move(file)); |         rb.PushIpcInterface<IFile>(std::move(file)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void OpenDirectory(Kernel::HLERequestContext& ctx) { | ||||||
|  |         IPC::RequestParser rp{ctx}; | ||||||
|  | 
 | ||||||
|  |         auto file_buffer = ctx.ReadBuffer(); | ||||||
|  |         auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); | ||||||
|  | 
 | ||||||
|  |         std::string name(file_buffer.begin(), end); | ||||||
|  | 
 | ||||||
|  |         // TODO(Subv): Implement this filter.
 | ||||||
|  |         u32 filter_flags = rp.Pop<u32>(); | ||||||
|  | 
 | ||||||
|  |         LOG_DEBUG(Service_FS, "called directory %s filter %u", name.c_str(), filter_flags); | ||||||
|  | 
 | ||||||
|  |         auto result = backend->OpenDirectory(name); | ||||||
|  |         if (result.Failed()) { | ||||||
|  |             IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |             rb.Push(result.Code()); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         auto directory = std::move(result.Unwrap()); | ||||||
|  | 
 | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|  |         rb.Push(RESULT_SUCCESS); | ||||||
|  |         rb.PushIpcInterface<IDirectory>(std::move(directory)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     void GetEntryType(Kernel::HLERequestContext& ctx) { |     void GetEntryType(Kernel::HLERequestContext& ctx) { | ||||||
|         IPC::RequestParser rp{ctx}; |         IPC::RequestParser rp{ctx}; | ||||||
| 
 | 
 | ||||||
| @ -274,10 +368,14 @@ void FSP_SRV::Initalize(Kernel::HLERequestContext& ctx) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { | void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { | ||||||
|     LOG_WARNING(Service_FS, "(STUBBED) called"); |     LOG_DEBUG(Service_FS, "called"); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     FileSys::Path unused; | ||||||
|  |     auto filesystem = OpenFileSystem(Type::SDMC, unused).Unwrap(); | ||||||
|  | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|  |     rb.PushIpcInterface<IFileSystem>(std::move(filesystem)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) { | void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei