diff options
| author | 2014-12-16 00:33:41 -0500 | |
|---|---|---|
| committer | 2014-12-17 19:21:38 -0500 | |
| commit | ea9ce0fba776eef8f9e4f3a86e71256091732a14 (patch) | |
| tree | 9e698ba00993a4aff1df4d60f9fcf3cf135ee76c /src/core/hle | |
| parent | Merge pull request #293 from lioncash/sops (diff) | |
| download | yuzu-ea9ce0fba776eef8f9e4f3a86e71256091732a14.tar.gz yuzu-ea9ce0fba776eef8f9e4f3a86e71256091732a14.tar.xz yuzu-ea9ce0fba776eef8f9e4f3a86e71256091732a14.zip | |
Filesystem/Archives: Implemented the SaveData archive
The savedata for each game is stored in /savedata/<ProgramID> for NCCH files. ELF files and 3DSX files use the folder 0 because they have no ID information
Got rid of the code duplication in File and Directory
Files that deal with the host machine's file system now live in DiskFile, similarly for directories and DiskDirectory and archives with DiskArchive.
FS_U: Use the correct error code when a file wasn't found
Diffstat (limited to 'src/core/hle')
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 6 | ||||
| -rw-r--r-- | src/core/hle/result.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/fs/archive.cpp | 51 | ||||
| -rw-r--r-- | src/core/hle/service/fs/archive.h | 6 | ||||
| -rw-r--r-- | src/core/hle/service/fs/fs_user.cpp | 42 |
6 files changed, 95 insertions, 13 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 929422b36..6a690e915 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -14,6 +14,7 @@ namespace Kernel { | |||
| 14 | 14 | ||
| 15 | Handle g_main_thread = 0; | 15 | Handle g_main_thread = 0; |
| 16 | ObjectPool g_object_pool; | 16 | ObjectPool g_object_pool; |
| 17 | u64 g_program_id = 0; | ||
| 17 | 18 | ||
| 18 | ObjectPool::ObjectPool() { | 19 | ObjectPool::ObjectPool() { |
| 19 | next_id = INITIAL_NEXT_ID; | 20 | next_id = INITIAL_NEXT_ID; |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 7e0f15c84..7123485be 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -151,6 +151,12 @@ private: | |||
| 151 | extern ObjectPool g_object_pool; | 151 | extern ObjectPool g_object_pool; |
| 152 | extern Handle g_main_thread; | 152 | extern Handle g_main_thread; |
| 153 | 153 | ||
| 154 | /// The ID code of the currently running game | ||
| 155 | /// TODO(Subv): This variable should not be here, | ||
| 156 | /// we need a way to store information about the currently loaded application | ||
| 157 | /// for later query during runtime, maybe using the LDR service? | ||
| 158 | extern u64 g_program_id; | ||
| 159 | |||
| 154 | /// Initialize the kernel | 160 | /// Initialize the kernel |
| 155 | void Init(); | 161 | void Init(); |
| 156 | 162 | ||
diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 15c4a2677..14d2be4a2 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | /// Detailed description of the error. This listing is likely incomplete. | 17 | /// Detailed description of the error. This listing is likely incomplete. |
| 18 | enum class ErrorDescription : u32 { | 18 | enum class ErrorDescription : u32 { |
| 19 | Success = 0, | 19 | Success = 0, |
| 20 | FS_NotFound = 100, | ||
| 21 | FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive | ||
| 20 | InvalidSection = 1000, | 22 | InvalidSection = 1000, |
| 21 | TooLarge = 1001, | 23 | TooLarge = 1001, |
| 22 | NotAuthorized = 1002, | 24 | NotAuthorized = 1002, |
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index caf82d556..9c3834733 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| 10 | #include "common/math_util.h" | 10 | #include "common/math_util.h" |
| 11 | 11 | ||
| 12 | #include "core/file_sys/archive_savedata.h" | ||
| 12 | #include "core/file_sys/archive_backend.h" | 13 | #include "core/file_sys/archive_backend.h" |
| 13 | #include "core/file_sys/archive_sdmc.h" | 14 | #include "core/file_sys/archive_sdmc.h" |
| 14 | #include "core/file_sys/directory_backend.h" | 15 | #include "core/file_sys/directory_backend.h" |
| @@ -135,6 +136,13 @@ public: | |||
| 135 | break; | 136 | break; |
| 136 | } | 137 | } |
| 137 | 138 | ||
| 139 | case FileCommand::Flush: | ||
| 140 | { | ||
| 141 | LOG_TRACE(Service_FS, "Flush"); | ||
| 142 | backend->Flush(); | ||
| 143 | break; | ||
| 144 | } | ||
| 145 | |||
| 138 | // Unknown command... | 146 | // Unknown command... |
| 139 | default: | 147 | default: |
| 140 | LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); | 148 | LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); |
| @@ -220,9 +228,18 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code) { | |||
| 220 | 228 | ||
| 221 | auto itr = id_code_map.find(id_code); | 229 | auto itr = id_code_map.find(id_code); |
| 222 | if (itr == id_code_map.end()) { | 230 | if (itr == id_code_map.end()) { |
| 231 | if (id_code == ArchiveIdCode::SaveData) { | ||
| 232 | // When a SaveData archive is created for the first time, it is not yet formatted | ||
| 233 | // and the save file/directory structure expected by the game has not yet been initialized. | ||
| 234 | // Returning the NotFormatted error code will signal the game to provision the SaveData archive | ||
| 235 | // with the files and folders that it expects. | ||
| 236 | // The FormatSaveData service call will create the SaveData archive when it is called. | ||
| 237 | return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, | ||
| 238 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 239 | } | ||
| 223 | // TODO: Verify error against hardware | 240 | // TODO: Verify error against hardware |
| 224 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | 241 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, |
| 225 | ErrorSummary::NotFound, ErrorLevel::Permanent); | 242 | ErrorSummary::NotFound, ErrorLevel::Permanent); |
| 226 | } | 243 | } |
| 227 | 244 | ||
| 228 | // This should never even happen in the first place with 64-bit handles, | 245 | // This should never even happen in the first place with 64-bit handles, |
| @@ -260,8 +277,8 @@ ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSy | |||
| 260 | 277 | ||
| 261 | std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); | 278 | std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); |
| 262 | if (backend == nullptr) { | 279 | if (backend == nullptr) { |
| 263 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | 280 | return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, |
| 264 | ErrorSummary::NotFound, ErrorLevel::Permanent); | 281 | ErrorSummary::NotFound, ErrorLevel::Status); |
| 265 | } | 282 | } |
| 266 | 283 | ||
| 267 | auto file = std::make_unique<File>(std::move(backend), path); | 284 | auto file = std::make_unique<File>(std::move(backend), path); |
| @@ -366,6 +383,28 @@ ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const F | |||
| 366 | return MakeResult<Handle>(handle); | 383 | return MakeResult<Handle>(handle); |
| 367 | } | 384 | } |
| 368 | 385 | ||
| 386 | ResultCode FormatSaveData() { | ||
| 387 | // TODO(Subv): Actually wipe the savedata folder after creating or opening it | ||
| 388 | |||
| 389 | // Do not create the archive again if it already exists | ||
| 390 | if (id_code_map.find(ArchiveIdCode::SaveData) != id_code_map.end()) | ||
| 391 | return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the correct error code | ||
| 392 | |||
| 393 | // Create the SaveData archive | ||
| 394 | std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX); | ||
| 395 | auto savedata_archive = std::make_unique<FileSys::Archive_SaveData>(savedata_directory, | ||
| 396 | Kernel::g_program_id); | ||
| 397 | |||
| 398 | if (savedata_archive->Initialize()) { | ||
| 399 | CreateArchive(std::move(savedata_archive), ArchiveIdCode::SaveData); | ||
| 400 | return RESULT_SUCCESS; | ||
| 401 | } else { | ||
| 402 | LOG_ERROR(Service_FS, "Can't instantiate SaveData archive with path %s", | ||
| 403 | savedata_archive->GetMountPoint().c_str()); | ||
| 404 | return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the proper error code | ||
| 405 | } | ||
| 406 | } | ||
| 407 | |||
| 369 | /// Initialize archives | 408 | /// Initialize archives |
| 370 | void ArchiveInit() { | 409 | void ArchiveInit() { |
| 371 | next_handle = 1; | 410 | next_handle = 1; |
| @@ -375,9 +414,9 @@ void ArchiveInit() { | |||
| 375 | // archive type is SDMC, so it is the only one getting exposed. | 414 | // archive type is SDMC, so it is the only one getting exposed. |
| 376 | 415 | ||
| 377 | std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); | 416 | std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); |
| 378 | auto archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory); | 417 | auto sdmc_archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory); |
| 379 | if (archive->Initialize()) | 418 | if (sdmc_archive->Initialize()) |
| 380 | CreateArchive(std::move(archive), ArchiveIdCode::SDMC); | 419 | CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC); |
| 381 | else | 420 | else |
| 382 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); | 421 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); |
| 383 | } | 422 | } |
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index a38de92e3..a128276b6 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h | |||
| @@ -109,6 +109,12 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons | |||
| 109 | */ | 109 | */ |
| 110 | ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); | 110 | ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); |
| 111 | 111 | ||
| 112 | /** | ||
| 113 | * Creates a blank SaveData archive. | ||
| 114 | * @return ResultCode 0 on success or the corresponding code on error | ||
| 115 | */ | ||
| 116 | ResultCode FormatSaveData(); | ||
| 117 | |||
| 112 | /// Initialize archives | 118 | /// Initialize archives |
| 113 | void ArchiveInit(); | 119 | void ArchiveInit(); |
| 114 | 120 | ||
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 0f75d5e3a..f99d84b2f 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp | |||
| @@ -3,11 +3,11 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/common.h" | 5 | #include "common/common.h" |
| 6 | #include "common/file_util.h" | ||
| 6 | #include "common/scope_exit.h" | 7 | #include "common/scope_exit.h" |
| 7 | |||
| 8 | #include "common/string_util.h" | 8 | #include "common/string_util.h" |
| 9 | #include "core/hle/service/fs/archive.h" | ||
| 10 | #include "core/hle/result.h" | 9 | #include "core/hle/result.h" |
| 10 | #include "core/hle/service/fs/archive.h" | ||
| 11 | #include "core/hle/service/fs/fs_user.h" | 11 | #include "core/hle/service/fs/fs_user.h" |
| 12 | #include "core/settings.h" | 12 | #include "core/settings.h" |
| 13 | 13 | ||
| @@ -50,9 +50,7 @@ static void Initialize(Service::Interface* self) { | |||
| 50 | static void OpenFile(Service::Interface* self) { | 50 | static void OpenFile(Service::Interface* self) { |
| 51 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 51 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 52 | 52 | ||
| 53 | // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to | 53 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); |
| 54 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 55 | Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 56 | auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | 54 | auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); |
| 57 | u32 filename_size = cmd_buff[5]; | 55 | u32 filename_size = cmd_buff[5]; |
| 58 | FileSys::Mode mode; mode.hex = cmd_buff[6]; | 56 | FileSys::Mode mode; mode.hex = cmd_buff[6]; |
| @@ -398,6 +396,36 @@ static void IsSdmcDetected(Service::Interface* self) { | |||
| 398 | LOG_DEBUG(Service_FS, "called"); | 396 | LOG_DEBUG(Service_FS, "called"); |
| 399 | } | 397 | } |
| 400 | 398 | ||
| 399 | /** | ||
| 400 | * FS_User::FormatSaveData service function | ||
| 401 | * Inputs: | ||
| 402 | * Outputs: | ||
| 403 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 404 | */ | ||
| 405 | static void FormatSaveData(Service::Interface* self) { | ||
| 406 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 407 | LOG_DEBUG(Service_FS, "(STUBBED)"); | ||
| 408 | |||
| 409 | // TODO(Subv): Find out what the inputs and outputs of this function are | ||
| 410 | |||
| 411 | cmd_buff[1] = FormatSaveData().raw; | ||
| 412 | } | ||
| 413 | |||
| 414 | /** | ||
| 415 | * FS_User::FormatThisUserSaveData service function | ||
| 416 | * Inputs: | ||
| 417 | * Outputs: | ||
| 418 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 419 | */ | ||
| 420 | static void FormatThisUserSaveData(Service::Interface* self) { | ||
| 421 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 422 | LOG_DEBUG(Service_FS, "(STUBBED)"); | ||
| 423 | |||
| 424 | // TODO(Subv): Find out what the inputs and outputs of this function are | ||
| 425 | |||
| 426 | cmd_buff[1] = FormatSaveData().raw; | ||
| 427 | } | ||
| 428 | |||
| 401 | const FSUserInterface::FunctionInfo FunctionTable[] = { | 429 | const FSUserInterface::FunctionInfo FunctionTable[] = { |
| 402 | {0x000100C6, nullptr, "Dummy1"}, | 430 | {0x000100C6, nullptr, "Dummy1"}, |
| 403 | {0x040100C4, nullptr, "Control"}, | 431 | {0x040100C4, nullptr, "Control"}, |
| @@ -415,7 +443,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { | |||
| 415 | {0x080C00C2, OpenArchive, "OpenArchive"}, | 443 | {0x080C00C2, OpenArchive, "OpenArchive"}, |
| 416 | {0x080D0144, nullptr, "ControlArchive"}, | 444 | {0x080D0144, nullptr, "ControlArchive"}, |
| 417 | {0x080E0080, CloseArchive, "CloseArchive"}, | 445 | {0x080E0080, CloseArchive, "CloseArchive"}, |
| 418 | {0x080F0180, nullptr, "FormatThisUserSaveData"}, | 446 | {0x080F0180, FormatThisUserSaveData,"FormatThisUserSaveData"}, |
| 419 | {0x08100200, nullptr, "CreateSystemSaveData"}, | 447 | {0x08100200, nullptr, "CreateSystemSaveData"}, |
| 420 | {0x08110040, nullptr, "DeleteSystemSaveData"}, | 448 | {0x08110040, nullptr, "DeleteSystemSaveData"}, |
| 421 | {0x08120080, nullptr, "GetFreeBytes"}, | 449 | {0x08120080, nullptr, "GetFreeBytes"}, |
| @@ -476,7 +504,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { | |||
| 476 | {0x08490040, nullptr, "GetArchiveResource"}, | 504 | {0x08490040, nullptr, "GetArchiveResource"}, |
| 477 | {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, | 505 | {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, |
| 478 | {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, | 506 | {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, |
| 479 | {0x084C0242, nullptr, "FormatSaveData"}, | 507 | {0x084C0242, FormatSaveData, "FormatSaveData"}, |
| 480 | {0x084D0102, nullptr, "GetLegacySubBannerData"}, | 508 | {0x084D0102, nullptr, "GetLegacySubBannerData"}, |
| 481 | {0x084E0342, nullptr, "UpdateSha256Context"}, | 509 | {0x084E0342, nullptr, "UpdateSha256Context"}, |
| 482 | {0x084F0102, nullptr, "ReadSpecialFile"}, | 510 | {0x084F0102, nullptr, "ReadSpecialFile"}, |