summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2016-03-20 16:11:49 -0400
committerGravatar bunnei2016-03-20 16:11:49 -0400
commitb83e95727f95fa6fe35d436be3e821605244a6a8 (patch)
tree64255c7432e882205a2dbea1fe962025863664ee /src
parentMerge pull request #1550 from LittleWhite-tb/gdbstub_include_fix (diff)
parentHLE/FS: Change the error code returned when an ExtSaveData archive is not found. (diff)
downloadyuzu-b83e95727f95fa6fe35d436be3e821605244a6a8.tar.gz
yuzu-b83e95727f95fa6fe35d436be3e821605244a6a8.tar.xz
yuzu-b83e95727f95fa6fe35d436be3e821605244a6a8.zip
Merge pull request #1302 from Subv/save_fix
HLE/FS: Fixed many corner cases in our file handling
Diffstat (limited to 'src')
-rw-r--r--src/core/file_sys/archive_backend.h29
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp48
-rw-r--r--src/core/file_sys/archive_extsavedata.h12
-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.cpp36
-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/file_sys/disk_archive.cpp80
-rw-r--r--src/core/file_sys/disk_archive.h12
-rw-r--r--src/core/file_sys/file_backend.h13
-rw-r--r--src/core/file_sys/ivfc_archive.cpp21
-rw-r--r--src/core/file_sys/ivfc_archive.h12
-rw-r--r--src/core/hle/result.h6
-rw-r--r--src/core/hle/service/cfg/cfg.cpp5
-rw-r--r--src/core/hle/service/fs/archive.cpp90
-rw-r--r--src/core/hle/service/fs/archive.h17
-rw-r--r--src/core/hle/service/fs/fs_user.cpp113
-rw-r--r--src/core/hle/service/ptm/ptm.cpp2
24 files changed, 400 insertions, 143 deletions
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h
index 601e95d8c..5d91e47f3 100644
--- a/src/core/file_sys/archive_backend.h
+++ b/src/core/file_sys/archive_backend.h
@@ -11,6 +11,7 @@
11 11
12#include "common/bit_field.h" 12#include "common/bit_field.h"
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/swap.h"
14 15
15#include "core/hle/result.h" 16#include "core/hle/result.h"
16 17
@@ -62,6 +63,14 @@ private:
62 std::u16string u16str; 63 std::u16string u16str;
63}; 64};
64 65
66struct ArchiveFormatInfo {
67 u32_le total_size; ///< The pre-defined size of the archive, as specified in the Create or Format call
68 u32_le number_directories; ///< The pre-defined number of directories in the archive, as specified in the Create or Format call
69 u32_le number_files; ///< The pre-defined number of files in the archive, as specified in the Create or Format call
70 u8 duplicate_data; ///< Whether the archive should duplicate the data, as specified in the Create or Format call
71};
72static_assert(std::is_pod<ArchiveFormatInfo>::value, "ArchiveFormatInfo is not POD");
73
65class ArchiveBackend : NonCopyable { 74class ArchiveBackend : NonCopyable {
66public: 75public:
67 virtual ~ArchiveBackend() { 76 virtual ~ArchiveBackend() {
@@ -76,16 +85,16 @@ public:
76 * Open a file specified by its path, using the specified mode 85 * Open a file specified by its path, using the specified mode
77 * @param path Path relative to the archive 86 * @param path Path relative to the archive
78 * @param mode Mode to open the file with 87 * @param mode Mode to open the file with
79 * @return Opened file, or nullptr 88 * @return Opened file, or error code
80 */ 89 */
81 virtual std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const = 0; 90 virtual ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, const Mode mode) const = 0;
82 91
83 /** 92 /**
84 * Delete a file specified by its path 93 * Delete a file specified by its path
85 * @param path Path relative to the archive 94 * @param path Path relative to the archive
86 * @return Whether the file could be deleted 95 * @return Result of the operation
87 */ 96 */
88 virtual bool DeleteFile(const Path& path) const = 0; 97 virtual ResultCode DeleteFile(const Path& path) const = 0;
89 98
90 /** 99 /**
91 * Rename a File specified by its path 100 * Rename a File specified by its path
@@ -108,7 +117,7 @@ public:
108 * @param size The size of the new file, filled with zeroes 117 * @param size The size of the new file, filled with zeroes
109 * @return File creation result code 118 * @return File creation result code
110 */ 119 */
111 virtual ResultCode CreateFile(const Path& path, u32 size) const = 0; 120 virtual ResultCode CreateFile(const Path& path, u64 size) const = 0;
112 121
113 /** 122 /**
114 * Create a directory specified by its path 123 * Create a directory specified by its path
@@ -159,9 +168,17 @@ public:
159 /** 168 /**
160 * Deletes the archive contents and then re-creates the base folder 169 * Deletes the archive contents and then re-creates the base folder
161 * @param path Path to the archive 170 * @param path Path to the archive
171 * @param format_info Format information for the new archive
162 * @return ResultCode of the operation, 0 on success 172 * @return ResultCode of the operation, 0 on success
163 */ 173 */
164 virtual ResultCode Format(const Path& path) = 0; 174 virtual ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) = 0;
175
176 /**
177 * Retrieves the format info about the archive with the specified path
178 * @param path Path to the archive
179 * @return Format information about the archive or error code
180 */
181 virtual ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const = 0;
165}; 182};
166 183
167} // namespace FileSys 184} // namespace FileSys
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index 92dad8e6f..961264fe5 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -58,7 +58,7 @@ Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) {
58} 58}
59 59
60ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location, bool shared) 60ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location, bool shared)
61 : mount_point(GetExtDataContainerPath(mount_location, shared)) { 61 : shared(shared), mount_point(GetExtDataContainerPath(mount_location, shared)) {
62 LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str()); 62 LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str());
63} 63}
64 64
@@ -74,21 +74,59 @@ bool ArchiveFactory_ExtSaveData::Initialize() {
74ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(const Path& path) { 74ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(const Path& path) {
75 std::string fullpath = GetExtSaveDataPath(mount_point, path) + "user/"; 75 std::string fullpath = GetExtSaveDataPath(mount_point, path) + "user/";
76 if (!FileUtil::Exists(fullpath)) { 76 if (!FileUtil::Exists(fullpath)) {
77 // TODO(Subv): Check error code, this one is probably wrong 77 // TODO(Subv): Verify the archive behavior of SharedExtSaveData compared to ExtSaveData.
78 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, 78 // ExtSaveData seems to return FS_NotFound (120) when the archive doesn't exist.
79 ErrorSummary::InvalidState, ErrorLevel::Status); 79 if (!shared) {
80 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS,
81 ErrorSummary::InvalidState, ErrorLevel::Status);
82 } else {
83 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
84 ErrorSummary::InvalidState, ErrorLevel::Status);
85 }
80 } 86 }
81 auto archive = Common::make_unique<DiskArchive>(fullpath); 87 auto archive = Common::make_unique<DiskArchive>(fullpath);
82 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 88 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
83} 89}
84 90
85ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path) { 91ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
86 // These folders are always created with the ExtSaveData 92 // These folders are always created with the ExtSaveData
87 std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/"; 93 std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/";
88 std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/"; 94 std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/";
89 FileUtil::CreateFullPath(user_path); 95 FileUtil::CreateFullPath(user_path);
90 FileUtil::CreateFullPath(boss_path); 96 FileUtil::CreateFullPath(boss_path);
97
98 // Write the format metadata
99 std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata";
100 FileUtil::IOFile file(metadata_path, "wb");
101
102 if (!file.IsOpen()) {
103 // TODO(Subv): Find the correct error code
104 return ResultCode(-1);
105 }
106
107 file.WriteBytes(&format_info, sizeof(format_info));
91 return RESULT_SUCCESS; 108 return RESULT_SUCCESS;
92} 109}
93 110
111ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Path& path) const {
112 std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata";
113 FileUtil::IOFile file(metadata_path, "rb");
114
115 if (!file.IsOpen()) {
116 LOG_ERROR(Service_FS, "Could not open metadata information for archive");
117 // TODO(Subv): Verify error code
118 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status);
119 }
120
121 ArchiveFormatInfo info = {};
122 file.ReadBytes(&info, sizeof(info));
123 return MakeResult<ArchiveFormatInfo>(info);
124}
125
126void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, const u8* icon_data, size_t icon_size) {
127 std::string game_path = FileSys::GetExtSaveDataPath(GetMountPoint(), path);
128 FileUtil::IOFile icon_file(game_path + "icon", "wb");
129 icon_file.WriteBytes(icon_data, icon_size);
130}
131
94} // namespace FileSys 132} // namespace FileSys
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index ec8d770fc..287a6fee1 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, const u8* icon_data, size_t 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
@@ -42,6 +51,7 @@ private:
42 * See GetExtSaveDataPath for the code that extracts this data from an archive path. 51 * See GetExtSaveDataPath for the code that extracts this data from an archive path.
43 */ 52 */
44 std::string mount_point; 53 std::string mount_point;
54 bool shared; ///< Whether this archive represents an ExtSaveData archive or a SharedExtSaveData archive
45}; 55};
46 56
47/** 57/**
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..fe020d21c 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -26,11 +26,17 @@ static std::string GetSaveDataContainerPath(const std::string& sdmc_directory) {
26} 26}
27 27
28static std::string GetSaveDataPath(const std::string& mount_location, u64 program_id) { 28static std::string GetSaveDataPath(const std::string& mount_location, u64 program_id) {
29 u32 high = program_id >> 32; 29 u32 high = (u32)(program_id >> 32);
30 u32 low = program_id & 0xFFFFFFFF; 30 u32 low = (u32)(program_id & 0xFFFFFFFF);
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 = (u32)(program_id >> 32);
36 u32 low = (u32)(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 LOG_ERROR(Service_FS, "Could not open metadata information for archive");
82 // TODO(Subv): Verify error code
83 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status);
84 }
85
86 ArchiveFormatInfo info = {};
87 file.ReadBytes(&info, sizeof(info));
88 return MakeResult<ArchiveFormatInfo>(info);
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/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp
index a51416774..8e4ea01c5 100644
--- a/src/core/file_sys/disk_archive.cpp
+++ b/src/core/file_sys/disk_archive.cpp
@@ -17,16 +17,28 @@
17 17
18namespace FileSys { 18namespace FileSys {
19 19
20std::unique_ptr<FileBackend> DiskArchive::OpenFile(const Path& path, const Mode mode) const { 20ResultVal<std::unique_ptr<FileBackend>> DiskArchive::OpenFile(const Path& path, const Mode mode) const {
21 LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex); 21 LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex);
22 auto file = Common::make_unique<DiskFile>(*this, path, mode); 22 auto file = Common::make_unique<DiskFile>(*this, path, mode);
23 if (!file->Open()) 23 ResultCode result = file->Open();
24 return nullptr; 24 if (result.IsError())
25 return std::move(file); 25 return result;
26 return MakeResult<std::unique_ptr<FileBackend>>(std::move(file));
26} 27}
27 28
28bool DiskArchive::DeleteFile(const Path& path) const { 29ResultCode DiskArchive::DeleteFile(const Path& path) const {
29 return FileUtil::Delete(mount_point + path.AsString()); 30 std::string file_path = mount_point + path.AsString();
31
32 if (FileUtil::IsDirectory(file_path))
33 return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
34
35 if (!FileUtil::Exists(file_path))
36 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Status);
37
38 if (FileUtil::Delete(file_path))
39 return RESULT_SUCCESS;
40
41 return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
30} 42}
31 43
32bool DiskArchive::RenameFile(const Path& src_path, const Path& dest_path) const { 44bool DiskArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
@@ -37,11 +49,14 @@ bool DiskArchive::DeleteDirectory(const Path& path) const {
37 return FileUtil::DeleteDir(mount_point + path.AsString()); 49 return FileUtil::DeleteDir(mount_point + path.AsString());
38} 50}
39 51
40ResultCode DiskArchive::CreateFile(const FileSys::Path& path, u32 size) const { 52ResultCode DiskArchive::CreateFile(const FileSys::Path& path, u64 size) const {
41 std::string full_path = mount_point + path.AsString(); 53 std::string full_path = mount_point + path.AsString();
42 54
55 if (FileUtil::IsDirectory(full_path))
56 return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
57
43 if (FileUtil::Exists(full_path)) 58 if (FileUtil::Exists(full_path))
44 return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::FS, ErrorSummary::NothingHappened, ErrorLevel::Info); 59 return ResultCode(ErrorDescription::FS_AlreadyExists, ErrorModule::FS, ErrorSummary::NothingHappened, ErrorLevel::Status);
45 60
46 if (size == 0) { 61 if (size == 0) {
47 FileUtil::CreateEmptyFile(full_path); 62 FileUtil::CreateEmptyFile(full_path);
@@ -89,38 +104,57 @@ DiskFile::DiskFile(const DiskArchive& archive, const Path& path, const Mode mode
89 this->mode.hex = mode.hex; 104 this->mode.hex = mode.hex;
90} 105}
91 106
92bool DiskFile::Open() { 107ResultCode DiskFile::Open() {
93 if (!mode.create_flag && !FileUtil::Exists(path)) { 108 if (FileUtil::IsDirectory(path))
94 LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.", path.c_str()); 109 return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
95 return false; 110
111 // Specifying only the Create flag is invalid
112 if (mode.create_flag && !mode.read_flag && !mode.write_flag) {
113 return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
114 }
115
116 if (!FileUtil::Exists(path)) {
117 if (!mode.create_flag) {
118 LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.", path.c_str());
119 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Status);
120 } else {
121 // Create the file
122 FileUtil::CreateEmptyFile(path);
123 }
96 } 124 }
97 125
98 std::string mode_string; 126 std::string mode_string = "";
99 if (mode.create_flag) 127 if (mode.write_flag)
100 mode_string = "w+"; 128 mode_string += "r+"; // Files opened with Write access can be read from
101 else if (mode.write_flag)
102 mode_string = "r+"; // Files opened with Write access can be read from
103 else if (mode.read_flag) 129 else if (mode.read_flag)
104 mode_string = "r"; 130 mode_string += "r";
105 131
106 // Open the file in binary mode, to avoid problems with CR/LF on Windows systems 132 // Open the file in binary mode, to avoid problems with CR/LF on Windows systems
107 mode_string += "b"; 133 mode_string += "b";
108 134
109 file = Common::make_unique<FileUtil::IOFile>(path, mode_string.c_str()); 135 file = Common::make_unique<FileUtil::IOFile>(path, mode_string.c_str());
110 return file->IsOpen(); 136 if (file->IsOpen())
137 return RESULT_SUCCESS;
138 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Status);
111} 139}
112 140
113size_t DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const { 141ResultVal<size_t> DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const {
142 if (!mode.read_flag && !mode.write_flag)
143 return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
144
114 file->Seek(offset, SEEK_SET); 145 file->Seek(offset, SEEK_SET);
115 return file->ReadBytes(buffer, length); 146 return MakeResult<size_t>(file->ReadBytes(buffer, length));
116} 147}
117 148
118size_t DiskFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const { 149ResultVal<size_t> DiskFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const {
150 if (!mode.write_flag)
151 return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
152
119 file->Seek(offset, SEEK_SET); 153 file->Seek(offset, SEEK_SET);
120 size_t written = file->WriteBytes(buffer, length); 154 size_t written = file->WriteBytes(buffer, length);
121 if (flush) 155 if (flush)
122 file->Flush(); 156 file->Flush();
123 return written; 157 return MakeResult<size_t>(written);
124} 158}
125 159
126u64 DiskFile::GetSize() const { 160u64 DiskFile::GetSize() const {
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h
index ef9a98057..b4cc2f702 100644
--- a/src/core/file_sys/disk_archive.h
+++ b/src/core/file_sys/disk_archive.h
@@ -33,11 +33,11 @@ public:
33 33
34 virtual std::string GetName() const override { return "DiskArchive: " + mount_point; } 34 virtual std::string GetName() const override { return "DiskArchive: " + mount_point; }
35 35
36 std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; 36 ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, const Mode mode) const override;
37 bool DeleteFile(const Path& path) const override; 37 ResultCode DeleteFile(const Path& path) const override;
38 bool RenameFile(const Path& src_path, const Path& dest_path) const override; 38 bool RenameFile(const Path& src_path, const Path& dest_path) const override;
39 bool DeleteDirectory(const Path& path) const override; 39 bool DeleteDirectory(const Path& path) const override;
40 ResultCode CreateFile(const Path& path, u32 size) const override; 40 ResultCode CreateFile(const Path& path, u64 size) const override;
41 bool CreateDirectory(const Path& path) const override; 41 bool CreateDirectory(const Path& path) const override;
42 bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; 42 bool RenameDirectory(const Path& src_path, const Path& dest_path) const override;
43 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; 43 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
@@ -54,9 +54,9 @@ class DiskFile : public FileBackend {
54public: 54public:
55 DiskFile(const DiskArchive& archive, const Path& path, const Mode mode); 55 DiskFile(const DiskArchive& archive, const Path& path, const Mode mode);
56 56
57 bool Open() override; 57 ResultCode Open() override;
58 size_t Read(u64 offset, size_t length, u8* buffer) const override; 58 ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override;
59 size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const override; 59 ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
60 u64 GetSize() const override; 60 u64 GetSize() const override;
61 bool SetSize(u64 size) const override; 61 bool SetSize(u64 size) const override;
62 bool Close() const override; 62 bool Close() const override;
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h
index df7165df3..9137bbbad 100644
--- a/src/core/file_sys/file_backend.h
+++ b/src/core/file_sys/file_backend.h
@@ -7,6 +7,7 @@
7#include <cstddef> 7#include <cstddef>
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/hle/result.h"
10 11
11//////////////////////////////////////////////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////////////////////////////////////////////
12// FileSys namespace 13// FileSys namespace
@@ -20,18 +21,18 @@ public:
20 21
21 /** 22 /**
22 * Open the file 23 * Open the file
23 * @return true if the file opened correctly 24 * @return Result of the file operation
24 */ 25 */
25 virtual bool Open() = 0; 26 virtual ResultCode Open() = 0;
26 27
27 /** 28 /**
28 * Read data from the file 29 * Read data from the file
29 * @param offset Offset in bytes to start reading data from 30 * @param offset Offset in bytes to start reading data from
30 * @param length Length in bytes of data to read from file 31 * @param length Length in bytes of data to read from file
31 * @param buffer Buffer to read data into 32 * @param buffer Buffer to read data into
32 * @return Number of bytes read 33 * @return Number of bytes read, or error code
33 */ 34 */
34 virtual size_t Read(u64 offset, size_t length, u8* buffer) const = 0; 35 virtual ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const = 0;
35 36
36 /** 37 /**
37 * Write data to the file 38 * Write data to the file
@@ -39,9 +40,9 @@ public:
39 * @param length Length in bytes of data to write to file 40 * @param length Length in bytes of data to write to file
40 * @param flush The flush parameters (0 == do not flush) 41 * @param flush The flush parameters (0 == do not flush)
41 * @param buffer Buffer to read data from 42 * @param buffer Buffer to read data from
42 * @return Number of bytes written 43 * @return Number of bytes written, or error code
43 */ 44 */
44 virtual size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const = 0; 45 virtual ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const = 0;
45 46
46 /** 47 /**
47 * Get the size of the file in bytes 48 * Get the size of the file in bytes
diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp
index 2efc31a8c..a8e9a72ef 100644
--- a/src/core/file_sys/ivfc_archive.cpp
+++ b/src/core/file_sys/ivfc_archive.cpp
@@ -20,13 +20,15 @@ std::string IVFCArchive::GetName() const {
20 return "IVFC"; 20 return "IVFC";
21} 21}
22 22
23std::unique_ptr<FileBackend> IVFCArchive::OpenFile(const Path& path, const Mode mode) const { 23ResultVal<std::unique_ptr<FileBackend>> IVFCArchive::OpenFile(const Path& path, const Mode mode) const {
24 return Common::make_unique<IVFCFile>(romfs_file, data_offset, data_size); 24 return MakeResult<std::unique_ptr<FileBackend>>(Common::make_unique<IVFCFile>(romfs_file, data_offset, data_size));
25} 25}
26 26
27bool IVFCArchive::DeleteFile(const Path& path) const { 27ResultCode IVFCArchive::DeleteFile(const Path& path) const {
28 LOG_CRITICAL(Service_FS, "Attempted to delete a file from an IVFC archive (%s).", GetName().c_str()); 28 LOG_CRITICAL(Service_FS, "Attempted to delete a file from an IVFC archive (%s).", GetName().c_str());
29 return false; 29 // TODO(Subv): Verify error code
30 return ResultCode(ErrorDescription::NoData, ErrorModule::FS,
31 ErrorSummary::Canceled, ErrorLevel::Status);
30} 32}
31 33
32bool IVFCArchive::RenameFile(const Path& src_path, const Path& dest_path) const { 34bool IVFCArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
@@ -39,7 +41,7 @@ bool IVFCArchive::DeleteDirectory(const Path& path) const {
39 return false; 41 return false;
40} 42}
41 43
42ResultCode IVFCArchive::CreateFile(const Path& path, u32 size) const { 44ResultCode IVFCArchive::CreateFile(const Path& path, u64 size) const {
43 LOG_CRITICAL(Service_FS, "Attempted to create a file in an IVFC archive (%s).", GetName().c_str()); 45 LOG_CRITICAL(Service_FS, "Attempted to create a file in an IVFC archive (%s).", GetName().c_str());
44 // TODO: Verify error code 46 // TODO: Verify error code
45 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, ErrorLevel::Permanent); 47 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, ErrorLevel::Permanent);
@@ -66,17 +68,18 @@ u64 IVFCArchive::GetFreeBytes() const {
66 68
67//////////////////////////////////////////////////////////////////////////////////////////////////// 69////////////////////////////////////////////////////////////////////////////////////////////////////
68 70
69size_t IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const { 71ResultVal<size_t> IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const {
70 LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length); 72 LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length);
71 romfs_file->Seek(data_offset + offset, SEEK_SET); 73 romfs_file->Seek(data_offset + offset, SEEK_SET);
72 size_t read_length = (size_t)std::min((u64)length, data_size - offset); 74 size_t read_length = (size_t)std::min((u64)length, data_size - offset);
73 75
74 return romfs_file->ReadBytes(buffer, read_length); 76 return MakeResult<size_t>(romfs_file->ReadBytes(buffer, read_length));
75} 77}
76 78
77size_t IVFCFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const { 79ResultVal<size_t> IVFCFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const {
78 LOG_ERROR(Service_FS, "Attempted to write to IVFC file"); 80 LOG_ERROR(Service_FS, "Attempted to write to IVFC file");
79 return 0; 81 // TODO(Subv): Find error code
82 return MakeResult<size_t>(0);
80} 83}
81 84
82u64 IVFCFile::GetSize() const { 85u64 IVFCFile::GetSize() const {
diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h
index f3fd82de4..19d32dcca 100644
--- a/src/core/file_sys/ivfc_archive.h
+++ b/src/core/file_sys/ivfc_archive.h
@@ -34,11 +34,11 @@ public:
34 34
35 std::string GetName() const override; 35 std::string GetName() const override;
36 36
37 std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; 37 ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, const Mode mode) const override;
38 bool DeleteFile(const Path& path) const override; 38 ResultCode DeleteFile(const Path& path) const override;
39 bool RenameFile(const Path& src_path, const Path& dest_path) const override; 39 bool RenameFile(const Path& src_path, const Path& dest_path) const override;
40 bool DeleteDirectory(const Path& path) const override; 40 bool DeleteDirectory(const Path& path) const override;
41 ResultCode CreateFile(const Path& path, u32 size) const override; 41 ResultCode CreateFile(const Path& path, u64 size) const override;
42 bool CreateDirectory(const Path& path) const override; 42 bool CreateDirectory(const Path& path) const override;
43 bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; 43 bool RenameDirectory(const Path& src_path, const Path& dest_path) const override;
44 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; 44 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
@@ -55,9 +55,9 @@ public:
55 IVFCFile(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size) 55 IVFCFile(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
56 : romfs_file(file), data_offset(offset), data_size(size) {} 56 : romfs_file(file), data_offset(offset), data_size(size) {}
57 57
58 bool Open() override { return true; } 58 ResultCode Open() override { return RESULT_SUCCESS; }
59 size_t Read(u64 offset, size_t length, u8* buffer) const override; 59 ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override;
60 size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const override; 60 ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
61 u64 GetSize() const override; 61 u64 GetSize() const override;
62 bool SetSize(u64 size) const override; 62 bool SetSize(u64 size) const override;
63 bool Close() const override { return false; } 63 bool Close() const override { return false; }
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 69613fbbb..0cb76ba1c 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -19,8 +19,12 @@
19enum class ErrorDescription : u32 { 19enum class ErrorDescription : u32 {
20 Success = 0, 20 Success = 0,
21 WrongAddress = 53, 21 WrongAddress = 53,
22 FS_NotFound = 100, 22 FS_NotFound = 120,
23 FS_AlreadyExists = 190,
24 FS_InvalidOpenFlags = 230,
25 FS_NotAFile = 250,
23 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,
24 InvalidSection = 1000, 28 InvalidSection = 1000,
25 TooLarge = 1001, 29 TooLarge = 1001,
26 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..525432957 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -310,7 +310,8 @@ ResultCode UpdateConfigNANDSavegame() {
310 310
311ResultCode FormatConfig() { 311ResultCode FormatConfig() {
312 ResultCode res = DeleteConfigNANDSaveFile(); 312 ResultCode res = DeleteConfigNANDSaveFile();
313 if (!res.IsSuccess()) 313 // The delete command fails if the file doesn't exist, so we have to check that too
314 if (!res.IsSuccess() && res.description != ErrorDescription::FS_NotFound)
314 return res; 315 return res;
315 // Delete the old data 316 // Delete the old data
316 cfg_config_file_buffer.fill(0); 317 cfg_config_file_buffer.fill(0);
@@ -407,7 +408,7 @@ void Init() {
407 // If the archive didn't exist, create the files inside 408 // If the archive didn't exist, create the files inside
408 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { 409 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
409 // Format the archive to create the directories 410 // Format the archive to create the directories
410 Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); 411 Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, FileSys::ArchiveFormatInfo(), archive_path);
411 412
412 // Open it again to get a valid archive now that the folder exists 413 // 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); 414 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 d64b3656a..590697e76 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -103,7 +103,18 @@ ResultVal<bool> File::SyncRequest() {
103 u32 address = cmd_buff[5]; 103 u32 address = cmd_buff[5];
104 LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x", 104 LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x",
105 GetTypeName().c_str(), GetName().c_str(), offset, length, address); 105 GetTypeName().c_str(), GetName().c_str(), offset, length, address);
106 cmd_buff[2] = static_cast<u32>(backend->Read(offset, length, Memory::GetPointer(address))); 106
107 if (offset + length > backend->GetSize()) {
108 LOG_ERROR(Service_FS, "Reading from out of bounds offset=0x%llX length=0x%08X file_size=0x%llX",
109 offset, length, backend->GetSize());
110 }
111
112 ResultVal<size_t> read = backend->Read(offset, length, Memory::GetPointer(address));
113 if (read.Failed()) {
114 cmd_buff[1] = read.Code().raw;
115 return read.Code();
116 }
117 cmd_buff[2] = static_cast<u32>(*read);
107 break; 118 break;
108 } 119 }
109 120
@@ -116,7 +127,13 @@ ResultVal<bool> File::SyncRequest() {
116 u32 address = cmd_buff[6]; 127 u32 address = cmd_buff[6];
117 LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", 128 LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
118 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); 129 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
119 cmd_buff[2] = static_cast<u32>(backend->Write(offset, length, flush != 0, Memory::GetPointer(address))); 130
131 ResultVal<size_t> written = backend->Write(offset, length, flush != 0, Memory::GetPointer(address));
132 if (written.Failed()) {
133 cmd_buff[1] = written.Code().raw;
134 return written.Code();
135 }
136 cmd_buff[2] = static_cast<u32>(*written);
120 break; 137 break;
121 } 138 }
122 139
@@ -294,13 +311,11 @@ ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_han
294 if (archive == nullptr) 311 if (archive == nullptr)
295 return ERR_INVALID_HANDLE; 312 return ERR_INVALID_HANDLE;
296 313
297 std::unique_ptr<FileSys::FileBackend> backend = archive->OpenFile(path, mode); 314 auto backend = archive->OpenFile(path, mode);
298 if (backend == nullptr) { 315 if (backend.Failed())
299 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, 316 return backend.Code();
300 ErrorSummary::NotFound, ErrorLevel::Status);
301 }
302 317
303 auto file = Kernel::SharedPtr<File>(new File(std::move(backend), path)); 318 auto file = Kernel::SharedPtr<File>(new File(backend.MoveFrom(), path));
304 return MakeResult<Kernel::SharedPtr<File>>(std::move(file)); 319 return MakeResult<Kernel::SharedPtr<File>>(std::move(file));
305} 320}
306 321
@@ -309,10 +324,7 @@ ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Pa
309 if (archive == nullptr) 324 if (archive == nullptr)
310 return ERR_INVALID_HANDLE; 325 return ERR_INVALID_HANDLE;
311 326
312 if (archive->DeleteFile(path)) 327 return archive->DeleteFile(path);
313 return RESULT_SUCCESS;
314 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
315 ErrorSummary::Canceled, ErrorLevel::Status);
316} 328}
317 329
318ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, 330ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path,
@@ -347,7 +359,7 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy
347 ErrorSummary::Canceled, ErrorLevel::Status); 359 ErrorSummary::Canceled, ErrorLevel::Status);
348} 360}
349 361
350ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u32 file_size) { 362ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u64 file_size) {
351 ArchiveBackend* archive = GetArchive(archive_handle); 363 ArchiveBackend* archive = GetArchive(archive_handle);
352 if (archive == nullptr) 364 if (archive == nullptr)
353 return ERR_INVALID_HANDLE; 365 return ERR_INVALID_HANDLE;
@@ -395,7 +407,7 @@ ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle a
395 407
396 std::unique_ptr<FileSys::DirectoryBackend> backend = archive->OpenDirectory(path); 408 std::unique_ptr<FileSys::DirectoryBackend> backend = archive->OpenDirectory(path);
397 if (backend == nullptr) { 409 if (backend == nullptr) {
398 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, 410 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS,
399 ErrorSummary::NotFound, ErrorLevel::Permanent); 411 ErrorSummary::NotFound, ErrorLevel::Permanent);
400 } 412 }
401 413
@@ -410,49 +422,45 @@ ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) {
410 return MakeResult<u64>(archive->GetFreeBytes()); 422 return MakeResult<u64>(archive->GetFreeBytes());
411} 423}
412 424
413ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { 425ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, const FileSys::Path& path) {
414 auto archive_itr = id_code_map.find(id_code); 426 auto archive_itr = id_code_map.find(id_code);
415 if (archive_itr == id_code_map.end()) { 427 if (archive_itr == id_code_map.end()) {
416 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error 428 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
417 } 429 }
418 430
419 return archive_itr->second->Format(path); 431 return archive_itr->second->Format(path, format_info);
432}
433
434ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code, FileSys::Path& archive_path) {
435 auto archive = id_code_map.find(id_code);
436 if (archive == id_code_map.end()) {
437 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
438 }
439
440 return archive->second->GetFormatInfo(archive_path);
420} 441}
421 442
422ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size) { 443ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size, const FileSys::ArchiveFormatInfo& format_info) {
423 // Construct the binary path to the archive first 444 // Construct the binary path to the archive first
424 FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); 445 FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
425 446
426 std::string media_type_directory; 447 auto archive = id_code_map.find(media_type == MediaType::NAND ? ArchiveIdCode::SharedExtSaveData : ArchiveIdCode::ExtSaveData);
427 if (media_type == MediaType::NAND) { 448
428 media_type_directory = FileUtil::GetUserPath(D_NAND_IDX); 449 if (archive == id_code_map.end()) {
429 } else if (media_type == MediaType::SDMC) { 450 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
430 media_type_directory = FileUtil::GetUserPath(D_SDMC_IDX);
431 } else {
432 LOG_ERROR(Service_FS, "Unsupported media type %u", media_type);
433 return ResultCode(-1); // TODO(Subv): Find the right error code
434 } 451 }
435 452
436 std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); 453 auto ext_savedata = static_cast<FileSys::ArchiveFactory_ExtSaveData*>(archive->second.get());
437 std::string game_path = FileSys::GetExtSaveDataPath(base_path, path); 454
438 // These two folders are always created with the ExtSaveData 455 ResultCode result = ext_savedata->Format(path, format_info);
439 std::string user_path = game_path + "user/"; 456 if (result.IsError())
440 std::string boss_path = game_path + "boss/"; 457 return result;
441 if (!FileUtil::CreateFullPath(user_path))
442 return ResultCode(-1); // TODO(Subv): Find the right error code
443 if (!FileUtil::CreateFullPath(boss_path))
444 return ResultCode(-1); // TODO(Subv): Find the right error code
445 458
446 u8* smdh_icon = Memory::GetPointer(icon_buffer); 459 u8* smdh_icon = Memory::GetPointer(icon_buffer);
447 if (!smdh_icon) 460 if (!smdh_icon)
448 return ResultCode(-1); // TODO(Subv): Find the right error code 461 return ResultCode(-1); // TODO(Subv): Find the right error code
449 462
450 // Create the icon 463 ext_savedata->WriteIcon(path, smdh_icon, icon_size);
451 FileUtil::IOFile icon_file(game_path + "icon", "wb+");
452 if (!icon_file.IsGood())
453 return ResultCode(-1); // TODO(Subv): Find the right error code
454
455 icon_file.WriteBytes(smdh_icon, icon_size);
456 return RESULT_SUCCESS; 464 return RESULT_SUCCESS;
457} 465}
458 466
@@ -473,7 +481,7 @@ ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) {
473 // Delete all directories (/user, /boss) and the icon file. 481 // Delete all directories (/user, /boss) and the icon file.
474 std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); 482 std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND);
475 std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); 483 std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path);
476 if (!FileUtil::DeleteDirRecursively(extsavedata_path)) 484 if (FileUtil::Exists(extsavedata_path) && !FileUtil::DeleteDirRecursively(extsavedata_path))
477 return ResultCode(-1); // TODO(Subv): Find the right error code 485 return ResultCode(-1); // TODO(Subv): Find the right error code
478 return RESULT_SUCCESS; 486 return RESULT_SUCCESS;
479} 487}
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 952deb4d4..006606740 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -136,7 +136,7 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy
136 * @param file_size The size of the new file, filled with zeroes 136 * @param file_size The size of the new file, filled with zeroes
137 * @return File creation result code 137 * @return File creation result code
138 */ 138 */
139ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u32 file_size); 139ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u64 file_size);
140 140
141/** 141/**
142 * Create a Directory from an Archive 142 * Create a Directory from an Archive
@@ -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 e6c1f3616..3ec7ceb30 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -234,7 +234,7 @@ static void DeleteDirectory(Service::Interface* self) {
234 * 3 : Archive handle upper word 234 * 3 : Archive handle upper word
235 * 4 : File path string type 235 * 4 : File path string type
236 * 5 : File path string size 236 * 5 : File path string size
237 * 7 : File size (filled with zeroes) 237 * 7-8 : File size
238 * 10: File path string data 238 * 10: File path string data
239 * Outputs: 239 * Outputs:
240 * 1 : Result of function, 0 on success, otherwise error code 240 * 1 : Result of function, 0 on success, otherwise error code
@@ -245,12 +245,12 @@ static void CreateFile(Service::Interface* self) {
245 ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); 245 ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
246 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); 246 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
247 u32 filename_size = cmd_buff[5]; 247 u32 filename_size = cmd_buff[5];
248 u32 file_size = cmd_buff[7]; 248 u64 file_size = ((u64)cmd_buff[8] << 32) | cmd_buff[7];
249 u32 filename_ptr = cmd_buff[10]; 249 u32 filename_ptr = cmd_buff[10];
250 250
251 FileSys::Path file_path(filename_type, filename_size, filename_ptr); 251 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
252 252
253 LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", filename_type, filename_size, file_path.DebugStr().c_str()); 253 LOG_DEBUG(Service_FS, "type=%d size=%llu data=%s", filename_type, filename_size, file_path.DebugStr().c_str());
254 254
255 cmd_buff[1] = CreateFileInArchive(archive_handle, file_path, file_size).raw; 255 cmd_buff[1] = CreateFileInArchive(archive_handle, file_path, file_size).raw;
256} 256}
@@ -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!");