diff options
28 files changed, 525 insertions, 544 deletions
| diff --git a/src/common/common_paths.h b/src/common/common_paths.h index 42e1a29c1..a86889756 100644 --- a/src/common/common_paths.h +++ b/src/common/common_paths.h @@ -40,6 +40,7 @@  #define MAPS_DIR          "maps"  #define CACHE_DIR         "cache"  #define SDMC_DIR          "sdmc" +#define SAVEDATA_DIR      "savedata"  #define SYSDATA_DIR       "sysdata"  #define SHADERCACHE_DIR   "shader_cache"  #define STATESAVES_DIR    "state_saves" diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 88c46c117..42cdf3262 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -676,6 +676,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new          paths[D_MAPS_IDX]           = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;          paths[D_CACHE_IDX]          = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;          paths[D_SDMC_IDX]           = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; +        paths[D_SAVEDATA_IDX]       = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP;          paths[D_SYSDATA_IDX]        = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP;          paths[D_SHADERCACHE_IDX]    = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;          paths[D_SHADERS_IDX]        = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; @@ -718,6 +719,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new              paths[D_MAPS_IDX]           = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;              paths[D_CACHE_IDX]          = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;              paths[D_SDMC_IDX]           = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; +            paths[D_SAVEDATA_IDX]       = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP;              paths[D_SHADERCACHE_IDX]    = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;              paths[D_SHADERS_IDX]        = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;              paths[D_STATESAVES_IDX]     = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; diff --git a/src/common/file_util.h b/src/common/file_util.h index a9d48cfe8..e691b6139 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -27,6 +27,7 @@ enum {      D_STATESAVES_IDX,      D_SCREENSHOTS_IDX,      D_SDMC_IDX, +    D_SAVEDATA_IDX,      D_SYSDATA_IDX,      D_HIRESTEXTURES_IDX,      D_DUMP_IDX, diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 198e4afd3..f71232c1a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -18,11 +18,11 @@ set(SRCS              arm/skyeye_common/vfp/vfpinstr.cpp              arm/skyeye_common/vfp/vfpsingle.cpp              file_sys/archive_romfs.cpp +            file_sys/archive_savedata.cpp              file_sys/archive_sdmc.cpp +            file_sys/disk_archive.cpp              file_sys/file_romfs.cpp -            file_sys/file_sdmc.cpp              file_sys/directory_romfs.cpp -            file_sys/directory_sdmc.cpp              hle/kernel/address_arbiter.cpp              hle/kernel/event.cpp              hle/kernel/kernel.cpp @@ -99,13 +99,13 @@ set(HEADERS              arm/arm_interface.h              file_sys/archive_backend.h              file_sys/archive_romfs.h +            file_sys/archive_savedata.h              file_sys/archive_sdmc.h +            file_sys/disk_archive.h              file_sys/file_backend.h              file_sys/file_romfs.h -            file_sys/file_sdmc.h              file_sys/directory_backend.h              file_sys/directory_romfs.h -            file_sys/directory_sdmc.h              hle/kernel/address_arbiter.h              hle/kernel/event.h              hle/kernel/kernel.h diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index de178a890..14330156b 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5807,24 +5807,25 @@ L_stm_s_takeabort:              break;          case 0x61:              if ((instr & 0xFF0) == 0xf70) { //ssub16 -                u8 tar = BITS(12, 15); -                u8 src1 = BITS(16, 19); -                u8 src2 = BITS(0, 3); -                s16 a1 = (state->Reg[src1] & 0xFFFF); -                s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); -                s16 b1 = (state->Reg[src2] & 0xFFFF); -                s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); -				state->Reg[tar] = ((a1 - a2) & 0xFFFF) | (((b1 - b2) & 0xFFFF) << 0x10); +                const u8 rd_idx = BITS(12, 15); +                const u8 rm_idx = BITS(0, 3); +                const u8 rn_idx = BITS(16, 19); +                const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF); +                const s16 rn_hi = ((state->Reg[rn_idx] >> 16) & 0xFFFF); +                const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF); +                const s16 rm_hi = ((state->Reg[rm_idx] >> 16) & 0xFFFF); +                state->Reg[rd_idx] = ((rn_lo - rm_lo) & 0xFFFF) | (((rn_hi - rm_hi) & 0xFFFF) << 16);                  return 1;              } else if ((instr & 0xFF0) == 0xf10) { //sadd16 -                u8 tar = BITS(12, 15); -                u8 src1 = BITS(16, 19); -                u8 src2 = BITS(0, 3); -                s16 a1 = (state->Reg[src1] & 0xFFFF); -                s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); -                s16 b1 = (state->Reg[src2] & 0xFFFF); -                s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); -				state->Reg[tar] = ((a1 + a2) & 0xFFFF) | (((b1 + b2) & 0xFFFF) << 0x10); +                const u8 rd_idx = BITS(12, 15); +                const u8 rm_idx = BITS(0, 3); +                const u8 rn_idx = BITS(16, 19); +                const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF); +                const s16 rm_hi = ((state->Reg[rm_idx] >> 16) & 0xFFFF); +                const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF); +                const s16 rn_hi = ((state->Reg[rn_idx] >> 16) & 0xFFFF); + +                state->Reg[rd_idx] = ((rn_lo + rm_lo) & 0xFFFF) | (((rn_hi + rm_hi) & 0xFFFF) << 16);                  return 1;              } else if ((instr & 0xFF0) == 0xf50) { //ssax                  u8 tar = BITS(12, 15); @@ -5848,40 +5849,44 @@ L_stm_s_takeabort:                  return 1;              } else printf ("Unhandled v6 insn: sadd/ssub/ssax/sasx\n");              break; -        case 0x62: -            if ((instr & 0xFF0) == 0xf70) { //QSUB16 -                u8 tar = BITS(12, 15); -                u8 src1 = BITS(16, 19); -                u8 src2 = BITS(0, 3); -                s16 a1 = (state->Reg[src1] & 0xFFFF); -                s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); -                s16 b1 = (state->Reg[src2] & 0xFFFF); -                s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); -                s32 res1 = (a1 - b1); -                s32 res2 = (a2 - b2); -                if (res1 > 0x7FFF) res1 = 0x7FFF; -                if (res2 > 0x7FFF) res2 = 0x7FFF; -                if (res1 < 0x7FFF) res1 = -0x8000; -                if (res2 < 0x7FFF) res2 = -0x8000; -                state->Reg[tar] = (res1 & 0xFFFF) | ((res2 & 0xFFFF) << 0x10); -                return 1; -            } else if ((instr & 0xFF0) == 0xf10) { //QADD16 -                u8 tar = BITS(12, 15); -                u8 src1 = BITS(16, 19); -                u8 src2 = BITS(0, 3); -                s16 a1 = (state->Reg[src1] & 0xFFFF); -                s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); -                s16 b1 = (state->Reg[src2] & 0xFFFF); -                s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); -                s32 res1 = (a1 + b1); -                s32 res2 = (a2 + b2); -                if (res1 > 0x7FFF) res1 = 0x7FFF; -                if (res2 > 0x7FFF) res2 = 0x7FFF; -                if (res1 < 0x7FFF) res1 = -0x8000; -                if (res2 < 0x7FFF) res2 = -0x8000; -                state->Reg[tar] = ((res1) & 0xFFFF) | (((res2) & 0xFFFF) << 0x10); +        case 0x62: // QSUB16 and QADD16 +            if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10) { +                const u8 rd_idx = BITS(12, 15); +                const u8 rn_idx = BITS(16, 19); +                const u8 rm_idx = BITS(0, 3); +                const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF); +                const s16 rm_hi = ((state->Reg[rm_idx] >> 0x10) & 0xFFFF); +                const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF); +                const s16 rn_hi = ((state->Reg[rn_idx] >> 0x10) & 0xFFFF); + +                s32 lo_result; +                s32 hi_result; + +                // QSUB16 +                if ((instr & 0xFF0) == 0xf70) { +                    lo_result = (rn_lo - rm_lo); +                    hi_result = (rn_hi - rm_hi); +                } +                else { // QADD16 +                    lo_result = (rn_lo + rm_lo); +                    hi_result = (rn_hi + rm_hi); +                } + +                if (lo_result > 0x7FFF) +                    lo_result = 0x7FFF; +                else if (lo_result < -0x8000) +                    lo_result = -0x8000; + +                if (hi_result > 0x7FFF) +                    hi_result = 0x7FFF; +                else if (hi_result < -0x8000) +                    hi_result = -0x8000; + +                state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);                  return 1; -            } else printf ("Unhandled v6 insn: qadd16/qsub16\n"); +            } else { +                printf("Unhandled v6 insn: %08x", BITS(20, 27)); +            }              break;          case 0x63:              printf ("Unhandled v6 insn: shadd/shsub\n"); 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 @@ +// 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_savedata.h" +#include "core/file_sys/disk_archive.h" +#include "core/settings.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +Archive_SaveData::Archive_SaveData(const std::string& mount_point, u64 program_id)  +        : DiskArchive(mount_point + Common::StringFromFormat("%016X", program_id) + DIR_SEP) { +    LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str()); +} + +bool Archive_SaveData::Initialize() { +    if (!FileUtil::CreateFullPath(mount_point)) { +        LOG_ERROR(Service_FS, "Unable to create SaveData path."); +        return false; +    } + +    return true; +} + +} // 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 @@ +// 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/disk_archive.h" +#include "core/loader/loader.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +/// File system interface to the SaveData archive +class Archive_SaveData final : public DiskArchive { +public: +    Archive_SaveData(const std::string& mount_point, u64 program_id); + +    /** +     * Initialize the archive. +     * @return CreateSaveDataResult AlreadyExists if the SaveData folder already exists, +     * Success if it was created properly and Failure if there was any error +     */ +    bool Initialize(); + +    std::string GetName() const override { return "SaveData"; } +}; + +} // 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 @@  #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" +#include "core/file_sys/disk_archive.h"  #include "core/settings.h"  //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -17,18 +16,10 @@  namespace FileSys { -Archive_SDMC::Archive_SDMC(const std::string& mount_point) { -    this->mount_point = mount_point; +Archive_SDMC::Archive_SDMC(const std::string& mount_point) : DiskArchive(mount_point) {      LOG_INFO(Service_FS, "Directory %s set as SDMC.", mount_point.c_str());  } -Archive_SDMC::~Archive_SDMC() { -} - -/** - * Initialize the archive. - * @return true if it initialized successfully - */  bool Archive_SDMC::Initialize() {      if (!Settings::values.use_virtual_sd) {          LOG_WARNING(Service_FS, "SDMC disabled by config."); @@ -43,74 +34,4 @@ bool Archive_SDMC::Initialize() {      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<FileBackend> Archive_SDMC::OpenFile(const Path& path, const Mode mode) const { -    LOG_DEBUG(Service_FS, "called path=%s mode=%u", path.DebugStr().c_str(), mode.hex); -    File_SDMC* file = new File_SDMC(this, path, mode); -    if (!file->Open()) -        return nullptr; -    return std::unique_ptr<FileBackend>(file); -} - -/** - * Delete a file specified by its path - * @param path Path relative to the archive - * @return Whether the file could be deleted - */ -bool Archive_SDMC::DeleteFile(const FileSys::Path& path) const { -    return FileUtil::Delete(GetMountPoint() + path.AsString()); -} - -bool Archive_SDMC::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const { -    return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); -} - -/** - * Delete a directory specified by its path - * @param path Path relative to the archive - * @return Whether the directory could be deleted - */ -bool Archive_SDMC::DeleteDirectory(const FileSys::Path& path) const { -    return FileUtil::DeleteDir(GetMountPoint() + path.AsString()); -} - -/** - * Create a directory specified by its path - * @param path Path relative to the archive - * @return Whether the directory could be created - */ -bool Archive_SDMC::CreateDirectory(const Path& path) const { -    return FileUtil::CreateDir(GetMountPoint() + path.AsString()); -} - -bool Archive_SDMC::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const { -    return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); -} - -/** - * Open a directory specified by its path - * @param path Path relative to the archive - * @return Opened directory, or nullptr - */ -std::unique_ptr<DirectoryBackend> Archive_SDMC::OpenDirectory(const Path& path) const { -    LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str()); -    Directory_SDMC* directory = new Directory_SDMC(this, path); -    if (!directory->Open()) -        return nullptr; -    return std::unique_ptr<DirectoryBackend>(directory); -} - -/** - * 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 index 059045245..c84c6948e 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h @@ -6,7 +6,7 @@  #include "common/common_types.h" -#include "core/file_sys/archive_backend.h" +#include "core/file_sys/disk_archive.h"  #include "core/loader/loader.h"  //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -15,10 +15,9 @@  namespace FileSys {  /// File system interface to the SDMC archive -class Archive_SDMC final : public ArchiveBackend { +class Archive_SDMC final : public DiskArchive {  public:      Archive_SDMC(const std::string& mount_point); -    ~Archive_SDMC() override;      /**       * Initialize the archive. @@ -27,67 +26,6 @@ public:      bool Initialize();      std::string GetName() const override { return "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<FileBackend> OpenFile(const Path& path, const Mode mode) const override; - -    /** -     * Delete a file specified by its path -     * @param path Path relative to the archive -     * @return Whether the file could be deleted -     */ -    bool DeleteFile(const FileSys::Path& path) const override; - -    /** -     * Rename a File specified by its path -     * @param src_path Source path relative to the archive -     * @param dest_path Destination path relative to the archive -     * @return Whether rename succeeded -     */ -    bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; - -    /** -     * Delete a directory specified by its path -     * @param path Path relative to the archive -     * @return Whether the directory could be deleted -     */ -    bool DeleteDirectory(const FileSys::Path& path) const override; - -    /** -     * Create a directory specified by its path -     * @param path Path relative to the archive -     * @return Whether the directory could be created -     */ -    bool CreateDirectory(const Path& path) const override; - -    /** -     * Rename a Directory specified by its path -     * @param src_path Source path relative to the archive -     * @param dest_path Destination path relative to the archive -     * @return Whether rename succeeded -     */ -    bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; - -    /** -     * Open a directory specified by its path -     * @param path Path relative to the archive -     * @return Opened directory, or nullptr -     */ -    std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const 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_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 @@ -// 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 Path& 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. -    this->path = archive->GetMountPoint() + path.AsString(); - -} - -Directory_SDMC::~Directory_SDMC() { -    Close(); -} - -bool Directory_SDMC::Open() { -    if (!FileUtil::IsDirectory(path)) -        return false; -    FileUtil::ScanDirectoryTree(path, directory); -    children_iterator = directory.children.begin(); -    return true; -} - -/** - * 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 entries_read = 0; - -    while (entries_read < count && children_iterator != directory.children.cend()) { -        const FileUtil::FSTEntry& file = *children_iterator; -        const std::string& filename = file.virtualName; -        Entry& entry = entries[entries_read]; - -        LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory); - -        // TODO(Link Mauve): use a proper conversion to UTF-16. -        for (size_t j = 0; j < FILENAME_LENGTH; ++j) { -            entry.filename[j] = filename[j]; -            if (!filename[j]) -                break; -        } - -        FileUtil::SplitFilename83(filename, entry.short_name, entry.extension); - -        entry.is_directory = file.isDirectory; -        entry.is_hidden = (filename[0] == '.'); -        entry.is_read_only = 0; -        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; - -        ++entries_read; -        ++children_iterator; -    } -    return entries_read; -} - -/** - * 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 deleted file mode 100644 index 407a256ef..000000000 --- a/src/core/file_sys/directory_sdmc.h +++ /dev/null @@ -1,55 +0,0 @@ -// 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_backend.h" -#include "core/file_sys/archive_sdmc.h" -#include "core/loader/loader.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -class Directory_SDMC final : public DirectoryBackend { -public: -    Directory_SDMC(); -    Directory_SDMC(const Archive_SDMC* archive, const Path& path); -    ~Directory_SDMC() override; - -    /** -    * Open the directory -    * @return true if the directory opened correctly -    */ -    bool Open() 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: -    std::string path; -    u32 total_entries_in_directory; -    FileUtil::FSTEntry directory; - -    // We need to remember the last entry we returned, so a subsequent call to Read will continue -    // from the next one.  This iterator will always point to the next unread entry. -    std::vector<FileUtil::FSTEntry>::iterator children_iterator; -}; - -} // namespace FileSys 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 @@ +// 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/disk_archive.h" +#include "core/settings.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +std::unique_ptr<FileBackend> DiskArchive::OpenFile(const Path& path, const Mode mode) const { +    LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex); +    DiskFile* file = new DiskFile(this, path, mode); +    if (!file->Open()) +        return nullptr; +    return std::unique_ptr<FileBackend>(file); +} + +bool DiskArchive::DeleteFile(const FileSys::Path& path) const { +    return FileUtil::Delete(GetMountPoint() + path.AsString()); +} + +bool DiskArchive::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const { +    return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); +} + +bool DiskArchive::DeleteDirectory(const FileSys::Path& path) const { +    return FileUtil::DeleteDir(GetMountPoint() + path.AsString()); +} + +bool DiskArchive::CreateDirectory(const Path& path) const { +    return FileUtil::CreateDir(GetMountPoint() + path.AsString()); +} + +bool DiskArchive::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const { +    return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); +} + +std::unique_ptr<DirectoryBackend> DiskArchive::OpenDirectory(const Path& path) const { +    LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str()); +    DiskDirectory* directory = new DiskDirectory(this, path); +    if (!directory->Open()) +        return nullptr; +    return std::unique_ptr<DirectoryBackend>(directory); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +DiskFile::DiskFile(const DiskArchive* archive, const Path& 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. +    this->path = archive->GetMountPoint() + path.AsString(); +    this->mode.hex = mode.hex; +    this->archive = archive; +} + +bool DiskFile::Open() { +    if (!mode.create_flag && !FileUtil::Exists(path)) { +        LOG_ERROR(Service_FS, "Non-existing file %s can’t be open without mode create.", path.c_str()); +        return false; +    } + +    std::string mode_string; +    if (mode.create_flag) +        mode_string = "w+"; +    else if (mode.write_flag) +        mode_string = "r+"; // Files opened with Write access can be read from +    else if (mode.read_flag) +        mode_string = "r"; + +    // Open the file in binary mode, to avoid problems with CR/LF on Windows systems +    mode_string += "b"; + +    file = new FileUtil::IOFile(path, mode_string.c_str()); +    return true; +} + +size_t DiskFile::Read(const u64 offset, const u32 length, u8* buffer) const { +    file->Seek(offset, SEEK_SET); +    return file->ReadBytes(buffer, length); +} + +size_t DiskFile::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 DiskFile::GetSize() const { +    return static_cast<size_t>(file->GetSize()); +} + +bool DiskFile::SetSize(const u64 size) const { +    file->Resize(size); +    file->Flush(); +    return true; +} + +bool DiskFile::Close() const { +    return file->Close(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +DiskDirectory::DiskDirectory(const DiskArchive* archive, const Path& 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. +    this->path = archive->GetMountPoint() + path.AsString(); +    this->archive = archive; +} + +bool DiskDirectory::Open() { +    if (!FileUtil::IsDirectory(path)) +        return false; +    FileUtil::ScanDirectoryTree(path, directory); +    children_iterator = directory.children.begin(); +    return true; +} + +u32 DiskDirectory::Read(const u32 count, Entry* entries) { +    u32 entries_read = 0; + +    while (entries_read < count && children_iterator != directory.children.cend()) { +        const FileUtil::FSTEntry& file = *children_iterator; +        const std::string& filename = file.virtualName; +        Entry& entry = entries[entries_read]; + +        LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory); + +        // TODO(Link Mauve): use a proper conversion to UTF-16. +        for (size_t j = 0; j < FILENAME_LENGTH; ++j) { +            entry.filename[j] = filename[j]; +            if (!filename[j]) +                break; +        } + +        FileUtil::SplitFilename83(filename, entry.short_name, entry.extension); + +        entry.is_directory = file.isDirectory; +        entry.is_hidden = (filename[0] == '.'); +        entry.is_read_only = 0; +        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; + +        ++entries_read; +        ++children_iterator; +    } +    return entries_read; +} + +} // 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 @@ +// 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_backend.h" +#include "core/loader/loader.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +/** + * Helper which implements a backend accessing the host machine's filesystem.  + * This should be subclassed by concrete archive types, which will provide the  + * base directory on the host filesystem and override any required functionality. + */ +class DiskArchive : public ArchiveBackend { +public: +    DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {} + +    virtual std::string GetName() const = 0; +    std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; +    bool DeleteFile(const FileSys::Path& path) const override; +    bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; +    bool DeleteDirectory(const FileSys::Path& path) const override; +    bool CreateDirectory(const Path& path) const override; +    bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; +    std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; + +    /** +     * Getter for the path used for this Archive +     * @return Mount point of that passthrough archive +     */ +    const std::string& GetMountPoint() const { +        return mount_point; +    } + +protected: +    std::string mount_point; +}; + +class DiskFile : public FileBackend { +public: +    DiskFile(); +    DiskFile(const DiskArchive* archive, const Path& path, const Mode mode); +     +    ~DiskFile() override { +        Close(); +    } + +    bool Open() override; +    size_t Read(const u64 offset, const u32 length, u8* buffer) const override; +    size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; +    size_t GetSize() const override; +    bool SetSize(const u64 size) const override; +    bool Close() const override; +     +    void Flush() const override { +        file->Flush(); +    } + +protected: +    const DiskArchive* archive; +    std::string path; +    Mode mode; +    FileUtil::IOFile* file; +}; + +class DiskDirectory : public DirectoryBackend { +public: +    DiskDirectory(); +    DiskDirectory(const DiskArchive* archive, const Path& path); + +    ~DiskDirectory() override { +        Close(); +    } + +    bool Open() override; +    u32 Read(const u32 count, Entry* entries) override; + +    bool Close() const override { +        return true; +    } + +protected: +    const DiskArchive* archive; +    std::string path; +    u32 total_entries_in_directory; +    FileUtil::FSTEntry directory; + +    // We need to remember the last entry we returned, so a subsequent call to Read will continue +    // from the next one.  This iterator will always point to the next unread entry. +    std::vector<FileUtil::FSTEntry>::iterator children_iterator; +}; + +} // namespace FileSys 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:       * @return true if the file closed correctly       */      virtual bool Close() const = 0; + +    /** +     * Flushes the file +     */ +    virtual void Flush() const = 0;  };  } // 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:       */      bool Close() const override; +    void Flush() const override { } +  private:      const Archive_RomFS* archive;  }; 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 @@ -// 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 Path& 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. -    this->path = archive->GetMountPoint() + path.AsString(); -    this->mode.hex = mode.hex; -} - -File_SDMC::~File_SDMC() { -    Close(); -} - -/** - * Open the file - * @return true if the file opened correctly - */ -bool File_SDMC::Open() { -    if (!mode.create_flag && !FileUtil::Exists(path)) { -        LOG_ERROR(Service_FS, "Non-existing file %s can’t be open without mode create.", path.c_str()); -        return false; -    } - -    std::string mode_string; -    if (mode.create_flag) -        mode_string = "w+"; -    else if (mode.write_flag) -        mode_string = "r+"; // Files opened with Write access can be read from -    else if (mode.read_flag) -        mode_string = "r"; -     -    // Open the file in binary mode, to avoid problems with CR/LF on Windows systems -    mode_string += "b"; - -    file = new FileUtil::IOFile(path, mode_string.c_str()); -    return true; -} - -/** - * 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_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { -    file->Seek(offset, SEEK_SET); -    return file->ReadBytes(buffer, length); -} - -/** - * 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 flush The flush parameters (0 == do not flush) - * @param buffer Buffer to read data from - * @return Number of bytes written - */ -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; -} - -/** - * Get the size of the file in bytes - * @return Size of the file in bytes - */ -size_t File_SDMC::GetSize() const { -    return static_cast<size_t>(file->GetSize()); -} - -/** - * Set the size of the file in bytes - * @param size New size of the file - * @return true if successful - */ -bool File_SDMC::SetSize(const u64 size) const { -    file->Resize(size); -    file->Flush(); -    return true; -} - -/** - * Close the file - * @return true if the file closed correctly - */ -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 deleted file mode 100644 index e01548598..000000000 --- a/src/core/file_sys/file_sdmc.h +++ /dev/null @@ -1,75 +0,0 @@ -// 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_backend.h" -#include "core/file_sys/archive_sdmc.h" -#include "core/loader/loader.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -class File_SDMC final : public FileBackend { -public: -    File_SDMC(); -    File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode); -    ~File_SDMC() override; - -    /** -     * Open the file -     * @return true if the file opened correctly -     */ -    bool Open() 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 flush The flush parameters (0 == do not flush) -     * @param buffer Buffer to read data from -     * @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; - -    /** -     * Set the size of the file in bytes -     * @param size New size of the file -     * @return true if successful -     */ -    bool SetSize(const u64 size) const override; - -    /** -     * Close the file -     * @return true if the file closed correctly -     */ -    bool Close() const override; - -private: -    std::string path; -    Mode mode; -    FileUtil::IOFile* file; -}; - -} // namespace FileSys diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 929422b36..6a690e915 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -14,6 +14,7 @@ namespace Kernel {  Handle g_main_thread = 0;  ObjectPool g_object_pool; +u64 g_program_id = 0;  ObjectPool::ObjectPool() {      next_id = INITIAL_NEXT_ID; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 7e0f15c84..7123485be 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -151,6 +151,12 @@ private:  extern ObjectPool g_object_pool;  extern Handle g_main_thread; +/// The ID code of the currently running game +/// TODO(Subv): This variable should not be here,  +/// we need a way to store information about the currently loaded application  +/// for later query during runtime, maybe using the LDR service? +extern u64 g_program_id; +  /// Initialize the kernel  void Init(); diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 304cf5b67..bb778ec26 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -12,11 +12,15 @@ namespace Kernel {  /// Permissions for mapped shared memory blocks  enum class MemoryPermission : u32 { -    None        = 0, -    Read        = (1u <<  0), -    Write       = (1u <<  1), -    ReadWrite   = (Read | Write), -    DontCare    = (1u << 28) +    None             = 0, +    Read             = (1u <<  0), +    Write            = (1u <<  1), +    ReadWrite        = (Read | Write), +    Execute          = (1u <<  2), +    ReadExecute      = (Read | Execute), +    WriteExecute     = (Write | Execute), +    ReadWriteExecute = (Read | Write | Execute), +    DontCare         = (1u << 28)  };  /** diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 15c4a2677..14d2be4a2 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -17,6 +17,8 @@  /// Detailed description of the error. This listing is likely incomplete.  enum class ErrorDescription : u32 {      Success = 0, +    FS_NotFound = 100, +    FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive      InvalidSection = 1000,      TooLarge = 1001,      NotAuthorized = 1002, diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index caf82d556..9c3834733 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -9,6 +9,7 @@  #include "common/file_util.h"  #include "common/math_util.h" +#include "core/file_sys/archive_savedata.h"  #include "core/file_sys/archive_backend.h"  #include "core/file_sys/archive_sdmc.h"  #include "core/file_sys/directory_backend.h" @@ -135,6 +136,13 @@ public:              break;          } +        case FileCommand::Flush: +        { +            LOG_TRACE(Service_FS, "Flush"); +            backend->Flush(); +            break; +        } +          // Unknown command...          default:              LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); @@ -220,9 +228,18 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code) {      auto itr = id_code_map.find(id_code);      if (itr == id_code_map.end()) { +        if (id_code == ArchiveIdCode::SaveData) { +            // When a SaveData archive is created for the first time, it is not yet formatted +            // and the save file/directory structure expected by the game has not yet been initialized.  +            // Returning the NotFormatted error code will signal the game to provision the SaveData archive  +            // with the files and folders that it expects.  +            // The FormatSaveData service call will create the SaveData archive when it is called. +            return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, +                              ErrorSummary::InvalidState, ErrorLevel::Status); +        }          // TODO: Verify error against hardware          return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, -                ErrorSummary::NotFound, ErrorLevel::Permanent); +                          ErrorSummary::NotFound, ErrorLevel::Permanent);      }      // This should never even happen in the first place with 64-bit handles,  @@ -260,8 +277,8 @@ ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSy      std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode);      if (backend == nullptr) { -        return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, -                          ErrorSummary::NotFound, ErrorLevel::Permanent); +        return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, +                          ErrorSummary::NotFound, ErrorLevel::Status);      }      auto file = std::make_unique<File>(std::move(backend), path); @@ -366,6 +383,28 @@ ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const F      return MakeResult<Handle>(handle);  } +ResultCode FormatSaveData() { +    // TODO(Subv): Actually wipe the savedata folder after creating or opening it + +    // Do not create the archive again if it already exists +    if (id_code_map.find(ArchiveIdCode::SaveData) != id_code_map.end()) +        return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the correct error code + +    // Create the SaveData archive +    std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX); +    auto savedata_archive = std::make_unique<FileSys::Archive_SaveData>(savedata_directory, +        Kernel::g_program_id); + +    if (savedata_archive->Initialize()) { +        CreateArchive(std::move(savedata_archive), ArchiveIdCode::SaveData); +        return RESULT_SUCCESS; +    } else { +        LOG_ERROR(Service_FS, "Can't instantiate SaveData archive with path %s", +            savedata_archive->GetMountPoint().c_str()); +        return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the proper error code +    } +} +  /// Initialize archives  void ArchiveInit() {      next_handle = 1; @@ -375,9 +414,9 @@ void ArchiveInit() {      // archive type is SDMC, so it is the only one getting exposed.      std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); -    auto archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory); -    if (archive->Initialize()) -        CreateArchive(std::move(archive), ArchiveIdCode::SDMC); +    auto sdmc_archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory); +    if (sdmc_archive->Initialize()) +        CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC);      else          LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());  } diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index a38de92e3..a128276b6 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -109,6 +109,12 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons   */  ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); +/** + * Creates a blank SaveData archive. + * @return ResultCode 0 on success or the corresponding code on error + */ +ResultCode FormatSaveData(); +  /// Initialize archives  void ArchiveInit(); diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 0f75d5e3a..f99d84b2f 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -3,11 +3,11 @@  // Refer to the license.txt file included.  #include "common/common.h" +#include "common/file_util.h"  #include "common/scope_exit.h" -  #include "common/string_util.h" -#include "core/hle/service/fs/archive.h"  #include "core/hle/result.h" +#include "core/hle/service/fs/archive.h"  #include "core/hle/service/fs/fs_user.h"  #include "core/settings.h" @@ -50,9 +50,7 @@ static void Initialize(Service::Interface* self) {  static void OpenFile(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); -    // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to -    // 3dmoo's or ctrulib's implementations.  Triple check if it's really the case. -    Handle archive_handle = static_cast<Handle>(cmd_buff[3]); +    ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);      auto filename_type    = static_cast<FileSys::LowPathType>(cmd_buff[4]);      u32 filename_size     = cmd_buff[5];      FileSys::Mode mode; mode.hex = cmd_buff[6]; @@ -398,6 +396,36 @@ static void IsSdmcDetected(Service::Interface* self) {      LOG_DEBUG(Service_FS, "called");  } +/** + * FS_User::FormatSaveData service function + *  Inputs: + *  Outputs: + *      1 : Result of function, 0 on success, otherwise error code + */ +static void FormatSaveData(Service::Interface* self) { +    u32* cmd_buff = Kernel::GetCommandBuffer(); +    LOG_DEBUG(Service_FS, "(STUBBED)"); + +    // TODO(Subv): Find out what the inputs and outputs of this function are + +    cmd_buff[1] = FormatSaveData().raw; +} + +/** + * FS_User::FormatThisUserSaveData service function + *  Inputs: + *  Outputs: + *      1 : Result of function, 0 on success, otherwise error code + */ +static void FormatThisUserSaveData(Service::Interface* self) { +    u32* cmd_buff = Kernel::GetCommandBuffer(); +    LOG_DEBUG(Service_FS, "(STUBBED)"); + +    // TODO(Subv): Find out what the inputs and outputs of this function are + +    cmd_buff[1] = FormatSaveData().raw; +} +  const FSUserInterface::FunctionInfo FunctionTable[] = {      {0x000100C6, nullptr,               "Dummy1"},      {0x040100C4, nullptr,               "Control"}, @@ -415,7 +443,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = {      {0x080C00C2, OpenArchive,           "OpenArchive"},      {0x080D0144, nullptr,               "ControlArchive"},      {0x080E0080, CloseArchive,          "CloseArchive"}, -    {0x080F0180, nullptr,               "FormatThisUserSaveData"}, +    {0x080F0180, FormatThisUserSaveData,"FormatThisUserSaveData"},      {0x08100200, nullptr,               "CreateSystemSaveData"},      {0x08110040, nullptr,               "DeleteSystemSaveData"},      {0x08120080, nullptr,               "GetFreeBytes"}, @@ -476,7 +504,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = {      {0x08490040, nullptr,               "GetArchiveResource"},      {0x084A0002, nullptr,               "ExportIntegrityVerificationSeed"},      {0x084B0002, nullptr,               "ImportIntegrityVerificationSeed"}, -    {0x084C0242, nullptr,               "FormatSaveData"}, +    {0x084C0242, FormatSaveData,        "FormatSaveData"},      {0x084D0102, nullptr,               "GetLegacySubBannerData"},      {0x084E0342, nullptr,               "UpdateSha256Context"},      {0x084F0102, nullptr,               "ReadSpecialFile"}, diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 15cc240f4..47e9bf77e 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -64,6 +64,10 @@ static Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other      case Kernel::MemoryPermission::Read:      case Kernel::MemoryPermission::Write:      case Kernel::MemoryPermission::ReadWrite: +    case Kernel::MemoryPermission::Execute: +    case Kernel::MemoryPermission::ReadExecute: +    case Kernel::MemoryPermission::WriteExecute: +    case Kernel::MemoryPermission::ReadWriteExecute:      case Kernel::MemoryPermission::DontCare:          Kernel::MapSharedMemory(handle, addr, permissions_type,              static_cast<Kernel::MemoryPermission>(other_permissions)); diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 463dacca3..480274d23 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -74,6 +74,7 @@ ResultStatus LoadFile(const std::string& filename) {          // Load application and RomFS          if (ResultStatus::Success == app_loader.Load()) { +            Kernel::g_program_id = app_loader.GetProgramId();              Service::FS::CreateArchive(std::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS);              return ResultStatus::Success;          } diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index ba9ba00c0..4d23656ec 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -315,4 +315,8 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {      return ResultStatus::Error;  } +u64 AppLoader_NCCH::GetProgramId() const { +    return *reinterpret_cast<u64 const*>(&ncch_header.program_id[0]); +} +  } // namespace Loader diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h index 03116add8..2fe2a7d82 100644 --- a/src/core/loader/ncch.h +++ b/src/core/loader/ncch.h @@ -191,6 +191,12 @@ public:       */      ResultStatus ReadRomFS(std::vector<u8>& buffer) const override; +    /* +     * Gets the program id from the NCCH header +     * @return u64 Program id +     */ +    u64 GetProgramId() const; +  private:      /** | 
