diff options
Diffstat (limited to 'src/core/file_sys')
-rw-r--r-- | src/core/file_sys/archive.h | 28 | ||||
-rw-r--r-- | src/core/file_sys/archive_romfs.cpp | 21 | ||||
-rw-r--r-- | src/core/file_sys/archive_romfs.h | 15 | ||||
-rw-r--r-- | src/core/file_sys/archive_sdmc.cpp | 108 | ||||
-rw-r--r-- | src/core/file_sys/archive_sdmc.h | 86 | ||||
-rw-r--r-- | src/core/file_sys/directory.h | 53 | ||||
-rw-r--r-- | src/core/file_sys/directory_romfs.cpp | 38 | ||||
-rw-r--r-- | src/core/file_sys/directory_romfs.h | 37 | ||||
-rw-r--r-- | src/core/file_sys/directory_sdmc.cpp | 86 | ||||
-rw-r--r-- | src/core/file_sys/directory_sdmc.h | 45 | ||||
-rw-r--r-- | src/core/file_sys/file.h | 53 | ||||
-rw-r--r-- | src/core/file_sys/file_romfs.cpp | 59 | ||||
-rw-r--r-- | src/core/file_sys/file_romfs.h | 54 | ||||
-rw-r--r-- | src/core/file_sys/file_sdmc.cpp | 63 | ||||
-rw-r--r-- | src/core/file_sys/file_sdmc.h | 60 |
15 files changed, 806 insertions, 0 deletions
diff --git a/src/core/file_sys/archive.h b/src/core/file_sys/archive.h index ac5630bea..560db6dea 100644 --- a/src/core/file_sys/archive.h +++ b/src/core/file_sys/archive.h @@ -4,7 +4,13 @@ #pragma once +#include <memory> + #include "common/common_types.h" +#include "common/bit_field.h" + +#include "core/file_sys/file.h" +#include "core/file_sys/directory.h" #include "core/hle/kernel/kernel.h" @@ -13,6 +19,13 @@ namespace FileSys { +union Mode { + u32 hex; + BitField<0, 1, u32> read_flag; + BitField<1, 1, u32> write_flag; + BitField<2, 1, u32> create_flag; +}; + class Archive : NonCopyable { public: /// Supported archive types @@ -36,6 +49,21 @@ public: virtual IdCode GetIdCode() const = 0; /** + * Open a file specified by its path, using the specified mode + * @param path Path relative to the archive + * @param mode Mode to open the file with + * @return Opened file, or nullptr + */ + virtual std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const = 0; + + /** + * Open a directory specified by its path + * @param path Path relative to the archive + * @return Opened directory, or nullptr + */ + virtual std::unique_ptr<Directory> OpenDirectory(const std::string& path) const = 0; + + /** * Read data from the archive * @param offset Offset in bytes to start reading data from * @param length Length in bytes of data to read from archive diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index dc3fb1807..9bab3471f 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp @@ -5,6 +5,8 @@ #include "common/common_types.h" #include "core/file_sys/archive_romfs.h" +#include "core/file_sys/directory_romfs.h" +#include "core/file_sys/file_romfs.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // FileSys namespace @@ -22,6 +24,25 @@ Archive_RomFS::~Archive_RomFS() { } /** + * Open a file specified by its path, using the specified mode + * @param path Path relative to the archive + * @param mode Mode to open the file with + * @return Opened file, or nullptr + */ +std::unique_ptr<File> Archive_RomFS::OpenFile(const std::string& path, const Mode mode) const { + return std::unique_ptr<File>(new File_RomFS); +} + +/** + * Open a directory specified by its path + * @param path Path relative to the archive + * @return Opened directory, or nullptr + */ +std::unique_ptr<Directory> Archive_RomFS::OpenDirectory(const std::string& path) const { + return std::unique_ptr<Directory>(new Directory_RomFS); +} + +/** * Read data from the archive * @param offset Offset in bytes to start reading data from * @param length Length in bytes of data to read from archive diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index e9ed6f77a..fcdefa95f 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h @@ -29,6 +29,21 @@ public: IdCode GetIdCode() const override { return IdCode::RomFS; }; /** + * Open a file specified by its path, using the specified mode + * @param path Path relative to the archive + * @param mode Mode to open the file with + * @return Opened file, or nullptr + */ + std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override; + + /** + * Open a directory specified by its path + * @param path Path relative to the archive + * @return Opened directory, or nullptr + */ + std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override; + + /** * Read data from the archive * @param offset Offset in bytes to start reading data from * @param length Length in bytes of data to read from archive diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp new file mode 100644 index 000000000..30d33be5f --- /dev/null +++ b/src/core/file_sys/archive_sdmc.cpp @@ -0,0 +1,108 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include <sys/stat.h> + +#include "common/common_types.h" +#include "common/file_util.h" + +#include "core/file_sys/archive_sdmc.h" +#include "core/file_sys/directory_sdmc.h" +#include "core/file_sys/file_sdmc.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +Archive_SDMC::Archive_SDMC(const std::string& mount_point) { + this->mount_point = mount_point; + DEBUG_LOG(FILESYS, "Directory %s set as SDMC.", mount_point.c_str()); +} + +Archive_SDMC::~Archive_SDMC() { +} + +bool Archive_SDMC::Initialize() { + if (!FileUtil::IsDirectory(mount_point)) { + WARN_LOG(FILESYS, "Directory %s not found, disabling SDMC.", mount_point.c_str()); + return false; + } + + return true; +} + +/** + * Open a file specified by its path, using the specified mode + * @param path Path relative to the archive + * @param mode Mode to open the file with + * @return Opened file, or nullptr + */ +std::unique_ptr<File> Archive_SDMC::OpenFile(const std::string& path, const Mode mode) const { + DEBUG_LOG(FILESYS, "called path=%s mode=%d", path.c_str(), mode); + File_SDMC* file = new File_SDMC(this, path, mode); + return std::unique_ptr<File>(file); +} + +/** + * Open a directory specified by its path + * @param path Path relative to the archive + * @return Opened directory, or nullptr + */ +std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const std::string& path) const { + DEBUG_LOG(FILESYS, "called path=%s", path.c_str()); + Directory_SDMC* directory = new Directory_SDMC(this, path); + return std::unique_ptr<Directory>(directory); +} + +/** + * Read data from the archive + * @param offset Offset in bytes to start reading archive from + * @param length Length in bytes to read data from archive + * @param buffer Buffer to read data into + * @return Number of bytes read + */ +size_t Archive_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { + ERROR_LOG(FILESYS, "(UNIMPLEMENTED)"); + return -1; +} + +/** + * Write data to the archive + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to archive + * @param buffer Buffer to write data from + * @param flush The flush parameters (0 == do not flush) + * @return Number of bytes written + */ +size_t Archive_SDMC::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) { + ERROR_LOG(FILESYS, "(UNIMPLEMENTED)"); + return -1; +} + +/** + * Get the size of the archive in bytes + * @return Size of the archive in bytes + */ +size_t Archive_SDMC::GetSize() const { + ERROR_LOG(FILESYS, "(UNIMPLEMENTED)"); + return 0; +} + +/** + * Set the size of the archive in bytes + */ +void Archive_SDMC::SetSize(const u64 size) { + ERROR_LOG(FILESYS, "(UNIMPLEMENTED)"); +} + +/** + * Getter for the path used for this Archive + * @return Mount point of that passthrough archive + */ +std::string Archive_SDMC::GetMountPoint() const { + return mount_point; +} + +} // namespace FileSys diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h new file mode 100644 index 000000000..946f8b957 --- /dev/null +++ b/src/core/file_sys/archive_sdmc.h @@ -0,0 +1,86 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/file_sys/archive.h" +#include "core/loader/loader.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +/// File system interface to the SDMC archive +class Archive_SDMC final : public Archive { +public: + Archive_SDMC(const std::string& mount_point); + ~Archive_SDMC() override; + + bool Initialize(); + + /** + * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.) + * @return IdCode of the archive + */ + IdCode GetIdCode() const override { return IdCode::SDMC; }; + + /** + * Open a file specified by its path, using the specified mode + * @param path Path relative to the archive + * @param mode Mode to open the file with + * @return Opened file, or nullptr + */ + std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override; + + /** + * Open a directory specified by its path + * @param path Path relative to the archive + * @return Opened directory, or nullptr + */ + std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override; + + /** + * Read data from the archive + * @param offset Offset in bytes to start reading archive from + * @param length Length in bytes to read data from archive + * @param buffer Buffer to read data into + * @return Number of bytes read + */ + size_t Read(const u64 offset, const u32 length, u8* buffer) const override; + + /** + * Write data to the archive + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to archive + * @param buffer Buffer to write data from + * @param flush The flush parameters (0 == do not flush) + * @return Number of bytes written + */ + size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override; + + /** + * Get the size of the archive in bytes + * @return Size of the archive in bytes + */ + size_t GetSize() const override; + + /** + * Set the size of the archive in bytes + */ + void SetSize(const u64 size) override; + + /** + * Getter for the path used for this Archive + * @return Mount point of that passthrough archive + */ + std::string GetMountPoint() const; + +private: + std::string mount_point; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h new file mode 100644 index 000000000..cf9a2010b --- /dev/null +++ b/src/core/file_sys/directory.h @@ -0,0 +1,53 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.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; +struct Entry { + char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated) + char short_name[8]; // 8.3 file name ('longfilename' -> 'LONGFI~1') + char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD) + char extension[3]; // 8.3 file extension (set to spaces for directories) + 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!"); + +class Directory : NonCopyable { +public: + Directory() { } + virtual ~Directory() { } + + /** + * List files contained in the directory + * @param count Number of entries to return at once in entries + * @param entries Buffer to read data into + * @return Number of entries listed + */ + virtual u32 Read(const u32 count, Entry* entries) = 0; + + /** + * Close the directory + * @return true if the directory closed correctly + */ + virtual bool Close() const = 0; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/directory_romfs.cpp b/src/core/file_sys/directory_romfs.cpp new file mode 100644 index 000000000..4e8f4c04d --- /dev/null +++ b/src/core/file_sys/directory_romfs.cpp @@ -0,0 +1,38 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/common_types.h" + +#include "core/file_sys/directory_romfs.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +Directory_RomFS::Directory_RomFS() { +} + +Directory_RomFS::~Directory_RomFS() { +} + +/** + * List files contained in the directory + * @param count Number of entries to return at once in entries + * @param entries Buffer to read data into + * @return Number of entries listed + */ +u32 Directory_RomFS::Read(const u32 count, Entry* entries) { + return 0; +} + +/** + * Close the directory + * @return true if the directory closed correctly + */ +bool Directory_RomFS::Close() const { + return false; +} + +} // namespace FileSys diff --git a/src/core/file_sys/directory_romfs.h b/src/core/file_sys/directory_romfs.h new file mode 100644 index 000000000..4b71c4b13 --- /dev/null +++ b/src/core/file_sys/directory_romfs.h @@ -0,0 +1,37 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/file_sys/directory.h" +#include "core/loader/loader.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +class Directory_RomFS final : public Directory { +public: + Directory_RomFS(); + ~Directory_RomFS() override; + + /** + * List files contained in the directory + * @param count Number of entries to return at once in entries + * @param entries Buffer to read data into + * @return Number of entries listed + */ + u32 Read(const u32 count, Entry* entries) override; + + /** + * Close the directory + * @return true if the directory closed correctly + */ + bool Close() const override; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp new file mode 100644 index 000000000..11e867857 --- /dev/null +++ b/src/core/file_sys/directory_sdmc.cpp @@ -0,0 +1,86 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include <sys/stat.h> + +#include "common/common_types.h" +#include "common/file_util.h" + +#include "core/file_sys/directory_sdmc.h" +#include "core/file_sys/archive_sdmc.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const std::string& path) { + // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass + // the root directory we set while opening the archive. + // For example, opening /../../usr/bin can give the emulated program your installed programs. + std::string absolute_path = archive->GetMountPoint() + path; + entry_count = FileUtil::ScanDirectoryTree(absolute_path, entry); + current_entry = 0; +} + +Directory_SDMC::~Directory_SDMC() { + Close(); +} + +/** + * List files contained in the directory + * @param count Number of entries to return at once in entries + * @param entries Buffer to read data into + * @return Number of entries listed + */ +u32 Directory_SDMC::Read(const u32 count, Entry* entries) { + u32 i; + for (i = 0; i < count && current_entry < entry_count; ++i) { + FileUtil::FSTEntry file = entry.children[current_entry]; + std::string filename = file.virtualName; + WARN_LOG(FILESYS, "File %s: size=%d dir=%d", filename.c_str(), file.size, file.isDirectory); + + Entry* entry = &entries[i]; + + // TODO(Link Mauve): use a proper conversion to UTF-16. + for (int j = 0; j < FILENAME_LENGTH; ++j) { + entry->filename[j] = filename[j]; + if (!filename[j]) + break; + } + + // Split the filename into 8.3 format. + // TODO(Link Mauve): move that to common, I guess, and make it more robust to long filenames. + std::string::size_type n = filename.rfind('.'); + if (n == std::string::npos) { + strncpy(entry->short_name, filename.c_str(), 8); + memset(entry->extension, '\0', 3); + } else { + strncpy(entry->short_name, filename.substr(0, n).c_str(), 8); + strncpy(entry->extension, filename.substr(n + 1).c_str(), 8); + } + + entry->is_directory = file.isDirectory; + entry->file_size = file.size; + + // We emulate a SD card where the archive bit has never been cleared, as it would be on + // most user SD cards. + // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a + // file bit. + entry->is_archive = !file.isDirectory; + + ++current_entry; + } + return i; +} + +/** + * Close the directory + * @return true if the directory closed correctly + */ +bool Directory_SDMC::Close() const { + return true; +} + +} // namespace FileSys diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h new file mode 100644 index 000000000..0bc6c9eff --- /dev/null +++ b/src/core/file_sys/directory_sdmc.h @@ -0,0 +1,45 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" +#include "common/file_util.h" + +#include "core/file_sys/directory.h" +#include "core/file_sys/archive_sdmc.h" +#include "core/loader/loader.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +class Directory_SDMC final : public Directory { +public: + Directory_SDMC(); + Directory_SDMC(const Archive_SDMC* archive, const std::string& path); + ~Directory_SDMC() override; + + /** + * List files contained in the directory + * @param count Number of entries to return at once in entries + * @param entries Buffer to read data into + * @return Number of entries listed + */ + u32 Read(const u32 count, Entry* entries) override; + + /** + * Close the directory + * @return true if the directory closed correctly + */ + bool Close() const override; + +private: + u32 entry_count; + u32 current_entry; + FileUtil::FSTEntry entry; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/file.h b/src/core/file_sys/file.h new file mode 100644 index 000000000..f7b009f5a --- /dev/null +++ b/src/core/file_sys/file.h @@ -0,0 +1,53 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +class File : NonCopyable { +public: + File() { } + virtual ~File() { } + + /** + * Read data from the file + * @param offset Offset in bytes to start reading data from + * @param length Length in bytes of data to read from file + * @param buffer Buffer to read data into + * @return Number of bytes read + */ + virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; + + /** + * Write data to the file + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to file + * @param buffer Buffer to write data from + * @param flush The flush parameters (0 == do not flush) + * @return Number of bytes written + */ + virtual size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const = 0; + + /** + * Get the size of the file in bytes + * @return Size of the file in bytes + */ + virtual size_t GetSize() const = 0; + + /** + * Close the file + * @return true if the file closed correctly + */ + virtual bool Close() const = 0; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/file_romfs.cpp b/src/core/file_sys/file_romfs.cpp new file mode 100644 index 000000000..00f3c2ea8 --- /dev/null +++ b/src/core/file_sys/file_romfs.cpp @@ -0,0 +1,59 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/common_types.h" + +#include "core/file_sys/file_romfs.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +File_RomFS::File_RomFS() { +} + +File_RomFS::~File_RomFS() { +} + +/** + * Read data from the file + * @param offset Offset in bytes to start reading data from + * @param length Length in bytes of data to read from file + * @param buffer Buffer to read data into + * @return Number of bytes read + */ +size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { + return -1; +} + +/** + * Write data to the file + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to file + * @param buffer Buffer to write data from + * @param flush The flush parameters (0 == do not flush) + * @return Number of bytes written + */ +size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { + return -1; +} + +/** + * Get the size of the file in bytes + * @return Size of the file in bytes + */ +size_t File_RomFS::GetSize() const { + return -1; +} + +/** + * Close the file + * @return true if the file closed correctly + */ +bool File_RomFS::Close() const { + return false; +} + +} // namespace FileSys diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h new file mode 100644 index 000000000..5db43d4a0 --- /dev/null +++ b/src/core/file_sys/file_romfs.h @@ -0,0 +1,54 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/file_sys/file.h" +#include "core/loader/loader.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +class File_RomFS final : public File { +public: + File_RomFS(); + ~File_RomFS() override; + + /** + * Read data from the file + * @param offset Offset in bytes to start reading data from + * @param length Length in bytes of data to read from file + * @param buffer Buffer to read data into + * @return Number of bytes read + */ + size_t Read(const u64 offset, const u32 length, u8* buffer) const override; + + /** + * Write data to the file + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to file + * @param buffer Buffer to write data from + * @param flush The flush parameters (0 == do not flush) + * @return Number of bytes written + */ + size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; + + /** + * Get the size of the file in bytes + * @return Size of the file in bytes + */ + size_t GetSize() const override; + + /** + * Close the file + * @return true if the file closed correctly + */ + bool Close() const override; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp new file mode 100644 index 000000000..76adc6403 --- /dev/null +++ b/src/core/file_sys/file_sdmc.cpp @@ -0,0 +1,63 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include <sys/stat.h> + +#include "common/common_types.h" +#include "common/file_util.h" + +#include "core/file_sys/file_sdmc.h" +#include "core/file_sys/archive_sdmc.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +File_SDMC::File_SDMC(const Archive_SDMC* archive, const std::string& path, const Mode mode) { + // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass + // the root directory we set while opening the archive. + // For example, opening /../../etc/passwd can give the emulated program your users list. + std::string real_path = archive->GetMountPoint() + path; + + if (!mode.create_flag && !FileUtil::Exists(real_path)) { + file = nullptr; + return; + } + + std::string mode_string; + if (mode.read_flag) + mode_string += "r"; + if (mode.write_flag) + mode_string += "w"; + + file = new FileUtil::IOFile(real_path, mode_string.c_str()); +} + +File_SDMC::~File_SDMC() { + Close(); +} + +size_t File_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { + file->Seek(offset, SEEK_SET); + return file->ReadBytes(buffer, length); +} + +size_t File_SDMC::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { + file->Seek(offset, SEEK_SET); + size_t written = file->WriteBytes(buffer, length); + if (flush) + file->Flush(); + return written; +} + +size_t File_SDMC::GetSize() const { + return file->GetSize(); +} + +bool File_SDMC::Close() const { + return file->Close(); +} + +} // namespace FileSys diff --git a/src/core/file_sys/file_sdmc.h b/src/core/file_sys/file_sdmc.h new file mode 100644 index 000000000..b2e46f449 --- /dev/null +++ b/src/core/file_sys/file_sdmc.h @@ -0,0 +1,60 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" +#include "common/file_util.h" + +#include "core/file_sys/file.h" +#include "core/file_sys/archive_sdmc.h" +#include "core/loader/loader.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +class File_SDMC final : public File { +public: + File_SDMC(); + File_SDMC(const Archive_SDMC* archive, const std::string& path, const Mode mode); + ~File_SDMC() override; + + /** + * Read data from the file + * @param offset Offset in bytes to start reading data from + * @param length Length in bytes of data to read from file + * @param buffer Buffer to read data into + * @return Number of bytes read + */ + size_t Read(const u64 offset, const u32 length, u8* buffer) const override; + + /** + * Write data to the file + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to file + * @param buffer Buffer to write data from + * @param flush The flush parameters (0 == do not flush) + * @return Number of bytes written + */ + size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; + + /** + * Get the size of the file in bytes + * @return Size of the file in bytes + */ + size_t GetSize() const override; + + /** + * Close the file + * @return true if the file closed correctly + */ + bool Close() const override; + +private: + FileUtil::IOFile* file; +}; + +} // namespace FileSys |