summaryrefslogtreecommitdiff
path: root/src/core/hle
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/core/hle
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/core/hle')
-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
6 files changed, 164 insertions, 69 deletions
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!");