HLE/FS: Implemented GetFormatInfo
Format information is currently only implemented for the ExtSaveData, SharedExtSaveData and SaveData archives, the information is stored in a file alongside the root folder of the archive.
This commit is contained in:
parent
9b2d643451
commit
d26c6b3212
|
@ -62,6 +62,14 @@ private:
|
||||||
std::u16string u16str;
|
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 {
|
class ArchiveBackend : NonCopyable {
|
||||||
public:
|
public:
|
||||||
virtual ~ArchiveBackend() {
|
virtual ~ArchiveBackend() {
|
||||||
|
@ -159,9 +167,17 @@ public:
|
||||||
/**
|
/**
|
||||||
* Deletes the archive contents and then re-creates the base folder
|
* Deletes the archive contents and then re-creates the base folder
|
||||||
* @param path Path to the archive
|
* @param path Path to the archive
|
||||||
|
* @param format_info Format information for the new archive
|
||||||
* @return ResultCode of the operation, 0 on success
|
* @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
|
} // namespace FileSys
|
||||||
|
|
|
@ -82,13 +82,45 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(cons
|
||||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
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
|
// These folders are always created with the ExtSaveData
|
||||||
std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/";
|
std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/";
|
||||||
std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/";
|
std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/";
|
||||||
FileUtil::CreateFullPath(user_path);
|
FileUtil::CreateFullPath(user_path);
|
||||||
FileUtil::CreateFullPath(boss_path);
|
FileUtil::CreateFullPath(boss_path);
|
||||||
|
|
||||||
|
// 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;
|
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
|
} // namespace FileSys
|
||||||
|
|
|
@ -31,10 +31,19 @@ public:
|
||||||
std::string GetName() const override { return "ExtSaveData"; }
|
std::string GetName() const override { return "ExtSaveData"; }
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
|
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; }
|
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:
|
private:
|
||||||
/**
|
/**
|
||||||
* This holds the full directory path for this archive, it is only set after a successful call
|
* This holds the full directory path for this archive, it is only set after a successful call
|
||||||
|
|
|
@ -29,11 +29,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path
|
||||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
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.");
|
LOG_ERROR(Service_FS, "Attempted to format a RomFS archive.");
|
||||||
// TODO: Verify error code
|
// TODO: Verify error code
|
||||||
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS,
|
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS,
|
||||||
ErrorSummary::NotSupported, ErrorLevel::Permanent);
|
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
|
} // namespace FileSys
|
||||||
|
|
|
@ -26,7 +26,8 @@ public:
|
||||||
|
|
||||||
std::string GetName() const override { return "RomFS"; }
|
std::string GetName() const override { return "RomFS"; }
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
|
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:
|
private:
|
||||||
std::shared_ptr<FileUtil::IOFile> romfs_file;
|
std::shared_ptr<FileUtil::IOFile> romfs_file;
|
||||||
|
|
|
@ -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);
|
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)
|
ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directory)
|
||||||
: mount_point(GetSaveDataContainerPath(sdmc_directory)) {
|
: mount_point(GetSaveDataContainerPath(sdmc_directory)) {
|
||||||
LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str());
|
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));
|
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);
|
std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
|
||||||
FileUtil::DeleteDirRecursively(concrete_mount_point);
|
FileUtil::DeleteDirRecursively(concrete_mount_point);
|
||||||
FileUtil::CreateFullPath(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;
|
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
|
} // namespace FileSys
|
||||||
|
|
|
@ -23,7 +23,9 @@ public:
|
||||||
std::string GetName() const override { return "SaveData"; }
|
std::string GetName() const override { return "SaveData"; }
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
|
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:
|
private:
|
||||||
std::string mount_point;
|
std::string mount_point;
|
||||||
|
|
|
@ -48,11 +48,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveDataCheck::Open(co
|
||||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
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.");
|
LOG_ERROR(Service_FS, "Attempted to format a SaveDataCheck archive.");
|
||||||
// TODO: Verify error code
|
// TODO: Verify error code
|
||||||
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS,
|
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS,
|
||||||
ErrorSummary::NotSupported, ErrorLevel::Permanent);
|
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
|
} // namespace FileSys
|
||||||
|
|
|
@ -23,7 +23,8 @@ public:
|
||||||
std::string GetName() const override { return "SaveDataCheck"; }
|
std::string GetName() const override { return "SaveDataCheck"; }
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
|
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:
|
private:
|
||||||
std::string mount_point;
|
std::string mount_point;
|
||||||
|
|
|
@ -40,9 +40,14 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path&
|
||||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
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. :)
|
// This is kind of an undesirable operation, so let's just ignore it. :)
|
||||||
return RESULT_SUCCESS;
|
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
|
} // namespace FileSys
|
||||||
|
|
|
@ -29,7 +29,8 @@ public:
|
||||||
std::string GetName() const override { return "SDMC"; }
|
std::string GetName() const override { return "SDMC"; }
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
|
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:
|
private:
|
||||||
std::string sdmc_directory;
|
std::string sdmc_directory;
|
||||||
|
|
|
@ -63,11 +63,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(c
|
||||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
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);
|
std::string fullpath = GetSystemSaveDataPath(base_path, path);
|
||||||
FileUtil::DeleteDirRecursively(fullpath);
|
FileUtil::DeleteDirRecursively(fullpath);
|
||||||
FileUtil::CreateFullPath(fullpath);
|
FileUtil::CreateFullPath(fullpath);
|
||||||
return RESULT_SUCCESS;
|
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
|
} // namespace FileSys
|
||||||
|
|
|
@ -23,7 +23,8 @@ public:
|
||||||
ArchiveFactory_SystemSaveData(const std::string& mount_point);
|
ArchiveFactory_SystemSaveData(const std::string& mount_point);
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
|
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"; }
|
std::string GetName() const override { return "SystemSaveData"; }
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ enum class ErrorDescription : u32 {
|
||||||
FS_InvalidOpenFlags = 230,
|
FS_InvalidOpenFlags = 230,
|
||||||
FS_NotAFile = 250,
|
FS_NotAFile = 250,
|
||||||
FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
|
FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
|
||||||
|
FS_InvalidPath = 702,
|
||||||
InvalidSection = 1000,
|
InvalidSection = 1000,
|
||||||
TooLarge = 1001,
|
TooLarge = 1001,
|
||||||
NotAuthorized = 1002,
|
NotAuthorized = 1002,
|
||||||
|
|
|
@ -407,7 +407,7 @@ void Init() {
|
||||||
// If the archive didn't exist, create the files inside
|
// If the archive didn't exist, create the files inside
|
||||||
if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
|
if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
|
||||||
// Format the archive to create the directories
|
// 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
|
// Open it again to get a valid archive now that the folder exists
|
||||||
archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path);
|
archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path);
|
||||||
|
|
|
@ -421,49 +421,45 @@ ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) {
|
||||||
return MakeResult<u64>(archive->GetFreeBytes());
|
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);
|
auto archive_itr = id_code_map.find(id_code);
|
||||||
if (archive_itr == id_code_map.end()) {
|
if (archive_itr == id_code_map.end()) {
|
||||||
return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
|
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
|
// Construct the binary path to the archive first
|
||||||
FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
|
FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
|
||||||
|
|
||||||
std::string media_type_directory;
|
auto archive = id_code_map.find(media_type == MediaType::NAND ? ArchiveIdCode::SharedExtSaveData : ArchiveIdCode::ExtSaveData);
|
||||||
if (media_type == MediaType::NAND) {
|
|
||||||
media_type_directory = FileUtil::GetUserPath(D_NAND_IDX);
|
if (archive == id_code_map.end()) {
|
||||||
} else if (media_type == MediaType::SDMC) {
|
return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND);
|
auto ext_savedata = static_cast<FileSys::ArchiveFactory_ExtSaveData*>(archive->second.get());
|
||||||
std::string game_path = FileSys::GetExtSaveDataPath(base_path, path);
|
|
||||||
// These two folders are always created with the ExtSaveData
|
ResultCode result = ext_savedata->Format(path, format_info);
|
||||||
std::string user_path = game_path + "user/";
|
if (result.IsError())
|
||||||
std::string boss_path = game_path + "boss/";
|
return result;
|
||||||
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
|
|
||||||
|
|
||||||
u8* smdh_icon = Memory::GetPointer(icon_buffer);
|
u8* smdh_icon = Memory::GetPointer(icon_buffer);
|
||||||
if (!smdh_icon)
|
if (!smdh_icon)
|
||||||
return ResultCode(-1); // TODO(Subv): Find the right error code
|
return ResultCode(-1); // TODO(Subv): Find the right error code
|
||||||
|
|
||||||
// Create the icon
|
ext_savedata->WriteIcon(path, smdh_icon, icon_size);
|
||||||
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);
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,10 +177,20 @@ ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle);
|
||||||
* Erases the contents of the physical folder that contains the archive
|
* Erases the contents of the physical folder that contains the archive
|
||||||
* identified by the specified id code and path
|
* identified by the specified id code and path
|
||||||
* @param id_code The id of the archive to format
|
* @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.
|
* @param path The path to the archive, if relevant.
|
||||||
* @return ResultCode 0 on success or the corresponding code on error
|
* @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
|
* 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 low The low word of the extdata id to create
|
||||||
* @param icon_buffer VAddr of the SMDH icon for this ExtSaveData
|
* @param icon_buffer VAddr of the SMDH icon for this ExtSaveData
|
||||||
* @param icon_size Size of the SMDH icon
|
* @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
|
* @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
|
* Deletes the SharedExtSaveData archive for the specified extdata ID
|
||||||
|
|
|
@ -443,17 +443,22 @@ static void IsSdmcWriteable(Service::Interface* self) {
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0 : 0x084C0242
|
* 0 : 0x084C0242
|
||||||
* 1 : Archive ID
|
* 1 : Archive ID
|
||||||
* 2 : Archive low path type
|
* 2 : Archive path type
|
||||||
* 3 : Archive low path size
|
* 3 : Archive path size
|
||||||
* 10 : (LowPathSize << 14) | 2
|
* 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
|
* 11 : Archive low path
|
||||||
* Outputs:
|
* Outputs:
|
||||||
* 1 : Result of function, 0 on success, otherwise error code
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
*/
|
*/
|
||||||
static void FormatSaveData(Service::Interface* self) {
|
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();
|
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 archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
|
||||||
auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
|
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());
|
LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str());
|
||||||
|
|
||||||
if (archive_id != FS::ArchiveIdCode::SaveData) {
|
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", archive_id);
|
||||||
LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", cmd_buff[1]);
|
cmd_buff[1] = ResultCode(ErrorDescription::FS_InvalidPath, ErrorModule::FS,
|
||||||
cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
|
ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,23 +482,40 @@ static void FormatSaveData(Service::Interface* self) {
|
||||||
return;
|
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
|
* FS_User::FormatThisUserSaveData service function
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 0: 0x080F0180
|
* 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:
|
* Outputs:
|
||||||
* 1 : Result of function, 0 on success, otherwise error code
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
*/
|
*/
|
||||||
static void FormatThisUserSaveData(Service::Interface* self) {
|
static void FormatThisUserSaveData(Service::Interface* self) {
|
||||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
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
|
* 2 : Low word of the saveid to create
|
||||||
* 3 : High word of the saveid to create
|
* 3 : High word of the saveid to create
|
||||||
* 4 : Unknown
|
* 4 : Unknown
|
||||||
* 5 : Unknown
|
* 5 : Number of directories
|
||||||
* 6 : Unknown
|
* 6 : Number of files
|
||||||
* 7 : Unknown
|
* 7-8 : Size limit
|
||||||
* 8 : Unknown
|
|
||||||
* 9 : Size of the SMDH icon
|
* 9 : Size of the SMDH icon
|
||||||
* 10: (SMDH Size << 4) | 0x0000000A
|
* 10: (SMDH Size << 4) | 0x0000000A
|
||||||
* 11: Pointer to the SMDH icon for the new ExtSaveData
|
* 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[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[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
|
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[] = {
|
const Interface::FunctionInfo FunctionTable[] = {
|
||||||
{0x000100C6, nullptr, "Dummy1"},
|
{0x000100C6, nullptr, "Dummy1"},
|
||||||
{0x040100C4, nullptr, "Control"},
|
{0x040100C4, nullptr, "Control"},
|
||||||
|
@ -802,7 +873,7 @@ const Interface::FunctionInfo FunctionTable[] = {
|
||||||
{0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
|
{0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
|
||||||
{0x08430000, nullptr, "InitializeCtrFileSystem"},
|
{0x08430000, nullptr, "InitializeCtrFileSystem"},
|
||||||
{0x08440000, nullptr, "CreateSeed"},
|
{0x08440000, nullptr, "CreateSeed"},
|
||||||
{0x084500C2, nullptr, "GetFormatInfo"},
|
{0x084500C2, GetFormatInfo, "GetFormatInfo"},
|
||||||
{0x08460102, nullptr, "GetLegacyRomHeader2"},
|
{0x08460102, nullptr, "GetLegacyRomHeader2"},
|
||||||
{0x08470180, nullptr, "FormatCtrCardUserSaveData"},
|
{0x08470180, nullptr, "FormatCtrCardUserSaveData"},
|
||||||
{0x08480042, nullptr, "GetSdmcCtrRootPath"},
|
{0x08480042, nullptr, "GetSdmcCtrRootPath"},
|
||||||
|
|
|
@ -103,7 +103,7 @@ void Init() {
|
||||||
// If the archive didn't exist, create the files inside
|
// If the archive didn't exist, create the files inside
|
||||||
if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
|
if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
|
||||||
// Format the archive to create the directories
|
// 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
|
// Open it again to get a valid archive now that the folder exists
|
||||||
archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path);
|
archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path);
|
||||||
ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!");
|
ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!");
|
||||||
|
|
Reference in New Issue