diff options
| -rw-r--r-- | src/core/file_sys/archive_backend.h | 18 | ||||
| -rw-r--r-- | src/core/file_sys/archive_extsavedata.cpp | 36 | ||||
| -rw-r--r-- | src/core/file_sys/archive_extsavedata.h | 11 | ||||
| -rw-r--r-- | src/core/file_sys/archive_romfs.cpp | 8 | ||||
| -rw-r--r-- | src/core/file_sys/archive_romfs.h | 3 | ||||
| -rw-r--r-- | src/core/file_sys/archive_savedata.cpp | 32 | ||||
| -rw-r--r-- | src/core/file_sys/archive_savedata.h | 4 | ||||
| -rw-r--r-- | src/core/file_sys/archive_savedatacheck.cpp | 8 | ||||
| -rw-r--r-- | src/core/file_sys/archive_savedatacheck.h | 3 | ||||
| -rw-r--r-- | src/core/file_sys/archive_sdmc.cpp | 7 | ||||
| -rw-r--r-- | src/core/file_sys/archive_sdmc.h | 3 | ||||
| -rw-r--r-- | src/core/file_sys/archive_systemsavedata.cpp | 8 | ||||
| -rw-r--r-- | src/core/file_sys/archive_systemsavedata.h | 3 | ||||
| -rw-r--r-- | src/core/hle/result.h | 1 | ||||
| -rw-r--r-- | src/core/hle/service/cfg/cfg.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/fs/archive.cpp | 48 | ||||
| -rw-r--r-- | src/core/hle/service/fs/archive.h | 15 | ||||
| -rw-r--r-- | src/core/hle/service/fs/fs_user.cpp | 107 | ||||
| -rw-r--r-- | src/core/hle/service/ptm/ptm.cpp | 2 | 
19 files changed, 257 insertions, 62 deletions
| diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index 60108b4b0..800ac1541 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h @@ -62,6 +62,14 @@ private:      std::u16string u16str;  }; +struct ArchiveFormatInfo { +    u32 total_size; ///< The pre-defined size of the archive, as specified in the Create or Format call +    u32 number_directories; ///< The pre-defined number of directories in the archive, as specified in the Create or Format call +    u32 number_files; ///< The pre-defined number of files in the archive, as specified in the Create or Format call +    u8 duplicate_data; ///< Whether the archive should duplicate the data, as specified in the Create or Format call +}; +static_assert(std::is_pod<ArchiveFormatInfo>::value, "ArchiveFormatInfo is not POD"); +  class ArchiveBackend : NonCopyable {  public:      virtual ~ArchiveBackend() { @@ -159,9 +167,17 @@ public:      /**       * Deletes the archive contents and then re-creates the base folder       * @param path Path to the archive +     * @param format_info Format information for the new archive       * @return ResultCode of the operation, 0 on success       */ -    virtual ResultCode Format(const Path& path) = 0; +    virtual ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) = 0; + +    /* +     * Retrieves the format info about the archive with the specified path +     * @param path Path to the archive +     * @return Format information about the archive or error code +     */ +    virtual ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const = 0;  };  } // namespace FileSys diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp index 92dad8e6f..e83a6153d 100644 --- a/src/core/file_sys/archive_extsavedata.cpp +++ b/src/core/file_sys/archive_extsavedata.cpp @@ -82,13 +82,45 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(cons      return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));  } -ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path) { +ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {      // These folders are always created with the ExtSaveData      std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/";      std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/";      FileUtil::CreateFullPath(user_path);      FileUtil::CreateFullPath(boss_path); -    return RESULT_SUCCESS; + +    // Write the format metadata +    std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata"; +    FileUtil::IOFile file(metadata_path, "wb"); + +    if (file.IsOpen()) { +        file.WriteBytes(&format_info, sizeof(format_info)); +        return RESULT_SUCCESS; +    } + +    // TODO(Subv): Find the correct error code +    return ResultCode(-1); +} + +ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Path& path) const { +    std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata"; +    FileUtil::IOFile file(metadata_path, "rb"); + +    if (file.IsOpen()) { +        ArchiveFormatInfo info; +        file.ReadBytes(&info, sizeof(info)); +        return MakeResult<ArchiveFormatInfo>(info); +    } + +    LOG_ERROR(Service_FS, "Could not open metadata information for archive"); +    // TODO(Subv): Verify error code +    return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status); +} + +void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, u8* icon_data, u32 icon_size) { +    std::string game_path = FileSys::GetExtSaveDataPath(GetMountPoint(), path); +    FileUtil::IOFile icon_file(game_path + "icon", "wb+"); +    icon_file.WriteBytes(icon_data, icon_size);  }  } // namespace FileSys diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h index ec8d770fc..48e092ee7 100644 --- a/src/core/file_sys/archive_extsavedata.h +++ b/src/core/file_sys/archive_extsavedata.h @@ -31,10 +31,19 @@ public:      std::string GetName() const override { return "ExtSaveData"; }      ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; -    ResultCode Format(const Path& path) override; +    ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; +    ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;      const std::string& GetMountPoint() const { return mount_point; } +    /* +     * Writes the SMDH icon of the ExtSaveData to file +     * @param path Path of this ExtSaveData +     * @param icon_data Binary data of the icon +     * @param icon_size Size of the icon data +     */ +    void WriteIcon(const Path& path, u8* icon_data, u32 icon_size); +  private:      /**       * This holds the full directory path for this archive, it is only set after a successful call diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index 696b51a94..a9a29ebde 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp @@ -29,11 +29,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path      return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));  } -ResultCode ArchiveFactory_RomFS::Format(const Path& path) { +ResultCode ArchiveFactory_RomFS::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {      LOG_ERROR(Service_FS, "Attempted to format a RomFS archive.");      // TODO: Verify error code      return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS,              ErrorSummary::NotSupported, ErrorLevel::Permanent);  } +ResultVal<ArchiveFormatInfo> ArchiveFactory_RomFS::GetFormatInfo(const Path& path) const { +    // TODO(Subv): Implement +    LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); +    return ResultCode(-1); +} +  } // namespace FileSys diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index 2bedfa9c6..c5a329122 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h @@ -26,7 +26,8 @@ public:      std::string GetName() const override { return "RomFS"; }      ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; -    ResultCode Format(const Path& path) override; +    ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; +    ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;  private:      std::shared_ptr<FileUtil::IOFile> romfs_file; diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp index 12876899f..82f49af5d 100644 --- a/src/core/file_sys/archive_savedata.cpp +++ b/src/core/file_sys/archive_savedata.cpp @@ -31,6 +31,12 @@ static std::string GetSaveDataPath(const std::string& mount_location, u64 progra      return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high, low);  } +static std::string GetSaveDataMetadataPath(const std::string& mount_location, u64 program_id) { +    u32 high = program_id >> 32; +    u32 low = program_id & 0xFFFFFFFF; +    return Common::StringFromFormat("%s%08x/%08x/data/00000001.metadata", mount_location.c_str(), high, low); +} +  ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directory)          : mount_point(GetSaveDataContainerPath(sdmc_directory)) {      LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str()); @@ -51,11 +57,35 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const P      return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));  } -ResultCode ArchiveFactory_SaveData::Format(const Path& path) { +ResultCode ArchiveFactory_SaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {      std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);      FileUtil::DeleteDirRecursively(concrete_mount_point);      FileUtil::CreateFullPath(concrete_mount_point); + +    // Write the format metadata +    std::string metadata_path = GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id); +    FileUtil::IOFile file(metadata_path, "wb"); + +    if (file.IsOpen()) { +        file.WriteBytes(&format_info, sizeof(format_info)); +        return RESULT_SUCCESS; +    }      return RESULT_SUCCESS;  } +ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveData::GetFormatInfo(const Path& path) const { +    std::string metadata_path = GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id); +    FileUtil::IOFile file(metadata_path, "rb"); + +    if (file.IsOpen()) { +        ArchiveFormatInfo info; +        file.ReadBytes(&info, sizeof(info)); +        return MakeResult<ArchiveFormatInfo>(info); +    } + +    LOG_ERROR(Service_FS, "Could not open metadata information for archive"); +    // TODO(Subv): Verify error code +    return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status); +} +  } // namespace FileSys diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h index 1f65297dd..7a5a24089 100644 --- a/src/core/file_sys/archive_savedata.h +++ b/src/core/file_sys/archive_savedata.h @@ -23,7 +23,9 @@ public:      std::string GetName() const override { return "SaveData"; }      ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; -    ResultCode Format(const Path& path) override; +    ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; + +    ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;  private:      std::string mount_point; diff --git a/src/core/file_sys/archive_savedatacheck.cpp b/src/core/file_sys/archive_savedatacheck.cpp index ea1dfe2c7..3db11c500 100644 --- a/src/core/file_sys/archive_savedatacheck.cpp +++ b/src/core/file_sys/archive_savedatacheck.cpp @@ -48,11 +48,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveDataCheck::Open(co      return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));  } -ResultCode ArchiveFactory_SaveDataCheck::Format(const Path& path) { +ResultCode ArchiveFactory_SaveDataCheck::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {      LOG_ERROR(Service_FS, "Attempted to format a SaveDataCheck archive.");      // TODO: Verify error code      return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS,          ErrorSummary::NotSupported, ErrorLevel::Permanent);  } +ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveDataCheck::GetFormatInfo(const Path& path) const { +    // TODO(Subv): Implement +    LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); +    return ResultCode(-1); +} +  } // namespace FileSys diff --git a/src/core/file_sys/archive_savedatacheck.h b/src/core/file_sys/archive_savedatacheck.h index b14aefe8b..ea2624d64 100644 --- a/src/core/file_sys/archive_savedatacheck.h +++ b/src/core/file_sys/archive_savedatacheck.h @@ -23,7 +23,8 @@ public:      std::string GetName() const override { return "SaveDataCheck"; }      ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; -    ResultCode Format(const Path& path) override; +    ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; +    ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;  private:      std::string mount_point; diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index 5c825f429..657221cbf 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp @@ -40,9 +40,14 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path&      return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));  } -ResultCode ArchiveFactory_SDMC::Format(const Path& path) { +ResultCode ArchiveFactory_SDMC::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {      // This is kind of an undesirable operation, so let's just ignore it. :)      return RESULT_SUCCESS;  } +ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMC::GetFormatInfo(const Path& path) const { +    // TODO(Subv): Implement +    LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); +    return ResultCode(-1); +}  } // namespace FileSys diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 10b273bdb..35c0f3725 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h @@ -29,7 +29,8 @@ public:      std::string GetName() const override { return "SDMC"; }      ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; -    ResultCode Format(const Path& path) override; +    ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; +    ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;  private:      std::string sdmc_directory; diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp index 896f89529..e1780de2f 100644 --- a/src/core/file_sys/archive_systemsavedata.cpp +++ b/src/core/file_sys/archive_systemsavedata.cpp @@ -63,11 +63,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(c      return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));  } -ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path) { +ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {      std::string fullpath = GetSystemSaveDataPath(base_path, path);      FileUtil::DeleteDirRecursively(fullpath);      FileUtil::CreateFullPath(fullpath);      return RESULT_SUCCESS;  } +ResultVal<ArchiveFormatInfo> ArchiveFactory_SystemSaveData::GetFormatInfo(const Path& path) const { +    // TODO(Subv): Implement +    LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); +    return ResultCode(-1); +} +  } // namespace FileSys diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h index afc689848..2bc13d4ee 100644 --- a/src/core/file_sys/archive_systemsavedata.h +++ b/src/core/file_sys/archive_systemsavedata.h @@ -23,7 +23,8 @@ public:      ArchiveFactory_SystemSaveData(const std::string& mount_point);      ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; -    ResultCode Format(const Path& path) override; +    ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; +    ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;      std::string GetName() const override { return "SystemSaveData"; } diff --git a/src/core/hle/result.h b/src/core/hle/result.h index b68c0ff0d..0cb76ba1c 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -24,6 +24,7 @@ enum class ErrorDescription : u32 {      FS_InvalidOpenFlags = 230,      FS_NotAFile = 250,      FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive +    FS_InvalidPath = 702,      InvalidSection = 1000,      TooLarge = 1001,      NotAuthorized = 1002, diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 4c82a58e4..7bcedc0ae 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -407,7 +407,7 @@ void Init() {      // If the archive didn't exist, create the files inside      if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {          // Format the archive to create the directories -        Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); +        Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, FileSys::ArchiveFormatInfo(), archive_path);          // Open it again to get a valid archive now that the folder exists          archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index b034de8f1..63381250a 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -421,49 +421,45 @@ ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) {      return MakeResult<u64>(archive->GetFreeBytes());  } -ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { +ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, const FileSys::Path& path) {      auto archive_itr = id_code_map.find(id_code);      if (archive_itr == id_code_map.end()) {          return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error      } -    return archive_itr->second->Format(path); +    return archive_itr->second->Format(path, format_info);  } -ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size) { +ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code, FileSys::Path& archive_path) { +    auto archive = id_code_map.find(id_code); +    if (archive == id_code_map.end()) { +        return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error +    } + +    return archive->second->GetFormatInfo(archive_path); +} + +ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size, const FileSys::ArchiveFormatInfo& format_info) {      // Construct the binary path to the archive first      FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); -    std::string media_type_directory; -    if (media_type == MediaType::NAND) { -        media_type_directory = FileUtil::GetUserPath(D_NAND_IDX); -    } else if (media_type == MediaType::SDMC) { -        media_type_directory = FileUtil::GetUserPath(D_SDMC_IDX); -    } else { -        LOG_ERROR(Service_FS, "Unsupported media type %u", media_type); -        return ResultCode(-1); // TODO(Subv): Find the right error code +    auto archive = id_code_map.find(media_type == MediaType::NAND ? ArchiveIdCode::SharedExtSaveData : ArchiveIdCode::ExtSaveData); + +    if (archive == id_code_map.end()) { +        return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error      } -    std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); -    std::string game_path = FileSys::GetExtSaveDataPath(base_path, path); -    // These two folders are always created with the ExtSaveData -    std::string user_path = game_path + "user/"; -    std::string boss_path = game_path + "boss/"; -    if (!FileUtil::CreateFullPath(user_path)) -        return ResultCode(-1); // TODO(Subv): Find the right error code -    if (!FileUtil::CreateFullPath(boss_path)) -        return ResultCode(-1); // TODO(Subv): Find the right error code +    auto ext_savedata = static_cast<FileSys::ArchiveFactory_ExtSaveData*>(archive->second.get()); + +    ResultCode result = ext_savedata->Format(path, format_info); +    if (result.IsError()) +        return result;      u8* smdh_icon = Memory::GetPointer(icon_buffer);      if (!smdh_icon)          return ResultCode(-1); // TODO(Subv): Find the right error code -    // Create the icon -    FileUtil::IOFile icon_file(game_path + "icon", "wb+"); -    if (!icon_file.IsGood()) -        return ResultCode(-1); // TODO(Subv): Find the right error code - -    icon_file.WriteBytes(smdh_icon, icon_size); +    ext_savedata->WriteIcon(path, smdh_icon, icon_size);      return RESULT_SUCCESS;  } diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 430dc2ef9..b17d7c902 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -177,10 +177,20 @@ ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle);   * Erases the contents of the physical folder that contains the archive   * identified by the specified id code and path   * @param id_code The id of the archive to format + * @param format_info Format information about the new archive   * @param path The path to the archive, if relevant.   * @return ResultCode 0 on success or the corresponding code on error   */ -ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = FileSys::Path()); +ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, const FileSys::Path& path = FileSys::Path()); + +/* + * Retrieves the format info about the archive of the specified type and path. + * The format info is supplied by the client code when creating archives. + * @param id_code The id of the archive + * @param archive_path The path of the archive, if relevant + * @return The format info of the archive, or the corresponding error code if failed. + */ +ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code, FileSys::Path& archive_path);  /**   * Creates a blank SharedExtSaveData archive for the specified extdata ID @@ -189,9 +199,10 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = File   * @param low The low word of the extdata id to create   * @param icon_buffer VAddr of the SMDH icon for this ExtSaveData   * @param icon_size Size of the SMDH icon + * @param format_info Format information about the new archive   * @return ResultCode 0 on success or the corresponding code on error   */ -ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size); +ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size, const FileSys::ArchiveFormatInfo& format_info);  /**   * Deletes the SharedExtSaveData archive for the specified extdata ID diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 12ed609e9..ff7a9975e 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -443,17 +443,22 @@ static void IsSdmcWriteable(Service::Interface* self) {   *  Inputs:   *      0  : 0x084C0242   *      1  : Archive ID - *      2  : Archive low path type - *      3  : Archive low path size - *      10 : (LowPathSize << 14) | 2 + *      2  : Archive path type + *      3  : Archive path size + *      4  : Size in Blocks (1 block = 512 bytes) + *      5  : Number of directories + *      6  : Number of files + *      7  : Directory bucket count + *      8  : File bucket count + *      9  : Duplicate data + *      10 : (PathSize << 14) | 2   *      11 : Archive low path   *  Outputs:   *      1 : Result of function, 0 on success, otherwise error code   */  static void FormatSaveData(Service::Interface* self) { -    // TODO(Subv): Find out what the other inputs and outputs of this function are      u32* cmd_buff = Kernel::GetCommandBuffer(); -    LOG_DEBUG(Service_FS, "(STUBBED)"); +    LOG_WARNING(Service_FS, "(STUBBED)");      auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);      auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); @@ -464,9 +469,9 @@ static void FormatSaveData(Service::Interface* self) {      LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str());      if (archive_id != FS::ArchiveIdCode::SaveData) { -        // TODO(Subv): What should happen if somebody attempts to format a different archive? -        LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", cmd_buff[1]); -        cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; +        LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", archive_id); +        cmd_buff[1] = ResultCode(ErrorDescription::FS_InvalidPath, ErrorModule::FS, +                                 ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw;          return;      } @@ -477,23 +482,40 @@ static void FormatSaveData(Service::Interface* self) {          return;      } -    cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw; +    FileSys::ArchiveFormatInfo format_info; +    format_info.duplicate_data = cmd_buff[9] & 0xFF; +    format_info.number_directories = cmd_buff[5]; +    format_info.number_files = cmd_buff[6]; +    format_info.total_size = cmd_buff[4] * 512; + +    cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData, format_info).raw;  }  /**   * FS_User::FormatThisUserSaveData service function   *  Inputs:   *      0: 0x080F0180 + *      1  : Size in Blocks (1 block = 512 bytes) + *      2  : Number of directories + *      3  : Number of files + *      4  : Directory bucket count + *      5  : File bucket count + *      6  : Duplicate data   *  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 +    FileSys::ArchiveFormatInfo format_info; +    format_info.duplicate_data = cmd_buff[6] & 0xFF; +    format_info.number_directories = cmd_buff[2]; +    format_info.number_files = cmd_buff[3]; +    format_info.total_size = cmd_buff[1] * 512; -    cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw; +    cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData, format_info).raw; + +    LOG_TRACE(Service_FS, "called");  }  /** @@ -531,10 +553,9 @@ static void GetFreeBytes(Service::Interface* self) {   *      2 : Low word of the saveid to create   *      3 : High word of the saveid to create   *      4 : Unknown - *      5 : Unknown - *      6 : Unknown - *      7 : Unknown - *      8 : Unknown + *      5 : Number of directories + *      6 : Number of files + *      7-8 : Size limit   *      9 : Size of the SMDH icon   *      10: (SMDH Size << 4) | 0x0000000A   *      11: Pointer to the SMDH icon for the new ExtSaveData @@ -556,7 +577,12 @@ static void CreateExtSaveData(Service::Interface* self) {              cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], icon_size,              cmd_buff[10], icon_buffer); -    cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size).raw; +    FileSys::ArchiveFormatInfo format_info; +    format_info.number_directories = cmd_buff[5]; +    format_info.number_files = cmd_buff[6]; +    format_info.duplicate_data = false; +    format_info.total_size = 0; +    cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size, format_info).raw;  }  /** @@ -731,6 +757,51 @@ static void GetArchiveResource(Service::Interface* self) {      cmd_buff[5] = 0x80000; // 8GiB free  } +/** + * FS_User::GetFormatInfo service function. + *  Inputs: + *      0 : 0x084500C2 + *      1 : Archive ID + *      2 : Archive path type + *      3 : Archive path size + *      4 : (PathSize << 14) | 2 + *      5 : Archive low path + *  Outputs: + *      0 : 0x08450140 + *      1 : Result of function, 0 on success, otherwise error code + *      2 : Total size + *      3 : Number of directories + *      4 : Number of files + *      5 : Duplicate data + */ +static void GetFormatInfo(Service::Interface* self) { +    u32* cmd_buff = Kernel::GetCommandBuffer(); + +    auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]); +    auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); +    u32 archivename_size = cmd_buff[3]; +    u32 archivename_ptr = cmd_buff[5]; +    FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr); + +    LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str()); + +    cmd_buff[0] = IPC::MakeHeader(0x0845, 5, 0); + +    auto format_info = GetArchiveFormatInfo(archive_id, archive_path); + +    if (format_info.Failed()) { +        LOG_ERROR(Service_FS, "Failed to retrieve the format info"); +        cmd_buff[1] = format_info.Code().raw; +        return; +    } + +    cmd_buff[1] = RESULT_SUCCESS.raw; +    cmd_buff[2] = format_info->total_size; +    cmd_buff[3] = format_info->number_directories; +    cmd_buff[4] = format_info->number_files; +    cmd_buff[5] = format_info->duplicate_data; +} +  const Interface::FunctionInfo FunctionTable[] = {      {0x000100C6, nullptr,                  "Dummy1"},      {0x040100C4, nullptr,                  "Control"}, @@ -802,7 +873,7 @@ const Interface::FunctionInfo FunctionTable[] = {      {0x08420040, nullptr,                  "DeleteAllExtSaveDataOnNand"},      {0x08430000, nullptr,                  "InitializeCtrFileSystem"},      {0x08440000, nullptr,                  "CreateSeed"}, -    {0x084500C2, nullptr,                  "GetFormatInfo"}, +    {0x084500C2, GetFormatInfo,            "GetFormatInfo"},      {0x08460102, nullptr,                  "GetLegacyRomHeader2"},      {0x08470180, nullptr,                  "FormatCtrCardUserSaveData"},      {0x08480042, nullptr,                  "GetSdmcCtrRootPath"}, diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp index 6bdee4d9e..94f494690 100644 --- a/src/core/hle/service/ptm/ptm.cpp +++ b/src/core/hle/service/ptm/ptm.cpp @@ -103,7 +103,7 @@ void Init() {      // If the archive didn't exist, create the files inside      if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {          // Format the archive to create the directories -        Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); +        Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, FileSys::ArchiveFormatInfo(), archive_path);          // Open it again to get a valid archive now that the folder exists          archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path);          ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); | 
