diff options
Diffstat (limited to 'src/core/file_sys')
| -rw-r--r-- | src/core/file_sys/archive_savedata.cpp | 33 | ||||
| -rw-r--r-- | src/core/file_sys/archive_savedata.h | 32 | ||||
| -rw-r--r-- | src/core/file_sys/archive_sdmc.cpp | 83 | ||||
| -rw-r--r-- | src/core/file_sys/archive_sdmc.h | 66 | ||||
| -rw-r--r-- | src/core/file_sys/directory_sdmc.cpp | 88 | ||||
| -rw-r--r-- | src/core/file_sys/directory_sdmc.h | 55 | ||||
| -rw-r--r-- | src/core/file_sys/disk_archive.cpp | 167 | ||||
| -rw-r--r-- | src/core/file_sys/disk_archive.h | 101 | ||||
| -rw-r--r-- | src/core/file_sys/file_backend.h | 5 | ||||
| -rw-r--r-- | src/core/file_sys/file_romfs.h | 2 | ||||
| -rw-r--r-- | src/core/file_sys/file_sdmc.cpp | 110 | ||||
| -rw-r--r-- | src/core/file_sys/file_sdmc.h | 75 |
12 files changed, 344 insertions, 473 deletions
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp new file mode 100644 index 000000000..2414564e4 --- /dev/null +++ b/src/core/file_sys/archive_savedata.cpp | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2+ | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <sys/stat.h> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/archive_savedata.h" | ||
| 11 | #include "core/file_sys/disk_archive.h" | ||
| 12 | #include "core/settings.h" | ||
| 13 | |||
| 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 15 | // FileSys namespace | ||
| 16 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | Archive_SaveData::Archive_SaveData(const std::string& mount_point, u64 program_id) | ||
| 20 | : DiskArchive(mount_point + Common::StringFromFormat("%016X", program_id) + DIR_SEP) { | ||
| 21 | LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str()); | ||
| 22 | } | ||
| 23 | |||
| 24 | bool Archive_SaveData::Initialize() { | ||
| 25 | if (!FileUtil::CreateFullPath(mount_point)) { | ||
| 26 | LOG_ERROR(Service_FS, "Unable to create SaveData path."); | ||
| 27 | return false; | ||
| 28 | } | ||
| 29 | |||
| 30 | return true; | ||
| 31 | } | ||
| 32 | |||
| 33 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h new file mode 100644 index 000000000..b3e561130 --- /dev/null +++ b/src/core/file_sys/archive_savedata.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2+ | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | #include "core/file_sys/disk_archive.h" | ||
| 10 | #include "core/loader/loader.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // FileSys namespace | ||
| 14 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | /// File system interface to the SaveData archive | ||
| 18 | class Archive_SaveData final : public DiskArchive { | ||
| 19 | public: | ||
| 20 | Archive_SaveData(const std::string& mount_point, u64 program_id); | ||
| 21 | |||
| 22 | /** | ||
| 23 | * Initialize the archive. | ||
| 24 | * @return CreateSaveDataResult AlreadyExists if the SaveData folder already exists, | ||
| 25 | * Success if it was created properly and Failure if there was any error | ||
| 26 | */ | ||
| 27 | bool Initialize(); | ||
| 28 | |||
| 29 | std::string GetName() const override { return "SaveData"; } | ||
| 30 | }; | ||
| 31 | |||
| 32 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index 9d58668e0..dccdf7f67 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp | |||
| @@ -8,8 +8,7 @@ | |||
| 8 | #include "common/file_util.h" | 8 | #include "common/file_util.h" |
| 9 | 9 | ||
| 10 | #include "core/file_sys/archive_sdmc.h" | 10 | #include "core/file_sys/archive_sdmc.h" |
| 11 | #include "core/file_sys/directory_sdmc.h" | 11 | #include "core/file_sys/disk_archive.h" |
| 12 | #include "core/file_sys/file_sdmc.h" | ||
| 13 | #include "core/settings.h" | 12 | #include "core/settings.h" |
| 14 | 13 | ||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -17,18 +16,10 @@ | |||
| 17 | 16 | ||
| 18 | namespace FileSys { | 17 | namespace FileSys { |
| 19 | 18 | ||
| 20 | Archive_SDMC::Archive_SDMC(const std::string& mount_point) { | 19 | Archive_SDMC::Archive_SDMC(const std::string& mount_point) : DiskArchive(mount_point) { |
| 21 | this->mount_point = mount_point; | ||
| 22 | LOG_INFO(Service_FS, "Directory %s set as SDMC.", mount_point.c_str()); | 20 | LOG_INFO(Service_FS, "Directory %s set as SDMC.", mount_point.c_str()); |
| 23 | } | 21 | } |
| 24 | 22 | ||
| 25 | Archive_SDMC::~Archive_SDMC() { | ||
| 26 | } | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Initialize the archive. | ||
| 30 | * @return true if it initialized successfully | ||
| 31 | */ | ||
| 32 | bool Archive_SDMC::Initialize() { | 23 | bool Archive_SDMC::Initialize() { |
| 33 | if (!Settings::values.use_virtual_sd) { | 24 | if (!Settings::values.use_virtual_sd) { |
| 34 | LOG_WARNING(Service_FS, "SDMC disabled by config."); | 25 | LOG_WARNING(Service_FS, "SDMC disabled by config."); |
| @@ -43,74 +34,4 @@ bool Archive_SDMC::Initialize() { | |||
| 43 | return true; | 34 | return true; |
| 44 | } | 35 | } |
| 45 | 36 | ||
| 46 | /** | ||
| 47 | * Open a file specified by its path, using the specified mode | ||
| 48 | * @param path Path relative to the archive | ||
| 49 | * @param mode Mode to open the file with | ||
| 50 | * @return Opened file, or nullptr | ||
| 51 | */ | ||
| 52 | std::unique_ptr<FileBackend> Archive_SDMC::OpenFile(const Path& path, const Mode mode) const { | ||
| 53 | LOG_DEBUG(Service_FS, "called path=%s mode=%u", path.DebugStr().c_str(), mode.hex); | ||
| 54 | File_SDMC* file = new File_SDMC(this, path, mode); | ||
| 55 | if (!file->Open()) | ||
| 56 | return nullptr; | ||
| 57 | return std::unique_ptr<FileBackend>(file); | ||
| 58 | } | ||
| 59 | |||
| 60 | /** | ||
| 61 | * Delete a file specified by its path | ||
| 62 | * @param path Path relative to the archive | ||
| 63 | * @return Whether the file could be deleted | ||
| 64 | */ | ||
| 65 | bool Archive_SDMC::DeleteFile(const FileSys::Path& path) const { | ||
| 66 | return FileUtil::Delete(GetMountPoint() + path.AsString()); | ||
| 67 | } | ||
| 68 | |||
| 69 | bool Archive_SDMC::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const { | ||
| 70 | return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); | ||
| 71 | } | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Delete a directory specified by its path | ||
| 75 | * @param path Path relative to the archive | ||
| 76 | * @return Whether the directory could be deleted | ||
| 77 | */ | ||
| 78 | bool Archive_SDMC::DeleteDirectory(const FileSys::Path& path) const { | ||
| 79 | return FileUtil::DeleteDir(GetMountPoint() + path.AsString()); | ||
| 80 | } | ||
| 81 | |||
| 82 | /** | ||
| 83 | * Create a directory specified by its path | ||
| 84 | * @param path Path relative to the archive | ||
| 85 | * @return Whether the directory could be created | ||
| 86 | */ | ||
| 87 | bool Archive_SDMC::CreateDirectory(const Path& path) const { | ||
| 88 | return FileUtil::CreateDir(GetMountPoint() + path.AsString()); | ||
| 89 | } | ||
| 90 | |||
| 91 | bool Archive_SDMC::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const { | ||
| 92 | return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); | ||
| 93 | } | ||
| 94 | |||
| 95 | /** | ||
| 96 | * Open a directory specified by its path | ||
| 97 | * @param path Path relative to the archive | ||
| 98 | * @return Opened directory, or nullptr | ||
| 99 | */ | ||
| 100 | std::unique_ptr<DirectoryBackend> Archive_SDMC::OpenDirectory(const Path& path) const { | ||
| 101 | LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str()); | ||
| 102 | Directory_SDMC* directory = new Directory_SDMC(this, path); | ||
| 103 | if (!directory->Open()) | ||
| 104 | return nullptr; | ||
| 105 | return std::unique_ptr<DirectoryBackend>(directory); | ||
| 106 | } | ||
| 107 | |||
| 108 | /** | ||
| 109 | * Getter for the path used for this Archive | ||
| 110 | * @return Mount point of that passthrough archive | ||
| 111 | */ | ||
| 112 | std::string Archive_SDMC::GetMountPoint() const { | ||
| 113 | return mount_point; | ||
| 114 | } | ||
| 115 | |||
| 116 | } // namespace FileSys | 37 | } // namespace FileSys |
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 059045245..c84c6948e 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | 8 | ||
| 9 | #include "core/file_sys/archive_backend.h" | 9 | #include "core/file_sys/disk_archive.h" |
| 10 | #include "core/loader/loader.h" | 10 | #include "core/loader/loader.h" |
| 11 | 11 | ||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -15,10 +15,9 @@ | |||
| 15 | namespace FileSys { | 15 | namespace FileSys { |
| 16 | 16 | ||
| 17 | /// File system interface to the SDMC archive | 17 | /// File system interface to the SDMC archive |
| 18 | class Archive_SDMC final : public ArchiveBackend { | 18 | class Archive_SDMC final : public DiskArchive { |
| 19 | public: | 19 | public: |
| 20 | Archive_SDMC(const std::string& mount_point); | 20 | Archive_SDMC(const std::string& mount_point); |
| 21 | ~Archive_SDMC() override; | ||
| 22 | 21 | ||
| 23 | /** | 22 | /** |
| 24 | * Initialize the archive. | 23 | * Initialize the archive. |
| @@ -27,67 +26,6 @@ public: | |||
| 27 | bool Initialize(); | 26 | bool Initialize(); |
| 28 | 27 | ||
| 29 | std::string GetName() const override { return "SDMC"; } | 28 | std::string GetName() const override { return "SDMC"; } |
| 30 | |||
| 31 | /** | ||
| 32 | * Open a file specified by its path, using the specified mode | ||
| 33 | * @param path Path relative to the archive | ||
| 34 | * @param mode Mode to open the file with | ||
| 35 | * @return Opened file, or nullptr | ||
| 36 | */ | ||
| 37 | std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; | ||
| 38 | |||
| 39 | /** | ||
| 40 | * Delete a file specified by its path | ||
| 41 | * @param path Path relative to the archive | ||
| 42 | * @return Whether the file could be deleted | ||
| 43 | */ | ||
| 44 | bool DeleteFile(const FileSys::Path& path) const override; | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Rename a File specified by its path | ||
| 48 | * @param src_path Source path relative to the archive | ||
| 49 | * @param dest_path Destination path relative to the archive | ||
| 50 | * @return Whether rename succeeded | ||
| 51 | */ | ||
| 52 | bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; | ||
| 53 | |||
| 54 | /** | ||
| 55 | * Delete a directory specified by its path | ||
| 56 | * @param path Path relative to the archive | ||
| 57 | * @return Whether the directory could be deleted | ||
| 58 | */ | ||
| 59 | bool DeleteDirectory(const FileSys::Path& path) const override; | ||
| 60 | |||
| 61 | /** | ||
| 62 | * Create a directory specified by its path | ||
| 63 | * @param path Path relative to the archive | ||
| 64 | * @return Whether the directory could be created | ||
| 65 | */ | ||
| 66 | bool CreateDirectory(const Path& path) const override; | ||
| 67 | |||
| 68 | /** | ||
| 69 | * Rename a Directory specified by its path | ||
| 70 | * @param src_path Source path relative to the archive | ||
| 71 | * @param dest_path Destination path relative to the archive | ||
| 72 | * @return Whether rename succeeded | ||
| 73 | */ | ||
| 74 | bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; | ||
| 75 | |||
| 76 | /** | ||
| 77 | * Open a directory specified by its path | ||
| 78 | * @param path Path relative to the archive | ||
| 79 | * @return Opened directory, or nullptr | ||
| 80 | */ | ||
| 81 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | ||
| 82 | |||
| 83 | /** | ||
| 84 | * Getter for the path used for this Archive | ||
| 85 | * @return Mount point of that passthrough archive | ||
| 86 | */ | ||
| 87 | std::string GetMountPoint() const; | ||
| 88 | |||
| 89 | private: | ||
| 90 | std::string mount_point; | ||
| 91 | }; | 29 | }; |
| 92 | 30 | ||
| 93 | } // namespace FileSys | 31 | } // namespace FileSys |
diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp deleted file mode 100644 index 519787641..000000000 --- a/src/core/file_sys/directory_sdmc.cpp +++ /dev/null | |||
| @@ -1,88 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <sys/stat.h> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/directory_sdmc.h" | ||
| 11 | #include "core/file_sys/archive_sdmc.h" | ||
| 12 | |||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 14 | // FileSys namespace | ||
| 15 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const Path& path) { | ||
| 19 | // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass | ||
| 20 | // the root directory we set while opening the archive. | ||
| 21 | // For example, opening /../../usr/bin can give the emulated program your installed programs. | ||
| 22 | this->path = archive->GetMountPoint() + path.AsString(); | ||
| 23 | |||
| 24 | } | ||
| 25 | |||
| 26 | Directory_SDMC::~Directory_SDMC() { | ||
| 27 | Close(); | ||
| 28 | } | ||
| 29 | |||
| 30 | bool Directory_SDMC::Open() { | ||
| 31 | if (!FileUtil::IsDirectory(path)) | ||
| 32 | return false; | ||
| 33 | FileUtil::ScanDirectoryTree(path, directory); | ||
| 34 | children_iterator = directory.children.begin(); | ||
| 35 | return true; | ||
| 36 | } | ||
| 37 | |||
| 38 | /** | ||
| 39 | * List files contained in the directory | ||
| 40 | * @param count Number of entries to return at once in entries | ||
| 41 | * @param entries Buffer to read data into | ||
| 42 | * @return Number of entries listed | ||
| 43 | */ | ||
| 44 | u32 Directory_SDMC::Read(const u32 count, Entry* entries) { | ||
| 45 | u32 entries_read = 0; | ||
| 46 | |||
| 47 | while (entries_read < count && children_iterator != directory.children.cend()) { | ||
| 48 | const FileUtil::FSTEntry& file = *children_iterator; | ||
| 49 | const std::string& filename = file.virtualName; | ||
| 50 | Entry& entry = entries[entries_read]; | ||
| 51 | |||
| 52 | LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory); | ||
| 53 | |||
| 54 | // TODO(Link Mauve): use a proper conversion to UTF-16. | ||
| 55 | for (size_t j = 0; j < FILENAME_LENGTH; ++j) { | ||
| 56 | entry.filename[j] = filename[j]; | ||
| 57 | if (!filename[j]) | ||
| 58 | break; | ||
| 59 | } | ||
| 60 | |||
| 61 | FileUtil::SplitFilename83(filename, entry.short_name, entry.extension); | ||
| 62 | |||
| 63 | entry.is_directory = file.isDirectory; | ||
| 64 | entry.is_hidden = (filename[0] == '.'); | ||
| 65 | entry.is_read_only = 0; | ||
| 66 | entry.file_size = file.size; | ||
| 67 | |||
| 68 | // We emulate a SD card where the archive bit has never been cleared, as it would be on | ||
| 69 | // most user SD cards. | ||
| 70 | // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a | ||
| 71 | // file bit. | ||
| 72 | entry.is_archive = !file.isDirectory; | ||
| 73 | |||
| 74 | ++entries_read; | ||
| 75 | ++children_iterator; | ||
| 76 | } | ||
| 77 | return entries_read; | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * Close the directory | ||
| 82 | * @return true if the directory closed correctly | ||
| 83 | */ | ||
| 84 | bool Directory_SDMC::Close() const { | ||
| 85 | return true; | ||
| 86 | } | ||
| 87 | |||
| 88 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h deleted file mode 100644 index 407a256ef..000000000 --- a/src/core/file_sys/directory_sdmc.h +++ /dev/null | |||
| @@ -1,55 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/directory_backend.h" | ||
| 11 | #include "core/file_sys/archive_sdmc.h" | ||
| 12 | #include "core/loader/loader.h" | ||
| 13 | |||
| 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 15 | // FileSys namespace | ||
| 16 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | class Directory_SDMC final : public DirectoryBackend { | ||
| 20 | public: | ||
| 21 | Directory_SDMC(); | ||
| 22 | Directory_SDMC(const Archive_SDMC* archive, const Path& path); | ||
| 23 | ~Directory_SDMC() override; | ||
| 24 | |||
| 25 | /** | ||
| 26 | * Open the directory | ||
| 27 | * @return true if the directory opened correctly | ||
| 28 | */ | ||
| 29 | bool Open() override; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * List files contained in the directory | ||
| 33 | * @param count Number of entries to return at once in entries | ||
| 34 | * @param entries Buffer to read data into | ||
| 35 | * @return Number of entries listed | ||
| 36 | */ | ||
| 37 | u32 Read(const u32 count, Entry* entries) override; | ||
| 38 | |||
| 39 | /** | ||
| 40 | * Close the directory | ||
| 41 | * @return true if the directory closed correctly | ||
| 42 | */ | ||
| 43 | bool Close() const override; | ||
| 44 | |||
| 45 | private: | ||
| 46 | std::string path; | ||
| 47 | u32 total_entries_in_directory; | ||
| 48 | FileUtil::FSTEntry directory; | ||
| 49 | |||
| 50 | // We need to remember the last entry we returned, so a subsequent call to Read will continue | ||
| 51 | // from the next one. This iterator will always point to the next unread entry. | ||
| 52 | std::vector<FileUtil::FSTEntry>::iterator children_iterator; | ||
| 53 | }; | ||
| 54 | |||
| 55 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp new file mode 100644 index 000000000..eabf58057 --- /dev/null +++ b/src/core/file_sys/disk_archive.cpp | |||
| @@ -0,0 +1,167 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <sys/stat.h> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/disk_archive.h" | ||
| 11 | #include "core/settings.h" | ||
| 12 | |||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 14 | // FileSys namespace | ||
| 15 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | std::unique_ptr<FileBackend> DiskArchive::OpenFile(const Path& path, const Mode mode) const { | ||
| 19 | LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex); | ||
| 20 | DiskFile* file = new DiskFile(this, path, mode); | ||
| 21 | if (!file->Open()) | ||
| 22 | return nullptr; | ||
| 23 | return std::unique_ptr<FileBackend>(file); | ||
| 24 | } | ||
| 25 | |||
| 26 | bool DiskArchive::DeleteFile(const FileSys::Path& path) const { | ||
| 27 | return FileUtil::Delete(GetMountPoint() + path.AsString()); | ||
| 28 | } | ||
| 29 | |||
| 30 | bool DiskArchive::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const { | ||
| 31 | return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); | ||
| 32 | } | ||
| 33 | |||
| 34 | bool DiskArchive::DeleteDirectory(const FileSys::Path& path) const { | ||
| 35 | return FileUtil::DeleteDir(GetMountPoint() + path.AsString()); | ||
| 36 | } | ||
| 37 | |||
| 38 | bool DiskArchive::CreateDirectory(const Path& path) const { | ||
| 39 | return FileUtil::CreateDir(GetMountPoint() + path.AsString()); | ||
| 40 | } | ||
| 41 | |||
| 42 | bool DiskArchive::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const { | ||
| 43 | return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); | ||
| 44 | } | ||
| 45 | |||
| 46 | std::unique_ptr<DirectoryBackend> DiskArchive::OpenDirectory(const Path& path) const { | ||
| 47 | LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str()); | ||
| 48 | DiskDirectory* directory = new DiskDirectory(this, path); | ||
| 49 | if (!directory->Open()) | ||
| 50 | return nullptr; | ||
| 51 | return std::unique_ptr<DirectoryBackend>(directory); | ||
| 52 | } | ||
| 53 | |||
| 54 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 55 | |||
| 56 | DiskFile::DiskFile(const DiskArchive* archive, const Path& path, const Mode mode) { | ||
| 57 | // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass | ||
| 58 | // the root directory we set while opening the archive. | ||
| 59 | // For example, opening /../../etc/passwd can give the emulated program your users list. | ||
| 60 | this->path = archive->GetMountPoint() + path.AsString(); | ||
| 61 | this->mode.hex = mode.hex; | ||
| 62 | this->archive = archive; | ||
| 63 | } | ||
| 64 | |||
| 65 | bool DiskFile::Open() { | ||
| 66 | if (!mode.create_flag && !FileUtil::Exists(path)) { | ||
| 67 | LOG_ERROR(Service_FS, "Non-existing file %s can’t be open without mode create.", path.c_str()); | ||
| 68 | return false; | ||
| 69 | } | ||
| 70 | |||
| 71 | std::string mode_string; | ||
| 72 | if (mode.create_flag) | ||
| 73 | mode_string = "w+"; | ||
| 74 | else if (mode.write_flag) | ||
| 75 | mode_string = "r+"; // Files opened with Write access can be read from | ||
| 76 | else if (mode.read_flag) | ||
| 77 | mode_string = "r"; | ||
| 78 | |||
| 79 | // Open the file in binary mode, to avoid problems with CR/LF on Windows systems | ||
| 80 | mode_string += "b"; | ||
| 81 | |||
| 82 | file = new FileUtil::IOFile(path, mode_string.c_str()); | ||
| 83 | return true; | ||
| 84 | } | ||
| 85 | |||
| 86 | size_t DiskFile::Read(const u64 offset, const u32 length, u8* buffer) const { | ||
| 87 | file->Seek(offset, SEEK_SET); | ||
| 88 | return file->ReadBytes(buffer, length); | ||
| 89 | } | ||
| 90 | |||
| 91 | size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { | ||
| 92 | file->Seek(offset, SEEK_SET); | ||
| 93 | size_t written = file->WriteBytes(buffer, length); | ||
| 94 | if (flush) | ||
| 95 | file->Flush(); | ||
| 96 | return written; | ||
| 97 | } | ||
| 98 | |||
| 99 | size_t DiskFile::GetSize() const { | ||
| 100 | return static_cast<size_t>(file->GetSize()); | ||
| 101 | } | ||
| 102 | |||
| 103 | bool DiskFile::SetSize(const u64 size) const { | ||
| 104 | file->Resize(size); | ||
| 105 | file->Flush(); | ||
| 106 | return true; | ||
| 107 | } | ||
| 108 | |||
| 109 | bool DiskFile::Close() const { | ||
| 110 | return file->Close(); | ||
| 111 | } | ||
| 112 | |||
| 113 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 114 | |||
| 115 | DiskDirectory::DiskDirectory(const DiskArchive* archive, const Path& path) { | ||
| 116 | // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass | ||
| 117 | // the root directory we set while opening the archive. | ||
| 118 | // For example, opening /../../usr/bin can give the emulated program your installed programs. | ||
| 119 | this->path = archive->GetMountPoint() + path.AsString(); | ||
| 120 | this->archive = archive; | ||
| 121 | } | ||
| 122 | |||
| 123 | bool DiskDirectory::Open() { | ||
| 124 | if (!FileUtil::IsDirectory(path)) | ||
| 125 | return false; | ||
| 126 | FileUtil::ScanDirectoryTree(path, directory); | ||
| 127 | children_iterator = directory.children.begin(); | ||
| 128 | return true; | ||
| 129 | } | ||
| 130 | |||
| 131 | u32 DiskDirectory::Read(const u32 count, Entry* entries) { | ||
| 132 | u32 entries_read = 0; | ||
| 133 | |||
| 134 | while (entries_read < count && children_iterator != directory.children.cend()) { | ||
| 135 | const FileUtil::FSTEntry& file = *children_iterator; | ||
| 136 | const std::string& filename = file.virtualName; | ||
| 137 | Entry& entry = entries[entries_read]; | ||
| 138 | |||
| 139 | LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory); | ||
| 140 | |||
| 141 | // TODO(Link Mauve): use a proper conversion to UTF-16. | ||
| 142 | for (size_t j = 0; j < FILENAME_LENGTH; ++j) { | ||
| 143 | entry.filename[j] = filename[j]; | ||
| 144 | if (!filename[j]) | ||
| 145 | break; | ||
| 146 | } | ||
| 147 | |||
| 148 | FileUtil::SplitFilename83(filename, entry.short_name, entry.extension); | ||
| 149 | |||
| 150 | entry.is_directory = file.isDirectory; | ||
| 151 | entry.is_hidden = (filename[0] == '.'); | ||
| 152 | entry.is_read_only = 0; | ||
| 153 | entry.file_size = file.size; | ||
| 154 | |||
| 155 | // We emulate a SD card where the archive bit has never been cleared, as it would be on | ||
| 156 | // most user SD cards. | ||
| 157 | // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a | ||
| 158 | // file bit. | ||
| 159 | entry.is_archive = !file.isDirectory; | ||
| 160 | |||
| 161 | ++entries_read; | ||
| 162 | ++children_iterator; | ||
| 163 | } | ||
| 164 | return entries_read; | ||
| 165 | } | ||
| 166 | |||
| 167 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h new file mode 100644 index 000000000..778c83953 --- /dev/null +++ b/src/core/file_sys/disk_archive.h | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | #include "core/file_sys/archive_backend.h" | ||
| 10 | #include "core/loader/loader.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // FileSys namespace | ||
| 14 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | /** | ||
| 18 | * Helper which implements a backend accessing the host machine's filesystem. | ||
| 19 | * This should be subclassed by concrete archive types, which will provide the | ||
| 20 | * base directory on the host filesystem and override any required functionality. | ||
| 21 | */ | ||
| 22 | class DiskArchive : public ArchiveBackend { | ||
| 23 | public: | ||
| 24 | DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {} | ||
| 25 | |||
| 26 | virtual std::string GetName() const = 0; | ||
| 27 | std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; | ||
| 28 | bool DeleteFile(const FileSys::Path& path) const override; | ||
| 29 | bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; | ||
| 30 | bool DeleteDirectory(const FileSys::Path& path) const override; | ||
| 31 | bool CreateDirectory(const Path& path) const override; | ||
| 32 | bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; | ||
| 33 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * Getter for the path used for this Archive | ||
| 37 | * @return Mount point of that passthrough archive | ||
| 38 | */ | ||
| 39 | const std::string& GetMountPoint() const { | ||
| 40 | return mount_point; | ||
| 41 | } | ||
| 42 | |||
| 43 | protected: | ||
| 44 | std::string mount_point; | ||
| 45 | }; | ||
| 46 | |||
| 47 | class DiskFile : public FileBackend { | ||
| 48 | public: | ||
| 49 | DiskFile(); | ||
| 50 | DiskFile(const DiskArchive* archive, const Path& path, const Mode mode); | ||
| 51 | |||
| 52 | ~DiskFile() override { | ||
| 53 | Close(); | ||
| 54 | } | ||
| 55 | |||
| 56 | bool Open() override; | ||
| 57 | size_t Read(const u64 offset, const u32 length, u8* buffer) const override; | ||
| 58 | size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; | ||
| 59 | size_t GetSize() const override; | ||
| 60 | bool SetSize(const u64 size) const override; | ||
| 61 | bool Close() const override; | ||
| 62 | |||
| 63 | void Flush() const override { | ||
| 64 | file->Flush(); | ||
| 65 | } | ||
| 66 | |||
| 67 | protected: | ||
| 68 | const DiskArchive* archive; | ||
| 69 | std::string path; | ||
| 70 | Mode mode; | ||
| 71 | FileUtil::IOFile* file; | ||
| 72 | }; | ||
| 73 | |||
| 74 | class DiskDirectory : public DirectoryBackend { | ||
| 75 | public: | ||
| 76 | DiskDirectory(); | ||
| 77 | DiskDirectory(const DiskArchive* archive, const Path& path); | ||
| 78 | |||
| 79 | ~DiskDirectory() override { | ||
| 80 | Close(); | ||
| 81 | } | ||
| 82 | |||
| 83 | bool Open() override; | ||
| 84 | u32 Read(const u32 count, Entry* entries) override; | ||
| 85 | |||
| 86 | bool Close() const override { | ||
| 87 | return true; | ||
| 88 | } | ||
| 89 | |||
| 90 | protected: | ||
| 91 | const DiskArchive* archive; | ||
| 92 | std::string path; | ||
| 93 | u32 total_entries_in_directory; | ||
| 94 | FileUtil::FSTEntry directory; | ||
| 95 | |||
| 96 | // We need to remember the last entry we returned, so a subsequent call to Read will continue | ||
| 97 | // from the next one. This iterator will always point to the next unread entry. | ||
| 98 | std::vector<FileUtil::FSTEntry>::iterator children_iterator; | ||
| 99 | }; | ||
| 100 | |||
| 101 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h index 1b81d5fe9..539ec7314 100644 --- a/src/core/file_sys/file_backend.h +++ b/src/core/file_sys/file_backend.h | |||
| @@ -61,6 +61,11 @@ public: | |||
| 61 | * @return true if the file closed correctly | 61 | * @return true if the file closed correctly |
| 62 | */ | 62 | */ |
| 63 | virtual bool Close() const = 0; | 63 | virtual bool Close() const = 0; |
| 64 | |||
| 65 | /** | ||
| 66 | * Flushes the file | ||
| 67 | */ | ||
| 68 | virtual void Flush() const = 0; | ||
| 64 | }; | 69 | }; |
| 65 | 70 | ||
| 66 | } // namespace FileSys | 71 | } // namespace FileSys |
diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h index 09fa2e7e3..32fa6b6d3 100644 --- a/src/core/file_sys/file_romfs.h +++ b/src/core/file_sys/file_romfs.h | |||
| @@ -64,6 +64,8 @@ public: | |||
| 64 | */ | 64 | */ |
| 65 | bool Close() const override; | 65 | bool Close() const override; |
| 66 | 66 | ||
| 67 | void Flush() const override { } | ||
| 68 | |||
| 67 | private: | 69 | private: |
| 68 | const Archive_RomFS* archive; | 70 | const Archive_RomFS* archive; |
| 69 | }; | 71 | }; |
diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp deleted file mode 100644 index 46c29900b..000000000 --- a/src/core/file_sys/file_sdmc.cpp +++ /dev/null | |||
| @@ -1,110 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <sys/stat.h> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/file_sdmc.h" | ||
| 11 | #include "core/file_sys/archive_sdmc.h" | ||
| 12 | |||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 14 | // FileSys namespace | ||
| 15 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | File_SDMC::File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode) { | ||
| 19 | // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass | ||
| 20 | // the root directory we set while opening the archive. | ||
| 21 | // For example, opening /../../etc/passwd can give the emulated program your users list. | ||
| 22 | this->path = archive->GetMountPoint() + path.AsString(); | ||
| 23 | this->mode.hex = mode.hex; | ||
| 24 | } | ||
| 25 | |||
| 26 | File_SDMC::~File_SDMC() { | ||
| 27 | Close(); | ||
| 28 | } | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Open the file | ||
| 32 | * @return true if the file opened correctly | ||
| 33 | */ | ||
| 34 | bool File_SDMC::Open() { | ||
| 35 | if (!mode.create_flag && !FileUtil::Exists(path)) { | ||
| 36 | LOG_ERROR(Service_FS, "Non-existing file %s can’t be open without mode create.", path.c_str()); | ||
| 37 | return false; | ||
| 38 | } | ||
| 39 | |||
| 40 | std::string mode_string; | ||
| 41 | if (mode.create_flag) | ||
| 42 | mode_string = "w+"; | ||
| 43 | else if (mode.write_flag) | ||
| 44 | mode_string = "r+"; // Files opened with Write access can be read from | ||
| 45 | else if (mode.read_flag) | ||
| 46 | mode_string = "r"; | ||
| 47 | |||
| 48 | // Open the file in binary mode, to avoid problems with CR/LF on Windows systems | ||
| 49 | mode_string += "b"; | ||
| 50 | |||
| 51 | file = new FileUtil::IOFile(path, mode_string.c_str()); | ||
| 52 | return true; | ||
| 53 | } | ||
| 54 | |||
| 55 | /** | ||
| 56 | * Read data from the file | ||
| 57 | * @param offset Offset in bytes to start reading data from | ||
| 58 | * @param length Length in bytes of data to read from file | ||
| 59 | * @param buffer Buffer to read data into | ||
| 60 | * @return Number of bytes read | ||
| 61 | */ | ||
| 62 | size_t File_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { | ||
| 63 | file->Seek(offset, SEEK_SET); | ||
| 64 | return file->ReadBytes(buffer, length); | ||
| 65 | } | ||
| 66 | |||
| 67 | /** | ||
| 68 | * Write data to the file | ||
| 69 | * @param offset Offset in bytes to start writing data to | ||
| 70 | * @param length Length in bytes of data to write to file | ||
| 71 | * @param flush The flush parameters (0 == do not flush) | ||
| 72 | * @param buffer Buffer to read data from | ||
| 73 | * @return Number of bytes written | ||
| 74 | */ | ||
| 75 | size_t File_SDMC::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { | ||
| 76 | file->Seek(offset, SEEK_SET); | ||
| 77 | size_t written = file->WriteBytes(buffer, length); | ||
| 78 | if (flush) | ||
| 79 | file->Flush(); | ||
| 80 | return written; | ||
| 81 | } | ||
| 82 | |||
| 83 | /** | ||
| 84 | * Get the size of the file in bytes | ||
| 85 | * @return Size of the file in bytes | ||
| 86 | */ | ||
| 87 | size_t File_SDMC::GetSize() const { | ||
| 88 | return static_cast<size_t>(file->GetSize()); | ||
| 89 | } | ||
| 90 | |||
| 91 | /** | ||
| 92 | * Set the size of the file in bytes | ||
| 93 | * @param size New size of the file | ||
| 94 | * @return true if successful | ||
| 95 | */ | ||
| 96 | bool File_SDMC::SetSize(const u64 size) const { | ||
| 97 | file->Resize(size); | ||
| 98 | file->Flush(); | ||
| 99 | return true; | ||
| 100 | } | ||
| 101 | |||
| 102 | /** | ||
| 103 | * Close the file | ||
| 104 | * @return true if the file closed correctly | ||
| 105 | */ | ||
| 106 | bool File_SDMC::Close() const { | ||
| 107 | return file->Close(); | ||
| 108 | } | ||
| 109 | |||
| 110 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/file_sdmc.h b/src/core/file_sys/file_sdmc.h deleted file mode 100644 index e01548598..000000000 --- a/src/core/file_sys/file_sdmc.h +++ /dev/null | |||
| @@ -1,75 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/file_backend.h" | ||
| 11 | #include "core/file_sys/archive_sdmc.h" | ||
| 12 | #include "core/loader/loader.h" | ||
| 13 | |||
| 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 15 | // FileSys namespace | ||
| 16 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | class File_SDMC final : public FileBackend { | ||
| 20 | public: | ||
| 21 | File_SDMC(); | ||
| 22 | File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode); | ||
| 23 | ~File_SDMC() override; | ||
| 24 | |||
| 25 | /** | ||
| 26 | * Open the file | ||
| 27 | * @return true if the file opened correctly | ||
| 28 | */ | ||
| 29 | bool Open() override; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Read data from the file | ||
| 33 | * @param offset Offset in bytes to start reading data from | ||
| 34 | * @param length Length in bytes of data to read from file | ||
| 35 | * @param buffer Buffer to read data into | ||
| 36 | * @return Number of bytes read | ||
| 37 | */ | ||
| 38 | size_t Read(const u64 offset, const u32 length, u8* buffer) const override; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Write data to the file | ||
| 42 | * @param offset Offset in bytes to start writing data to | ||
| 43 | * @param length Length in bytes of data to write to file | ||
| 44 | * @param flush The flush parameters (0 == do not flush) | ||
| 45 | * @param buffer Buffer to read data from | ||
| 46 | * @return Number of bytes written | ||
| 47 | */ | ||
| 48 | size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; | ||
| 49 | |||
| 50 | /** | ||
| 51 | * Get the size of the file in bytes | ||
| 52 | * @return Size of the file in bytes | ||
| 53 | */ | ||
| 54 | size_t GetSize() const override; | ||
| 55 | |||
| 56 | /** | ||
| 57 | * Set the size of the file in bytes | ||
| 58 | * @param size New size of the file | ||
| 59 | * @return true if successful | ||
| 60 | */ | ||
| 61 | bool SetSize(const u64 size) const override; | ||
| 62 | |||
| 63 | /** | ||
| 64 | * Close the file | ||
| 65 | * @return true if the file closed correctly | ||
| 66 | */ | ||
| 67 | bool Close() const override; | ||
| 68 | |||
| 69 | private: | ||
| 70 | std::string path; | ||
| 71 | Mode mode; | ||
| 72 | FileUtil::IOFile* file; | ||
| 73 | }; | ||
| 74 | |||
| 75 | } // namespace FileSys | ||