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/savedata_factory.cpp | ||||
|     file_sys/savedata_factory.h | ||||
|     file_sys/sdmc_factory.cpp | ||||
|     file_sys/sdmc_factory.h | ||||
|     file_sys/storage.h | ||||
|     frontend/emu_window.cpp | ||||
|     frontend/emu_window.h | ||||
|  | ||||
| @ -6,34 +6,28 @@ | ||||
| 
 | ||||
| #include <array> | ||||
| #include <cstddef> | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| #include "core/file_sys/filesystem.h" | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| // FileSys namespace
 | ||||
| 
 | ||||
| namespace FileSys { | ||||
| 
 | ||||
| // Structure of a directory entry, from http://3dbrew.org/wiki/FSDir:Read#Entry_format
 | ||||
| const size_t FILENAME_LENGTH = 0x20C / 2; | ||||
| // Structure of a directory entry, from
 | ||||
| // http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry
 | ||||
| const size_t FILENAME_LENGTH = 0x300; | ||||
| struct Entry { | ||||
|     char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated)
 | ||||
|     std::array<char, 9> short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated)
 | ||||
|     char unknown1;                  // unknown (observed values: 0x0A, 0x70, 0xFD)
 | ||||
|     std::array<char, 4> | ||||
|         extension;     // 8.3 file extension (set to spaces for directories, null-terminated)
 | ||||
|     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)
 | ||||
|     char filename[FILENAME_LENGTH]; | ||||
|     INSERT_PADDING_BYTES(4); | ||||
|     EntryType type; | ||||
|     INSERT_PADDING_BYTES(3); | ||||
|     u64 file_size; | ||||
| }; | ||||
| static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!"); | ||||
| static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry."); | ||||
| static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension 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."); | ||||
| static_assert(sizeof(Entry) == 0x310, "Directory Entry struct isn't exactly 0x310 bytes long!"); | ||||
| static_assert(offsetof(Entry, type) == 0x304, "Wrong offset for type in Entry."); | ||||
| static_assert(offsetof(Entry, file_size) == 0x308, "Wrong offset for file_size in Entry."); | ||||
| 
 | ||||
| class DirectoryBackend : NonCopyable { | ||||
| public: | ||||
| @ -46,7 +40,10 @@ public: | ||||
|      * @param entries Buffer to read data into | ||||
|      * @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 | ||||
|  | ||||
| @ -11,16 +11,43 @@ | ||||
| 
 | ||||
| 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 { | ||||
|     return "Disk"; | ||||
| } | ||||
| 
 | ||||
| ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::string& path, | ||||
|                                                                      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; | ||||
|     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()) { | ||||
|         return ERROR_PATH_NOT_FOUND; | ||||
| @ -75,8 +102,15 @@ ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const | ||||
|     return ResultCode(-1); | ||||
| } | ||||
| 
 | ||||
