summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/file_sys/archive_backend.h18
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp36
-rw-r--r--src/core/file_sys/archive_extsavedata.h11
-rw-r--r--src/core/file_sys/archive_romfs.cpp8
-rw-r--r--src/core/file_sys/archive_romfs.h3
-rw-r--r--src/core/file_sys/archive_savedata.cpp32
-rw-r--r--src/core/file_sys/archive_savedata.h4
-rw-r--r--src/core/file_sys/archive_savedatacheck.cpp8
-rw-r--r--src/core/file_sys/archive_savedatacheck.h3
-rw-r--r--src/core/file_sys/archive_sdmc.cpp7
-rw-r--r--src/core/file_sys/archive_sdmc.h3
-rw-r--r--src/core/file_sys/archive_systemsavedata.cpp8
-rw-r--r--src/core/file_sys/archive_systemsavedata.h3
-rw-r--r--src/core/hle/result.h1
-rw-r--r--src/core/hle/service/cfg/cfg.cpp2
-rw-r--r--src/core/hle/service/fs/archive.cpp48
-rw-r--r--src/core/hle/service/fs/archive.h15
-rw-r--r--src/core/hle/service/fs/fs_user.cpp107
-rw-r--r--src/core/hle/service/ptm/ptm.cpp2
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:
62 std::u16string u16str; 62 std::u16string u16str;
63}; 63};
64 64
65struct ArchiveFormatInfo {
66 u32 total_size; ///< The pre-defined size of the archive, as specified in the Create or Format call
67 u32 number_directories; ///< The pre-defined number of directories in the archive, as specified in the Create or Format call
68 u32 number_files; ///< The pre-defined number of files in the archive, as specified in the Create or Format call
69 u8 duplicate_data; ///< Whether the archive should duplicate the data, as specified in the Create or Format call
70};
71static_assert(std::is_pod<ArchiveFormatInfo>::value, "ArchiveFormatInfo is not POD");
72
65class ArchiveBackend : NonCopyable { 73class ArchiveBackend : NonCopyable {
66public: 74public:
67 virtual ~ArchiveBackend() { 75 virtual ~ArchiveBackend() {
@@ -159,9 +167,17 @@ public:
159 /** 167 /**
160 * Deletes the archive contents and then re-creates the base folder 168 * Deletes the archive contents and then re-creates the base folder
161 * @param path Path to the archive 169 * @param path Path to the archive
170 * @param format_info Format information for the new archive
162 * @return ResultCode of the operation, 0 on success 171 * @return ResultCode of the operation, 0 on success
163 */ 172 */
164 virtual ResultCode Format(const Path& path) = 0; 173 virtual ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) = 0;
174
175 /*
176 * Retrieves the format info about the archive with the specified path
177 * @param path Path to the archive
178 * @return Format information about the archive or error code
179 */
180 virtual ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const = 0;
165}; 181};
166 182
167} // namespace FileSys 183} // 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
82 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 82 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
83} 83}
84 84
85ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path) { 85ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
86 // These folders are always created with the ExtSaveData 86 // These folders are always created with the ExtSaveData
87 std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/"; 87 std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/";
88 std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/"; 88 std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/";
89 FileUtil::CreateFullPath(user_path); 89 FileUtil::CreateFullPath(user_path);
90 FileUtil::CreateFullPath(boss_path); 90 FileUtil::CreateFullPath(boss_path);
91 return RESULT_SUCCESS; 91
92 // Write the format metadata
93 std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata";
94 FileUtil::IOFile file(metadata_path, "wb");
95
96 if (file.IsOpen()) {
97 file.WriteBytes(&format_info, sizeof(format_info));
98 return RESULT_SUCCESS;
99 }
100
101 // TODO(Subv): Find the correct error code
102 return ResultCode(-1);
103}
104
105ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Path& path) const {
106 std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata";
107 FileUtil::IOFile file(metadata_path, "rb");
108
109 if (file.IsOpen()) {
110 ArchiveFormatInfo info;
111 file.ReadBytes(&info, sizeof(info));
112 return MakeResult<ArchiveFormatInfo>(info);
113 }
114
115 LOG_ERROR(Service_FS, "Could not open metadata information for archive");
116 // TODO(Subv): Verify error code
117 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status);
118}
119
120void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, u8* icon_data, u32 icon_size) {
121 std::string game_path = FileSys::GetExtSaveDataPath(GetMountPoint(), path);
122 FileUtil::IOFile icon_file(game_path + "icon", "wb+");
123 icon_file.WriteBytes(icon_data, icon_size);
92} 124}
93 125
94} // namespace FileSys 126} // 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:
31 std::string GetName() const override { return "ExtSaveData"; } 31 std::string GetName() const override { return "ExtSaveData"; }
32 32
33 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 33 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
34 ResultCode Format(const Path& path) override; 34 ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
35 ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
35 36
36 const std::string& GetMountPoint() const { return mount_point; } 37 const std::string& GetMountPoint() const { return mount_point; }
37 38
39 /*
40 * Writes the SMDH icon of the ExtSaveData to file
41 * @param path Path of this ExtSaveData
42 * @param icon_data Binary data of the icon
43 * @param icon_size Size of the icon data
44 */
45 void WriteIcon(const Path& path, u8* icon_data, u32 icon_size);
46
38private: 47private:
39 /** 48 /**
40 * This holds the full directory path for this archive, it is only set after a successful call 49 * 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
29 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 29 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
30} 30}
31 31
32ResultCode ArchiveFactory_RomFS::Format(const Path& path) { 32ResultCode ArchiveFactory_RomFS::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
33 LOG_ERROR(Service_FS, "Attempted to format a RomFS archive."); 33 LOG_ERROR(Service_FS, "Attempted to format a RomFS archive.");
34 // TODO: Verify error code 34 // TODO: Verify error code
35 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, 35 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS,
36 ErrorSummary::NotSupported, ErrorLevel::Permanent); 36 ErrorSummary::NotSupported, ErrorLevel::Permanent);
37} 37}
38 38
39ResultVal<ArchiveFormatInfo> ArchiveFactory_RomFS::GetFormatInfo(const Path& path) const {
40 // TODO(Subv): Implement
41 LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str());
42 return ResultCode(-1);
43}
44
39} // namespace FileSys 45} // 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:
26 26
27 std::string GetName() const override { return "RomFS"; } 27 std::string GetName() const override { return "RomFS"; }
28 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 28 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
29 ResultCode Format(const Path& path) override; 29 ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
30 ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
30 31
31private: 32private:
32 std::shared_ptr<FileUtil::IOFile> romfs_file; 33 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
31 return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high, low); 31 return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high, low);
32} 32}
33 33
34static std::string GetSaveDataMetadataPath(const std::string& mount_location, u64 program_id) {
35 u32 high = program_id >> 32;
36 u32 low = program_id & 0xFFFFFFFF;
37 return Common::StringFromFormat("%s%08x/%08x/data/00000001.metadata", mount_location.c_str(), high, low);
38}
39
34ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directory) 40ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directory)
35 : mount_point(GetSaveDataContainerPath(sdmc_directory)) { 41 : mount_point(GetSaveDataContainerPath(sdmc_directory)) {
36 LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str()); 42 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
51 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 57 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
52} 58}
53 59
54ResultCode ArchiveFactory_SaveData::Format(const Path& path) { 60ResultCode ArchiveFactory_SaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
55 std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id); 61 std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
56 FileUtil::DeleteDirRecursively(concrete_mount_point); 62 FileUtil::DeleteDirRecursively(concrete_mount_point);
57 FileUtil::CreateFullPath(concrete_mount_point); 63 FileUtil::CreateFullPath(concrete_mount_point);
64
65 // Write the format metadata
66 std::string metadata_path = GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id);
67 FileUtil::IOFile file(metadata_path, "wb");
68
69 if (file.IsOpen()) {
70 file.WriteBytes(&format_info, sizeof(format_info));
71 return RESULT_SUCCESS;
72 }
58 return RESULT_SUCCESS; 73 return RESULT_SUCCESS;
59} 74}
60 75
76ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveData::GetFormatInfo(const Path& path) const {
77 std::string metadata_path = GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id);
78 FileUtil::IOFile file(metadata_path, "rb");
79
80 if (file.IsOpen()) {
81 ArchiveFormatInfo info;
82 file.ReadBytes(&info, sizeof(info));
83 return MakeResult<ArchiveFormatInfo>(info);
84 }
85
86 LOG_ERROR(Service_FS, "Could not open metadata information for archive");
87 // TODO(Subv): Verify error code
88 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status);
89}
90
61} // namespace FileSys 91} // 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:
23 std::string GetName() const override { return "SaveData"; } 23 std::string GetName() const override { return "SaveData"; }
24 24
25 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 25 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
26 ResultCode Format(const Path& path) override; 26 ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
27
28 ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
27 29
28private: 30private:
29 std::string mount_point; 31 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
48 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 48 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
49} 49}
50 50
51ResultCode ArchiveFactory_SaveDataCheck::Format(const Path& path) { 51ResultCode ArchiveFactory_SaveDataCheck::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
52 LOG_ERROR(Service_FS, "Attempted to format a SaveDataCheck archive."); 52 LOG_ERROR(Service_FS, "Attempted to format a SaveDataCheck archive.");
53 // TODO: Verify error code 53 // TODO: Verify error code
54 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, 54 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS,
55 ErrorSummary::NotSupported, ErrorLevel::Permanent); 55 ErrorSummary::NotSupported, ErrorLevel::Permanent);
56} 56}
57 57
58ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveDataCheck::GetFormatInfo(const Path& path) const {
59 // TODO(Subv): Implement
60 LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str());
61 return ResultCode(-1);
62}
63
58} // namespace FileSys 64} // 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:
23 std::string GetName() const override { return "SaveDataCheck"; } 23 std::string GetName() const override { return "SaveDataCheck"; }
24 24
25 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 25 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
26 ResultCode Format(const Path& path) override; 26 ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
27 ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
27 28
28private: 29private:
29 std::string mount_point; 30 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&
40 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 40 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
41} 41}
42 42
43ResultCode ArchiveFactory_SDMC::Format(const Path& path) { 43ResultCode ArchiveFactory_SDMC::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
44 // This is kind of an undesirable operation, so let's just ignore it. :) 44 // This is kind of an undesirable operation, so let's just ignore it. :)
45 return RESULT_SUCCESS; 45 return RESULT_SUCCESS;
46} 46}
47 47
48ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMC::GetFormatInfo(const Path& path) const {
49 // TODO(Subv): Implement
50 LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str());
51 return ResultCode(-1);
52}
48} // namespace FileSys 53} // 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:
29 std::string GetName() const override { return "SDMC"; } 29 std::string GetName() const override { return "SDMC"; }
30 30
31 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 31 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
32 ResultCode Format(const Path& path) override; 32 ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
33 ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
33 34
34private: 35private:
35 std::string sdmc_directory; 36 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
63 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 63 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
64} 64}
65 65
66ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path) { 66ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
67 std::string fullpath = GetSystemSaveDataPath(base_path, path); 67 std::string fullpath = GetSystemSaveDataPath(base_path, path);
68 FileUtil::DeleteDirRecursively(fullpath); 68 FileUtil::DeleteDirRecursively(fullpath);
69 FileUtil::CreateFullPath(fullpath); 69 FileUtil::CreateFullPath(fullpath);
70 return RESULT_SUCCESS; 70 return RESULT_SUCCESS;
71} 71}
72 72
73ResultVal<ArchiveFormatInfo> ArchiveFactory_SystemSaveData::GetFormatInfo(const Path& path) const {
74 // TODO(Subv): Implement
75 LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str());
76 return ResultCode(-1);
77}
78
73} // namespace FileSys 79} // 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:
23 ArchiveFactory_SystemSaveData(const std::string& mount_point); 23 ArchiveFactory_SystemSaveData(const std::string& mount_point);
24 24
25 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 25 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
26 ResultCode Format(const Path& path) override; 26 ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
27 ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
27 28
28 std::string GetName() const override { return "SystemSaveData"; } 29 std::string GetName() const override { return "SystemSaveData"; }
29 30
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 {
24 FS_InvalidOpenFlags = 230, 24 FS_InvalidOpenFlags = 230,
25 FS_NotAFile = 250, 25 FS_NotAFile = 250,
26 FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive 26 FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
27 FS_InvalidPath = 702,
27 InvalidSection = 1000, 28 InvalidSection = 1000,
28 TooLarge = 1001, 29 TooLarge = 1001,
29 NotAuthorized = 1002, 30 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() {
407 // If the archive didn't exist, create the files inside 407 // If the archive didn't exist, create the files inside
408 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { 408 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
409 // Format the archive to create the directories 409 // Format the archive to create the directories
410 Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); 410 Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, FileSys::ArchiveFormatInfo(), archive_path);
411 411
412 // Open it again to get a valid archive now that the folder exists 412 // Open it again to get a valid archive now that the folder exists
413 archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); 413 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) {
421 return MakeResult<u64>(archive->GetFreeBytes()); 421 return MakeResult<u64>(archive->GetFreeBytes());
422} 422}
423 423
424ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { 424ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, const FileSys::Path& path) {
425 auto archive_itr = id_code_map.find(id_code); 425 auto archive_itr = id_code_map.find(id_code);
426 if (archive_itr == id_code_map.end()) { 426 if (archive_itr == id_code_map.end()) {
427 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error 427 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
428 } 428 }
429 429
430 return archive_itr->second->Format(path); 430 return archive_itr->second->Format(path, format_info);
431} 431}
432 432
433ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size) { 433ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code, FileSys::Path& archive_path) {
434 auto archive = id_code_map.find(id_code);
435 if (archive == id_code_map.end()) {
436 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
437 }
438
439 return archive->second->GetFormatInfo(archive_path);
440}
441
442ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size, const FileSys::ArchiveFormatInfo& format_info) {
434 // Construct the binary path to the archive first 443 // Construct the binary path to the archive first
435 FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); 444 FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
436 445
437 std::string media_type_directory; 446 auto archive = id_code_map.find(media_type == MediaType::NAND ? ArchiveIdCode::SharedExtSaveData : ArchiveIdCode::ExtSaveData);
438 if (media_type == MediaType::NAND) { 447
439 media_type_directory = FileUtil::GetUserPath(D_NAND_IDX); 448 if (archive == id_code_map.end()) {
440 } else if (media_type == MediaType::SDMC) { 449 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
441 media_type_directory = FileUtil::GetUserPath(D_SDMC_IDX);
442 } else {
443 LOG_ERROR(Service_FS, "Unsupported media type %u", media_type);
444 return ResultCode(-1); // TODO(Subv): Find the right error code
445 } 450 }
446 451
447 std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); 452 auto ext_savedata = static_cast<FileSys::ArchiveFactory_ExtSaveData*>(archive->second.get());
448 std::string game_path = FileSys::GetExtSaveDataPath(base_path, path); 453
449 // These two folders are always created with the ExtSaveData 454 ResultCode result = ext_savedata->Format(path, format_info);
450 std::string user_path = game_path + "user/"; 455 if (result.IsError())
451 std::string boss_path = game_path + "boss/"; 456 return result;
452 if (!FileUtil::CreateFullPath(user_path))
453 return ResultCode(-1); // TODO(Subv): Find the right error code
454 if (!FileUtil::CreateFullPath(boss_path))
455 return ResultCode(-1); // TODO(Subv): Find the right error code
456 457
457 u8* smdh_icon = Memory::GetPointer(icon_buffer); 458 u8* smdh_icon = Memory::GetPointer(icon_buffer);
458 if (!smdh_icon) 459 if (!smdh_icon)
459 return ResultCode(-1); // TODO(Subv): Find the right error code 460 return ResultCode(-1); // TODO(Subv): Find the right error code
460 461
461 // Create the icon 462 ext_savedata->WriteIcon(path, smdh_icon, icon_size);
462 FileUtil::IOFile icon_file(game_path + "icon", "wb+");
463 if (!icon_file.IsGood())
464 return ResultCode(-1); // TODO(Subv): Find the right error code
465
466 icon_file.WriteBytes(smdh_icon, icon_size);
467 return RESULT_SUCCESS; 463 return RESULT_SUCCESS;
468} 464}
469 465
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);
177 * Erases the contents of the physical folder that contains the archive 177 * Erases the contents of the physical folder that contains the archive
178 * identified by the specified id code and path 178 * identified by the specified id code and path
179 * @param id_code The id of the archive to format 179 * @param id_code The id of the archive to format
180 * @param format_info Format information about the new archive
180 * @param path The path to the archive, if relevant. 181 * @param path The path to the archive, if relevant.
181 * @return ResultCode 0 on success or the corresponding code on error 182 * @return ResultCode 0 on success or the corresponding code on error
182 */ 183 */
183ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = FileSys::Path()); 184ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, const FileSys::Path& path = FileSys::Path());
185
186/*
187 * Retrieves the format info about the archive of the specified type and path.
188 * The format info is supplied by the client code when creating archives.
189 * @param id_code The id of the archive
190 * @param archive_path The path of the archive, if relevant
191 * @return The format info of the archive, or the corresponding error code if failed.
192 */
193ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code, FileSys::Path& archive_path);
184 194
185/** 195/**
186 * Creates a blank SharedExtSaveData archive for the specified extdata ID 196 * Creates a blank SharedExtSaveData archive for the specified extdata ID
@@ -189,9 +199,10 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = File
189 * @param low The low word of the extdata id to create 199 * @param low The low word of the extdata id to create
190 * @param icon_buffer VAddr of the SMDH icon for this ExtSaveData 200 * @param icon_buffer VAddr of the SMDH icon for this ExtSaveData
191 * @param icon_size Size of the SMDH icon 201 * @param icon_size Size of the SMDH icon
202 * @param format_info Format information about the new archive
192 * @return ResultCode 0 on success or the corresponding code on error 203 * @return ResultCode 0 on success or the corresponding code on error
193 */ 204 */
194ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size); 205ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size, const FileSys::ArchiveFormatInfo& format_info);
195 206
196/** 207/**
197 * Deletes the SharedExtSaveData archive for the specified extdata ID 208 * 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) {
443 * Inputs: 443 * Inputs:
444 * 0 : 0x084C0242 444 * 0 : 0x084C0242
445 * 1 : Archive ID 445 * 1 : Archive ID
446 * 2 : Archive low path type 446 * 2 : Archive path type
447 * 3 : Archive low path size 447 * 3 : Archive path size
448 * 10 : (LowPathSize << 14) | 2 448 * 4 : Size in Blocks (1 block = 512 bytes)
449 * 5 : Number of directories
450 * 6 : Number of files
451 * 7 : Directory bucket count
452 * 8 : File bucket count
453 * 9 : Duplicate data
454 * 10 : (PathSize << 14) | 2
449 * 11 : Archive low path 455 * 11 : Archive low path
450 * Outputs: 456 * Outputs:
451 * 1 : Result of function, 0 on success, otherwise error code 457 * 1 : Result of function, 0 on success, otherwise error code
452 */ 458 */
453static void FormatSaveData(Service::Interface* self) { 459static void FormatSaveData(Service::Interface* self) {
454 // TODO(Subv): Find out what the other inputs and outputs of this function are
455 u32* cmd_buff = Kernel::GetCommandBuffer(); 460 u32* cmd_buff = Kernel::GetCommandBuffer();
456 LOG_DEBUG(Service_FS, "(STUBBED)"); 461 LOG_WARNING(Service_FS, "(STUBBED)");
457 462
458 auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]); 463 auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
459 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); 464 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
@@ -464,9 +469,9 @@ static void FormatSaveData(Service::Interface* self) {
464 LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str()); 469 LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str());
465 470
466 if (archive_id != FS::ArchiveIdCode::SaveData) { 471 if (archive_id != FS::ArchiveIdCode::SaveData) {
467 // TODO(Subv): What should happen if somebody attempts to format a different archive? 472 LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", archive_id);
468 LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", cmd_buff[1]); 473 cmd_buff[1] = ResultCode(ErrorDescription::FS_InvalidPath, ErrorModule::FS,
469 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; 474 ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw;
470 return; 475 return;
471 } 476 }
472 477
@@ -477,23 +482,40 @@ static void FormatSaveData(Service::Interface* self) {
477 return; 482 return;
478 } 483 }
479 484
480 cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw; 485 FileSys::ArchiveFormatInfo format_info;
486 format_info.duplicate_data = cmd_buff[9] & 0xFF;
487 format_info.number_directories = cmd_buff[5];
488 format_info.number_files = cmd_buff[6];
489 format_info.total_size = cmd_buff[4] * 512;
490
491 cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData, format_info).raw;
481} 492}
482 493
483/** 494/**
484 * FS_User::FormatThisUserSaveData service function 495 * FS_User::FormatThisUserSaveData service function
485 * Inputs: 496 * Inputs:
486 * 0: 0x080F0180 497 * 0: 0x080F0180
498 * 1 : Size in Blocks (1 block = 512 bytes)
499 * 2 : Number of directories
500 * 3 : Number of files
501 * 4 : Directory bucket count
502 * 5 : File bucket count
503 * 6 : Duplicate data
487 * Outputs: 504 * Outputs:
488 * 1 : Result of function, 0 on success, otherwise error code 505 * 1 : Result of function, 0 on success, otherwise error code
489 */ 506 */
490static void FormatThisUserSaveData(Service::Interface* self) { 507static void FormatThisUserSaveData(Service::Interface* self) {
491 u32* cmd_buff = Kernel::GetCommandBuffer(); 508 u32* cmd_buff = Kernel::GetCommandBuffer();
492 LOG_DEBUG(Service_FS, "(STUBBED)");
493 509
494 // TODO(Subv): Find out what the inputs and outputs of this function are 510 FileSys::ArchiveFormatInfo format_info;
511 format_info.duplicate_data = cmd_buff[6] & 0xFF;
512 format_info.number_directories = cmd_buff[2];
513 format_info.number_files = cmd_buff[3];
514 format_info.total_size = cmd_buff[1] * 512;
495 515
496 cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw; 516 cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData, format_info).raw;
517
518 LOG_TRACE(Service_FS, "called");
497} 519}
498 520
499/** 521/**
@@ -531,10 +553,9 @@ static void GetFreeBytes(Service::Interface* self) {
531 * 2 : Low word of the saveid to create 553 * 2 : Low word of the saveid to create
532 * 3 : High word of the saveid to create 554 * 3 : High word of the saveid to create
533 * 4 : Unknown 555 * 4 : Unknown
534 * 5 : Unknown 556 * 5 : Number of directories
535 * 6 : Unknown 557 * 6 : Number of files
536 * 7 : Unknown 558 * 7-8 : Size limit
537 * 8 : Unknown
538 * 9 : Size of the SMDH icon 559 * 9 : Size of the SMDH icon
539 * 10: (SMDH Size << 4) | 0x0000000A 560 * 10: (SMDH Size << 4) | 0x0000000A
540 * 11: Pointer to the SMDH icon for the new ExtSaveData 561 * 11: Pointer to the SMDH icon for the new ExtSaveData
@@ -556,7 +577,12 @@ static void CreateExtSaveData(Service::Interface* self) {
556 cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], icon_size, 577 cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], icon_size,
557 cmd_buff[10], icon_buffer); 578 cmd_buff[10], icon_buffer);
558 579
559 cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size).raw; 580 FileSys::ArchiveFormatInfo format_info;
581 format_info.number_directories = cmd_buff[5];
582 format_info.number_files = cmd_buff[6];
583 format_info.duplicate_data = false;
584 format_info.total_size = 0;
585 cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size, format_info).raw;
560} 586}
561 587
562/** 588/**
@@ -731,6 +757,51 @@ static void GetArchiveResource(Service::Interface* self) {
731 cmd_buff[5] = 0x80000; // 8GiB free 757 cmd_buff[5] = 0x80000; // 8GiB free
732} 758}
733 759
760/**
761 * FS_User::GetFormatInfo service function.
762 * Inputs:
763 * 0 : 0x084500C2
764 * 1 : Archive ID
765 * 2 : Archive path type
766 * 3 : Archive path size
767 * 4 : (PathSize << 14) | 2
768 * 5 : Archive low path
769 * Outputs:
770 * 0 : 0x08450140
771 * 1 : Result of function, 0 on success, otherwise error code
772 * 2 : Total size
773 * 3 : Number of directories
774 * 4 : Number of files
775 * 5 : Duplicate data
776 */
777static void GetFormatInfo(Service::Interface* self) {
778 u32* cmd_buff = Kernel::GetCommandBuffer();
779
780 auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
781 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
782 u32 archivename_size = cmd_buff[3];
783 u32 archivename_ptr = cmd_buff[5];
784 FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
785
786 LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str());
787
788 cmd_buff[0] = IPC::MakeHeader(0x0845, 5, 0);
789
790 auto format_info = GetArchiveFormatInfo(archive_id, archive_path);
791
792 if (format_info.Failed()) {
793 LOG_ERROR(Service_FS, "Failed to retrieve the format info");
794 cmd_buff[1] = format_info.Code().raw;
795 return;
796 }
797
798 cmd_buff[1] = RESULT_SUCCESS.raw;
799 cmd_buff[2] = format_info->total_size;
800 cmd_buff[3] = format_info->number_directories;
801 cmd_buff[4] = format_info->number_files;
802 cmd_buff[5] = format_info->duplicate_data;
803}
804
734const Interface::FunctionInfo FunctionTable[] = { 805const Interface::FunctionInfo FunctionTable[] = {
735 {0x000100C6, nullptr, "Dummy1"}, 806 {0x000100C6, nullptr, "Dummy1"},
736 {0x040100C4, nullptr, "Control"}, 807 {0x040100C4, nullptr, "Control"},
@@ -802,7 +873,7 @@ const Interface::FunctionInfo FunctionTable[] = {
802 {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"}, 873 {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
803 {0x08430000, nullptr, "InitializeCtrFileSystem"}, 874 {0x08430000, nullptr, "InitializeCtrFileSystem"},
804 {0x08440000, nullptr, "CreateSeed"}, 875 {0x08440000, nullptr, "CreateSeed"},
805 {0x084500C2, nullptr, "GetFormatInfo"}, 876 {0x084500C2, GetFormatInfo, "GetFormatInfo"},
806 {0x08460102, nullptr, "GetLegacyRomHeader2"}, 877 {0x08460102, nullptr, "GetLegacyRomHeader2"},
807 {0x08470180, nullptr, "FormatCtrCardUserSaveData"}, 878 {0x08470180, nullptr, "FormatCtrCardUserSaveData"},
808 {0x08480042, nullptr, "GetSdmcCtrRootPath"}, 879 {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() {
103 // If the archive didn't exist, create the files inside 103 // If the archive didn't exist, create the files inside
104 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { 104 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
105 // Format the archive to create the directories 105 // Format the archive to create the directories
106 Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); 106 Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, FileSys::ArchiveFormatInfo(), archive_path);
107 // Open it again to get a valid archive now that the folder exists 107 // Open it again to get a valid archive now that the folder exists
108 archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); 108 archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path);
109 ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); 109 ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!");