diff options
| author | 2014-10-06 15:25:19 -0400 | |
|---|---|---|
| committer | 2014-10-06 15:25:19 -0400 | |
| commit | 0e2d83fa3ab4aad56dc8813e45d5fdfe05132a5a (patch) | |
| tree | 766620c93a936e767cc073382573660041c2e193 | |
| parent | Merge pull request #125 from purpasmart96/master (diff) | |
| parent | Common: Add a helper function to generate a 8.3 filename from a long one. (diff) | |
| download | yuzu-0e2d83fa3ab4aad56dc8813e45d5fdfe05132a5a.tar.gz yuzu-0e2d83fa3ab4aad56dc8813e45d5fdfe05132a5a.tar.xz yuzu-0e2d83fa3ab4aad56dc8813e45d5fdfe05132a5a.zip | |
Merge pull request #129 from linkmauve/master
Fix the filesystem implementation in order to get blargSnes to run
| -rw-r--r-- | src/common/file_util.cpp | 42 | ||||
| -rw-r--r-- | src/common/file_util.h | 11 | ||||
| -rw-r--r-- | src/core/file_sys/archive_sdmc.cpp | 6 | ||||
| -rw-r--r-- | src/core/file_sys/archive_sdmc.h | 4 | ||||
| -rw-r--r-- | src/core/file_sys/directory.h | 10 | ||||
| -rw-r--r-- | src/core/file_sys/directory_sdmc.cpp | 43 | ||||
| -rw-r--r-- | src/core/file_sys/directory_sdmc.h | 9 | ||||
| -rw-r--r-- | src/core/file_sys/file.h | 15 | ||||
| -rw-r--r-- | src/core/file_sys/file_romfs.cpp | 19 | ||||
| -rw-r--r-- | src/core/file_sys/file_romfs.h | 15 | ||||
| -rw-r--r-- | src/core/file_sys/file_sdmc.cpp | 70 | ||||
| -rw-r--r-- | src/core/file_sys/file_sdmc.h | 17 | ||||
| -rw-r--r-- | src/core/hle/kernel/archive.cpp | 11 |
13 files changed, 226 insertions, 46 deletions
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 9292a1cd6..5fd155222 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -780,6 +780,48 @@ size_t ReadFileToString(bool text_file, const char *filename, std::string &str) | |||
| 780 | return file.ReadArray(&str[0], str.size()); | 780 | return file.ReadArray(&str[0], str.size()); |
| 781 | } | 781 | } |
| 782 | 782 | ||
| 783 | /** | ||
| 784 | * Splits the filename into 8.3 format | ||
| 785 | * Loosely implemented following https://en.wikipedia.org/wiki/8.3_filename | ||
| 786 | * @param filename The normal filename to use | ||
| 787 | * @param short_name A 9-char array in which the short name will be written | ||
| 788 | * @param extension A 4-char array in which the extension will be written | ||
| 789 | */ | ||
| 790 | void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name, | ||
| 791 | std::array<char, 4>& extension) { | ||
| 792 | const std::string forbidden_characters = ".\"/\\[]:;=, "; | ||
| 793 | |||
| 794 | // On a FAT32 partition, 8.3 names are stored as a 11 bytes array, filled with spaces. | ||
| 795 | short_name = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'}; | ||
| 796 | extension = {' ', ' ', ' ', '\0'}; | ||
| 797 | |||
| 798 | std::string::size_type point = filename.rfind('.'); | ||
| 799 | if (point == filename.size() - 1) | ||
| 800 | point = filename.rfind('.', point); | ||
| 801 | |||
| 802 | // Get short name. | ||
| 803 | int j = 0; | ||
| 804 | for (char letter : filename.substr(0, point)) { | ||
| 805 | if (forbidden_characters.find(letter, 0) != std::string::npos) | ||
| 806 | continue; | ||
| 807 | if (j == 8) { | ||
| 808 | // TODO(Link Mauve): also do that for filenames containing a space. | ||
| 809 | // TODO(Link Mauve): handle multiple files having the same short name. | ||
| 810 | short_name[6] = '~'; | ||
| 811 | short_name[7] = '1'; | ||
| 812 | break; | ||
| 813 | } | ||
| 814 | short_name[j++] = toupper(letter); | ||
| 815 | } | ||
| 816 | |||
| 817 | // Get extension. | ||
| 818 | if (point != std::string::npos) { | ||
| 819 | j = 0; | ||
| 820 | for (char letter : filename.substr(point + 1, 3)) | ||
| 821 | extension[j++] = toupper(letter); | ||
| 822 | } | ||
| 823 | } | ||
| 824 | |||
| 783 | IOFile::IOFile() | 825 | IOFile::IOFile() |
| 784 | : m_file(NULL), m_good(true) | 826 | : m_file(NULL), m_good(true) |
| 785 | {} | 827 | {} |
diff --git a/src/common/file_util.h b/src/common/file_util.h index f9d91972f..288734cad 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 7 | #include <fstream> | 8 | #include <fstream> |
| 8 | #include <cstdio> | 9 | #include <cstdio> |
| 9 | #include <cstring> | 10 | #include <cstring> |
| @@ -131,6 +132,16 @@ std::string &GetExeDirectory(); | |||
| 131 | size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename); | 132 | size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename); |
| 132 | size_t ReadFileToString(bool text_file, const char *filename, std::string &str); | 133 | size_t ReadFileToString(bool text_file, const char *filename, std::string &str); |
| 133 | 134 | ||
| 135 | /** | ||
| 136 | * Splits the filename into 8.3 format | ||
| 137 | * Loosely implemented following https://en.wikipedia.org/wiki/8.3_filename | ||
| 138 | * @param filename The normal filename to use | ||
| 139 | * @param short_name A 9-char array in which the short name will be written | ||
| 140 | * @param extension A 4-char array in which the extension will be written | ||
| 141 | */ | ||
| 142 | void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name, | ||
| 143 | std::array<char, 4>& extension); | ||
| 144 | |||
| 134 | // simple wrapper for cstdlib file functions to | 145 | // simple wrapper for cstdlib file functions to |
| 135 | // hopefully will make error checking easier | 146 | // hopefully will make error checking easier |
| 136 | // and make forgetting an fclose() harder | 147 | // and make forgetting an fclose() harder |
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index 30d33be5f..213923c02 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp | |||
| @@ -24,6 +24,10 @@ Archive_SDMC::Archive_SDMC(const std::string& mount_point) { | |||
| 24 | Archive_SDMC::~Archive_SDMC() { | 24 | Archive_SDMC::~Archive_SDMC() { |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | /** | ||
| 28 | * Initialize the archive. | ||
| 29 | * @return true if it initialized successfully | ||
| 30 | */ | ||
| 27 | bool Archive_SDMC::Initialize() { | 31 | bool Archive_SDMC::Initialize() { |
| 28 | if (!FileUtil::IsDirectory(mount_point)) { | 32 | if (!FileUtil::IsDirectory(mount_point)) { |
| 29 | WARN_LOG(FILESYS, "Directory %s not found, disabling SDMC.", mount_point.c_str()); | 33 | WARN_LOG(FILESYS, "Directory %s not found, disabling SDMC.", mount_point.c_str()); |
| @@ -42,6 +46,8 @@ bool Archive_SDMC::Initialize() { | |||
| 42 | std::unique_ptr<File> Archive_SDMC::OpenFile(const std::string& path, const Mode mode) const { | 46 | std::unique_ptr<File> Archive_SDMC::OpenFile(const std::string& path, const Mode mode) const { |
| 43 | DEBUG_LOG(FILESYS, "called path=%s mode=%d", path.c_str(), mode); | 47 | DEBUG_LOG(FILESYS, "called path=%s mode=%d", path.c_str(), mode); |
| 44 | File_SDMC* file = new File_SDMC(this, path, mode); | 48 | File_SDMC* file = new File_SDMC(this, path, mode); |
| 49 | if (!file->Open()) | ||
| 50 | return nullptr; | ||
| 45 | return std::unique_ptr<File>(file); | 51 | return std::unique_ptr<File>(file); |
| 46 | } | 52 | } |
| 47 | 53 | ||
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 946f8b957..f68648e6f 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h | |||
| @@ -20,6 +20,10 @@ public: | |||
| 20 | Archive_SDMC(const std::string& mount_point); | 20 | Archive_SDMC(const std::string& mount_point); |
| 21 | ~Archive_SDMC() override; | 21 | ~Archive_SDMC() override; |
| 22 | 22 | ||
| 23 | /** | ||
| 24 | * Initialize the archive. | ||
| 25 | * @return true if it initialized successfully | ||
| 26 | */ | ||
| 23 | bool Initialize(); | 27 | bool Initialize(); |
| 24 | 28 | ||
| 25 | /** | 29 | /** |
diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h index cf9a2010b..e10431337 100644 --- a/src/core/file_sys/directory.h +++ b/src/core/file_sys/directory.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | 10 | ||
| 9 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| @@ -17,9 +19,9 @@ namespace FileSys { | |||
| 17 | const size_t FILENAME_LENGTH = 0x20C / 2; | 19 | const size_t FILENAME_LENGTH = 0x20C / 2; |
| 18 | struct Entry { | 20 | struct Entry { |
| 19 | char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated) | 21 | char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated) |
| 20 | char short_name[8]; // 8.3 file name ('longfilename' -> 'LONGFI~1') | 22 | std::array<char, 9> short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated) |
| 21 | char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD) | 23 | char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD) |
| 22 | char extension[3]; // 8.3 file extension (set to spaces for directories) | 24 | std::array<char, 4> extension; // 8.3 file extension (set to spaces for directories, null-terminated) |
| 23 | char unknown2; // unknown (always 0x01) | 25 | char unknown2; // unknown (always 0x01) |
| 24 | char unknown3; // unknown (0x00 or 0x08) | 26 | char unknown3; // unknown (0x00 or 0x08) |
| 25 | char is_directory; // directory flag | 27 | char is_directory; // directory flag |
| @@ -29,6 +31,10 @@ struct Entry { | |||
| 29 | u64 file_size; // file size (for files only) | 31 | u64 file_size; // file size (for files only) |
| 30 | }; | 32 | }; |
| 31 | static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!"); | 33 | static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!"); |
| 34 | static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry."); | ||
| 35 | static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension in Entry."); | ||
| 36 | static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry."); | ||
| 37 | static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry."); | ||
| 32 | 38 | ||
| 33 | class Directory : NonCopyable { | 39 | class Directory : NonCopyable { |
| 34 | public: | 40 | public: |
diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp index 11e867857..36951564d 100644 --- a/src/core/file_sys/directory_sdmc.cpp +++ b/src/core/file_sys/directory_sdmc.cpp | |||
| @@ -20,8 +20,8 @@ Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const std::string& p | |||
| 20 | // the root directory we set while opening the archive. | 20 | // the root directory we set while opening the archive. |
| 21 | // For example, opening /../../usr/bin can give the emulated program your installed programs. | 21 | // For example, opening /../../usr/bin can give the emulated program your installed programs. |
| 22 | std::string absolute_path = archive->GetMountPoint() + path; | 22 | std::string absolute_path = archive->GetMountPoint() + path; |
| 23 | entry_count = FileUtil::ScanDirectoryTree(absolute_path, entry); | 23 | FileUtil::ScanDirectoryTree(absolute_path, directory); |
| 24 | current_entry = 0; | 24 | children_iterator = directory.children.begin(); |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | Directory_SDMC::~Directory_SDMC() { | 27 | Directory_SDMC::~Directory_SDMC() { |
| @@ -35,44 +35,39 @@ Directory_SDMC::~Directory_SDMC() { | |||
| 35 | * @return Number of entries listed | 35 | * @return Number of entries listed |
| 36 | */ | 36 | */ |
| 37 | u32 Directory_SDMC::Read(const u32 count, Entry* entries) { | 37 | u32 Directory_SDMC::Read(const u32 count, Entry* entries) { |
| 38 | u32 i; | 38 | u32 entries_read = 0; |
| 39 | for (i = 0; i < count && current_entry < entry_count; ++i) { | 39 | |
| 40 | FileUtil::FSTEntry file = entry.children[current_entry]; | 40 | while (entries_read < count && children_iterator != directory.children.cend()) { |
| 41 | std::string filename = file.virtualName; | 41 | const FileUtil::FSTEntry& file = *children_iterator; |
| 42 | WARN_LOG(FILESYS, "File %s: size=%d dir=%d", filename.c_str(), file.size, file.isDirectory); | 42 | const std::string& filename = file.virtualName; |
| 43 | Entry& entry = entries[entries_read]; | ||
| 43 | 44 | ||
| 44 | Entry* entry = &entries[i]; | 45 | WARN_LOG(FILESYS, "File %s: size=%d dir=%d", filename.c_str(), file.size, file.isDirectory); |
| 45 | 46 | ||
| 46 | // TODO(Link Mauve): use a proper conversion to UTF-16. | 47 | // TODO(Link Mauve): use a proper conversion to UTF-16. |
| 47 | for (int j = 0; j < FILENAME_LENGTH; ++j) { | 48 | for (int j = 0; j < FILENAME_LENGTH; ++j) { |
| 48 | entry->filename[j] = filename[j]; | 49 | entry.filename[j] = filename[j]; |
| 49 | if (!filename[j]) | 50 | if (!filename[j]) |
| 50 | break; | 51 | break; |
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | // Split the filename into 8.3 format. | 54 | FileUtil::SplitFilename83(filename, entry.short_name, entry.extension); |
| 54 | // TODO(Link Mauve): move that to common, I guess, and make it more robust to long filenames. | ||
| 55 | std::string::size_type n = filename.rfind('.'); | ||
| 56 | if (n == std::string::npos) { | ||
| 57 | strncpy(entry->short_name, filename.c_str(), 8); | ||
| 58 | memset(entry->extension, '\0', 3); | ||
| 59 | } else { | ||
| 60 | strncpy(entry->short_name, filename.substr(0, n).c_str(), 8); | ||
| 61 | strncpy(entry->extension, filename.substr(n + 1).c_str(), 8); | ||
| 62 | } | ||
| 63 | 55 | ||
| 64 | entry->is_directory = file.isDirectory; | 56 | entry.is_directory = file.isDirectory; |
| 65 | entry->file_size = file.size; | 57 | entry.is_hidden = (filename[0] == '.'); |
| 58 | entry.is_read_only = 0; | ||
| 59 | entry.file_size = file.size; | ||
| 66 | 60 | ||
| 67 | // We emulate a SD card where the archive bit has never been cleared, as it would be on | 61 | // We emulate a SD card where the archive bit has never been cleared, as it would be on |
| 68 | // most user SD cards. | 62 | // most user SD cards. |
| 69 | // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a | 63 | // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a |
| 70 | // file bit. | 64 | // file bit. |
| 71 | entry->is_archive = !file.isDirectory; | 65 | entry.is_archive = !file.isDirectory; |
| 72 | 66 | ||
| 73 | ++current_entry; | 67 | ++entries_read; |
| 68 | ++children_iterator; | ||
| 74 | } | 69 | } |
| 75 | return i; | 70 | return entries_read; |
| 76 | } | 71 | } |
| 77 | 72 | ||
| 78 | /** | 73 | /** |
diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h index 0bc6c9eff..cb8d32fda 100644 --- a/src/core/file_sys/directory_sdmc.h +++ b/src/core/file_sys/directory_sdmc.h | |||
| @@ -37,9 +37,12 @@ public: | |||
| 37 | bool Close() const override; | 37 | bool Close() const override; |
| 38 | 38 | ||
| 39 | private: | 39 | private: |
| 40 | u32 entry_count; | 40 | u32 total_entries_in_directory; |
| 41 | u32 current_entry; | 41 | FileUtil::FSTEntry directory; |
| 42 | FileUtil::FSTEntry entry; | 42 | |
| 43 | // We need to remember the last entry we returned, so a subsequent call to Read will continue | ||
| 44 | // from the next one. This iterator will always point to the next unread entry. | ||
| 45 | std::vector<FileUtil::FSTEntry>::iterator children_iterator; | ||
| 43 | }; | 46 | }; |
| 44 | 47 | ||
| 45 | } // namespace FileSys | 48 | } // namespace FileSys |
diff --git a/src/core/file_sys/file.h b/src/core/file_sys/file.h index f7b009f5a..4013b6c3e 100644 --- a/src/core/file_sys/file.h +++ b/src/core/file_sys/file.h | |||
| @@ -19,6 +19,12 @@ public: | |||
| 19 | virtual ~File() { } | 19 | virtual ~File() { } |
| 20 | 20 | ||
| 21 | /** | 21 | /** |
| 22 | * Open the file | ||
| 23 | * @return true if the file opened correctly | ||
| 24 | */ | ||
| 25 | virtual bool Open() = 0; | ||
| 26 | |||
| 27 | /** | ||
| 22 | * Read data from the file | 28 | * Read data from the file |
| 23 | * @param offset Offset in bytes to start reading data from | 29 | * @param offset Offset in bytes to start reading data from |
| 24 | * @param length Length in bytes of data to read from file | 30 | * @param length Length in bytes of data to read from file |
| @@ -31,8 +37,8 @@ public: | |||
| 31 | * Write data to the file | 37 | * Write data to the file |
| 32 | * @param offset Offset in bytes to start writing data to | 38 | * @param offset Offset in bytes to start writing data to |
| 33 | * @param length Length in bytes of data to write to file | 39 | * @param length Length in bytes of data to write to file |
| 34 | * @param buffer Buffer to write data from | ||
| 35 | * @param flush The flush parameters (0 == do not flush) | 40 | * @param flush The flush parameters (0 == do not flush) |
| 41 | * @param buffer Buffer to read data from | ||
| 36 | * @return Number of bytes written | 42 | * @return Number of bytes written |
| 37 | */ | 43 | */ |
| 38 | virtual size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const = 0; | 44 | virtual size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const = 0; |
| @@ -44,6 +50,13 @@ public: | |||
| 44 | virtual size_t GetSize() const = 0; | 50 | virtual size_t GetSize() const = 0; |
| 45 | 51 | ||
| 46 | /** | 52 | /** |
| 53 | * Set the size of the file in bytes | ||
| 54 | * @param size New size of the file | ||
| 55 | * @return true if successful | ||
| 56 | */ | ||
| 57 | virtual bool SetSize(const u64 size) const = 0; | ||
| 58 | |||
| 59 | /** | ||
| 47 | * Close the file | 60 | * Close the file |
| 48 | * @return true if the file closed correctly | 61 | * @return true if the file closed correctly |
| 49 | */ | 62 | */ |
diff --git a/src/core/file_sys/file_romfs.cpp b/src/core/file_sys/file_romfs.cpp index 00f3c2ea8..b55708df4 100644 --- a/src/core/file_sys/file_romfs.cpp +++ b/src/core/file_sys/file_romfs.cpp | |||
| @@ -18,6 +18,14 @@ File_RomFS::~File_RomFS() { | |||
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | /** | 20 | /** |
| 21 | * Open the file | ||
| 22 | * @return true if the file opened correctly | ||
| 23 | */ | ||
| 24 | bool File_RomFS::Open() { | ||
| 25 | return false; | ||
| 26 | } | ||
| 27 | |||
| 28 | /** | ||
| 21 | * Read data from the file | 29 | * Read data from the file |
| 22 | * @param offset Offset in bytes to start reading data from | 30 | * @param offset Offset in bytes to start reading data from |
| 23 | * @param length Length in bytes of data to read from file | 31 | * @param length Length in bytes of data to read from file |
| @@ -32,8 +40,8 @@ size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { | |||
| 32 | * Write data to the file | 40 | * Write data to the file |
| 33 | * @param offset Offset in bytes to start writing data to | 41 | * @param offset Offset in bytes to start writing data to |
| 34 | * @param length Length in bytes of data to write to file | 42 | * @param length Length in bytes of data to write to file |
| 35 | * @param buffer Buffer to write data from | ||
| 36 | * @param flush The flush parameters (0 == do not flush) | 43 | * @param flush The flush parameters (0 == do not flush) |
| 44 | * @param buffer Buffer to read data from | ||
| 37 | * @return Number of bytes written | 45 | * @return Number of bytes written |
| 38 | */ | 46 | */ |
| 39 | size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { | 47 | size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { |
| @@ -49,6 +57,15 @@ size_t File_RomFS::GetSize() const { | |||
| 49 | } | 57 | } |
| 50 | 58 | ||
| 51 | /** | 59 | /** |
| 60 | * Set the size of the file in bytes | ||
| 61 | * @param size New size of the file | ||
| 62 | * @return true if successful | ||
| 63 | */ | ||
| 64 | bool File_RomFS::SetSize(const u64 size) const { | ||
| 65 | return false; | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 52 | * Close the file | 69 | * Close the file |
| 53 | * @return true if the file closed correctly | 70 | * @return true if the file closed correctly |
| 54 | */ | 71 | */ |
diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h index 5db43d4a0..5196701d3 100644 --- a/src/core/file_sys/file_romfs.h +++ b/src/core/file_sys/file_romfs.h | |||
| @@ -20,6 +20,12 @@ public: | |||
| 20 | ~File_RomFS() override; | 20 | ~File_RomFS() override; |
| 21 | 21 | ||
| 22 | /** | 22 | /** |
| 23 | * Open the file | ||
| 24 | * @return true if the file opened correctly | ||
| 25 | */ | ||
| 26 | bool Open() override; | ||
| 27 | |||
| 28 | /** | ||
| 23 | * Read data from the file | 29 | * Read data from the file |
| 24 | * @param offset Offset in bytes to start reading data from | 30 | * @param offset Offset in bytes to start reading data from |
| 25 | * @param length Length in bytes of data to read from file | 31 | * @param length Length in bytes of data to read from file |
| @@ -32,8 +38,8 @@ public: | |||
| 32 | * Write data to the file | 38 | * Write data to the file |
| 33 | * @param offset Offset in bytes to start writing data to | 39 | * @param offset Offset in bytes to start writing data to |
| 34 | * @param length Length in bytes of data to write to file | 40 | * @param length Length in bytes of data to write to file |
| 35 | * @param buffer Buffer to write data from | ||
| 36 | * @param flush The flush parameters (0 == do not flush) | 41 | * @param flush The flush parameters (0 == do not flush) |
| 42 | * @param buffer Buffer to read data from | ||
| 37 | * @return Number of bytes written | 43 | * @return Number of bytes written |
| 38 | */ | 44 | */ |
| 39 | size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; | 45 | size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; |
| @@ -45,6 +51,13 @@ public: | |||
| 45 | size_t GetSize() const override; | 51 | size_t GetSize() const override; |
| 46 | 52 | ||
| 47 | /** | 53 | /** |
| 54 | * Set the size of the file in bytes | ||
| 55 | * @param size New size of the file | ||
| 56 | * @return true if successful | ||
| 57 | */ | ||
| 58 | bool SetSize(const u64 size) const override; | ||
| 59 | |||
| 60 | /** | ||
| 48 | * Close the file | 61 | * Close the file |
| 49 | * @return true if the file closed correctly | 62 | * @return true if the file closed correctly |
| 50 | */ | 63 | */ |
diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp index 07951c9f1..26204392c 100644 --- a/src/core/file_sys/file_sdmc.cpp +++ b/src/core/file_sys/file_sdmc.cpp | |||
| @@ -19,31 +19,56 @@ File_SDMC::File_SDMC(const Archive_SDMC* archive, const std::string& path, const | |||
| 19 | // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass | 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. | 20 | // the root directory we set while opening the archive. |
| 21 | // For example, opening /../../etc/passwd can give the emulated program your users list. | 21 | // For example, opening /../../etc/passwd can give the emulated program your users list. |
| 22 | std::string real_path = archive->GetMountPoint() + path; | 22 | this->path = archive->GetMountPoint() + path; |
| 23 | this->mode.hex = mode.hex; | ||
| 24 | } | ||
| 25 | |||
| 26 | File_SDMC::~File_SDMC() { | ||
| 27 | Close(); | ||
| 28 | } | ||
| 23 | 29 | ||
| 24 | if (!mode.create_flag && !FileUtil::Exists(real_path)) { | 30 | /** |
| 25 | file = nullptr; | 31 | * Open the file |
| 26 | return; | 32 | * @return true if the file opened correctly |
| 33 | */ | ||
| 34 | bool File_SDMC::Open() { | ||
| 35 | if (!mode.create_flag && !FileUtil::Exists(path)) { | ||
| 36 | ERROR_LOG(FILESYS, "Non-existing file %s can’t be open without mode create.", path.c_str()); | ||
| 37 | return false; | ||
| 27 | } | 38 | } |
| 28 | 39 | ||
| 29 | std::string mode_string; | 40 | std::string mode_string; |
| 30 | if (mode.read_flag) | 41 | if (mode.read_flag && mode.write_flag) |
| 31 | mode_string += "r"; | 42 | mode_string = "w+"; |
| 32 | if (mode.write_flag) | 43 | else if (mode.read_flag) |
| 33 | mode_string += "w"; | 44 | mode_string = "r"; |
| 45 | else if (mode.write_flag) | ||
| 46 | mode_string = "w"; | ||
| 34 | 47 | ||
| 35 | file = new FileUtil::IOFile(real_path, mode_string.c_str()); | 48 | file = new FileUtil::IOFile(path, mode_string.c_str()); |
| 36 | } | 49 | return true; |
| 37 | |||
| 38 | File_SDMC::~File_SDMC() { | ||
| 39 | Close(); | ||
| 40 | } | 50 | } |
| 41 | 51 | ||
| 52 | /** | ||
| 53 | * Read data from the file | ||
| 54 | * @param offset Offset in bytes to start reading data from | ||
| 55 | * @param length Length in bytes of data to read from file | ||
| 56 | * @param buffer Buffer to read data into | ||
| 57 | * @return Number of bytes read | ||
| 58 | */ | ||
| 42 | size_t File_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { | 59 | size_t File_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { |
| 43 | file->Seek(offset, SEEK_SET); | 60 | file->Seek(offset, SEEK_SET); |
| 44 | return file->ReadBytes(buffer, length); | 61 | return file->ReadBytes(buffer, length); |
| 45 | } | 62 | } |
| 46 | 63 | ||
| 64 | /** | ||
| 65 | * Write data to the file | ||
| 66 | * @param offset Offset in bytes to start writing data to | ||
| 67 | * @param length Length in bytes of data to write to file | ||
| 68 | * @param flush The flush parameters (0 == do not flush) | ||
| 69 | * @param buffer Buffer to read data from | ||
| 70 | * @return Number of bytes written | ||
| 71 | */ | ||
| 47 | size_t File_SDMC::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { | 72 | size_t File_SDMC::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { |
| 48 | file->Seek(offset, SEEK_SET); | 73 | file->Seek(offset, SEEK_SET); |
| 49 | size_t written = file->WriteBytes(buffer, length); | 74 | size_t written = file->WriteBytes(buffer, length); |
| @@ -52,10 +77,29 @@ size_t File_SDMC::Write(const u64 offset, const u32 length, const u32 flush, con | |||
| 52 | return written; | 77 | return written; |
| 53 | } | 78 | } |
| 54 | 79 | ||
| 80 | /** | ||
| 81 | * Get the size of the file in bytes | ||
| 82 | * @return Size of the file in bytes | ||
| 83 | */ | ||
| 55 | size_t File_SDMC::GetSize() const { | 84 | size_t File_SDMC::GetSize() const { |
| 56 | return static_cast<size_t>(file->GetSize()); | 85 | return static_cast<size_t>(file->GetSize()); |
| 57 | } | 86 | } |
| 58 | 87 | ||
| 88 | /** | ||
| 89 | * Set the size of the file in bytes | ||
| 90 | * @param size New size of the file | ||
| 91 | * @return true if successful | ||
| 92 | */ | ||
| 93 | bool File_SDMC::SetSize(const u64 size) const { | ||
| 94 | file->Resize(size); | ||
| 95 | file->Flush(); | ||
| 96 | return true; | ||
| 97 | } | ||
| 98 | |||
| 99 | /** | ||
| 100 | * Close the file | ||
| 101 | * @return true if the file closed correctly | ||
| 102 | */ | ||
| 59 | bool File_SDMC::Close() const { | 103 | bool File_SDMC::Close() const { |
| 60 | return file->Close(); | 104 | return file->Close(); |
| 61 | } | 105 | } |
diff --git a/src/core/file_sys/file_sdmc.h b/src/core/file_sys/file_sdmc.h index b2e46f449..df032f7c0 100644 --- a/src/core/file_sys/file_sdmc.h +++ b/src/core/file_sys/file_sdmc.h | |||
| @@ -23,6 +23,12 @@ public: | |||
| 23 | ~File_SDMC() override; | 23 | ~File_SDMC() override; |
| 24 | 24 | ||
| 25 | /** | 25 | /** |
| 26 | * Open the file | ||
| 27 | * @return true if the file opened correctly | ||
| 28 | */ | ||
| 29 | bool Open() override; | ||
| 30 | |||
| 31 | /** | ||
| 26 | * Read data from the file | 32 | * Read data from the file |
| 27 | * @param offset Offset in bytes to start reading data from | 33 | * @param offset Offset in bytes to start reading data from |
| 28 | * @param length Length in bytes of data to read from file | 34 | * @param length Length in bytes of data to read from file |
| @@ -35,8 +41,8 @@ public: | |||
| 35 | * Write data to the file | 41 | * Write data to the file |
| 36 | * @param offset Offset in bytes to start writing data to | 42 | * @param offset Offset in bytes to start writing data to |
| 37 | * @param length Length in bytes of data to write to file | 43 | * @param length Length in bytes of data to write to file |
| 38 | * @param buffer Buffer to write data from | ||
| 39 | * @param flush The flush parameters (0 == do not flush) | 44 | * @param flush The flush parameters (0 == do not flush) |
| 45 | * @param buffer Buffer to read data from | ||
| 40 | * @return Number of bytes written | 46 | * @return Number of bytes written |
| 41 | */ | 47 | */ |
| 42 | size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; | 48 | size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; |
| @@ -48,12 +54,21 @@ public: | |||
| 48 | size_t GetSize() const override; | 54 | size_t GetSize() const override; |
| 49 | 55 | ||
| 50 | /** | 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 | /** | ||
| 51 | * Close the file | 64 | * Close the file |
| 52 | * @return true if the file closed correctly | 65 | * @return true if the file closed correctly |
| 53 | */ | 66 | */ |
| 54 | bool Close() const override; | 67 | bool Close() const override; |
| 55 | 68 | ||
| 56 | private: | 69 | private: |
| 70 | std::string path; | ||
| 71 | Mode mode; | ||
| 57 | FileUtil::IOFile* file; | 72 | FileUtil::IOFile* file; |
| 58 | }; | 73 | }; |
| 59 | 74 | ||
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp index fa4972994..86aba7489 100644 --- a/src/core/hle/kernel/archive.cpp +++ b/src/core/hle/kernel/archive.cpp | |||
| @@ -181,6 +181,14 @@ public: | |||
| 181 | break; | 181 | break; |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | case FileCommand::SetSize: | ||
| 185 | { | ||
| 186 | u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); | ||
| 187 | DEBUG_LOG(KERNEL, "SetSize %s %s size=%d", GetTypeName().c_str(), GetName().c_str(), size); | ||
| 188 | backend->SetSize(size); | ||
| 189 | break; | ||
| 190 | } | ||
| 191 | |||
| 184 | case FileCommand::Close: | 192 | case FileCommand::Close: |
| 185 | { | 193 | { |
| 186 | DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); | 194 | DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); |
| @@ -366,6 +374,9 @@ Handle OpenFileFromArchive(Handle archive_handle, const std::string& path, const | |||
| 366 | file->path = path; | 374 | file->path = path; |
| 367 | file->backend = archive->backend->OpenFile(path, mode); | 375 | file->backend = archive->backend->OpenFile(path, mode); |
| 368 | 376 | ||
| 377 | if (!file->backend) | ||
| 378 | return 0; | ||
| 379 | |||
| 369 | return handle; | 380 | return handle; |
| 370 | } | 381 | } |
| 371 | 382 | ||