| ResultCode Disk_FileSystem::CreateDirectory(const Path& path) const { | ||||
|     LOG_WARNING(Service_FS, "(STUBBED) called"); | ||||
| ResultCode Disk_FileSystem::CreateDirectory(const std::string& path) const { | ||||
|     // 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
 | ||||
|     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( | ||||
|     const Path& path) const { | ||||
|     return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<Disk_Directory>()); | ||||
|     const std::string& path) const { | ||||
| 
 | ||||
|     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 { | ||||
| @ -103,8 +146,10 @@ ResultVal<FileSys::EntryType> Disk_FileSystem::GetEntryType(const std::string& p | ||||
|         return ERROR_PATH_NOT_FOUND; | ||||
|     } | ||||
| 
 | ||||
|     // TODO(Subv): Find out the EntryType values
 | ||||
|     UNIMPLEMENTED_MSG("Unimplemented GetEntryType"); | ||||
|     if (FileUtil::IsDirectory(full_path)) | ||||
|         return MakeResult(EntryType::Directory); | ||||
| 
 | ||||
|     return MakeResult(EntryType::File); | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
| 
 | ||||
| u32 Disk_Directory::Read(const u32 count, Entry* entries) { | ||||
|     LOG_WARNING(Service_FS, "(STUBBED) called"); | ||||
|     return 0; | ||||
| Disk_Directory::Disk_Directory(const std::string& path) : directory() { | ||||
|     unsigned size = FileUtil::ScanDirectoryTree(path, directory); | ||||
|     directory.size = size; | ||||
|     directory.isDirectory = true; | ||||
|     children_iterator = directory.children.begin(); | ||||
| } | ||||
| 
 | ||||
| bool Disk_Directory::Close() const { | ||||
|     LOG_WARNING(Service_FS, "(STUBBED) called"); | ||||
|     return true; | ||||
| u64 Disk_Directory::Read(const u64 count, Entry* entries) { | ||||
|     u64 entries_read = 0; | ||||
| 
 | ||||
|     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
 | ||||
|  | ||||
| @ -30,9 +30,10 @@ public: | ||||
|     ResultCode DeleteDirectory(const Path& path) const override; | ||||
|     ResultCode DeleteDirectoryRecursively(const Path& path) 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; | ||||
|     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; | ||||
|     ResultVal<EntryType> GetEntryType(const std::string& path) const override; | ||||
| 
 | ||||
| @ -59,8 +60,26 @@ private: | ||||
| 
 | ||||
| class Disk_Directory : public DirectoryBackend { | ||||
| public: | ||||
|     u32 Read(const u32 count, Entry* entries) override; | ||||
|     bool Close() const override; | ||||
|     Disk_Directory(const std::string& path); | ||||
| 
 | ||||
|     ~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
 | ||||
|  | ||||
| @ -27,7 +27,7 @@ enum LowPathType : u32 { | ||||
|     Wchar = 4, | ||||
| }; | ||||
| 
 | ||||
| enum EntryType : u32 { | ||||
| enum EntryType : u8 { | ||||
|     Directory = 0, | ||||
|     File = 1, | ||||
| }; | ||||
| @ -35,6 +35,7 @@ enum EntryType : u32 { | ||||
| enum class Mode : u32 { | ||||
|     Read = 1, | ||||
|     Write = 2, | ||||
|     Append = 4, | ||||
| }; | ||||
| 
 | ||||
| class Path { | ||||
| @ -103,7 +104,7 @@ public: | ||||
|      * @param path Path relative to the archive | ||||
|      * @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 | ||||
| @ -149,7 +150,8 @@ public: | ||||
|      * @param path Path relative to the archive | ||||
|      * @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 | ||||
|  | ||||
| @ -55,7 +55,7 @@ ResultCode RomFS_FileSystem::CreateFile(const std::string& path, u64 size) const | ||||
|     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).", | ||||
|                  GetName().c_str()); | ||||
|     // 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( | ||||
|     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>()); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -36,9 +36,10 @@ public: | ||||
|     ResultCode DeleteDirectory(const Path& path) const override; | ||||
|     ResultCode DeleteDirectoryRecursively(const Path& path) 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; | ||||
|     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; | ||||
|     ResultVal<EntryType> GetEntryType(const std::string& path) const override; | ||||
| 
 | ||||
| @ -70,7 +71,10 @@ private: | ||||
| 
 | ||||
| class ROMFSDirectory : public DirectoryBackend { | ||||
| 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; | ||||
|     } | ||||
|     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 "core/file_sys/filesystem.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/fsp_srv.h" | ||||
| 
 | ||||
| @ -60,9 +61,13 @@ void RegisterFileSystems() { | ||||
|     filesystem_map.clear(); | ||||
| 
 | ||||
|     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)); | ||||
|     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) { | ||||
|  | ||||
| @ -26,6 +26,7 @@ namespace FileSystem { | ||||
| enum class Type { | ||||
|     RomFS = 1, | ||||
|     SaveData = 2, | ||||
|     SDMC = 3, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include <cinttypes> | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #include "core/file_sys/directory.h" | ||||
| #include "core/file_sys/filesystem.h" | ||||
| #include "core/file_sys/storage.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> { | ||||
| public: | ||||
|     explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend) | ||||
|         : ServiceFramework("IFileSystem"), backend(std::move(backend)) { | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IFileSystem::CreateFile, "CreateFile"}, | ||||
|             {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, | ||||
|             {7, &IFileSystem::GetEntryType, "GetEntryType"}, | ||||
|             {8, &IFileSystem::OpenFile, "OpenFile"}, | ||||
|             {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, | ||||
|             {10, &IFileSystem::Commit, "Commit"}, | ||||
|         }; | ||||
|         RegisterHandlers(functions); | ||||
| @ -182,6 +235,20 @@ public: | ||||
|         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) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
| @ -208,6 +275,33 @@ public: | ||||
|         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) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
| @ -274,10 +368,14 @@ void FSP_SRV::Initalize(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.PushIpcInterface<IFileSystem>(std::move(filesystem)); | ||||
| } | ||||
| 
 | ||||
| void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei