summaryrefslogtreecommitdiff
path: root/src/core/hle
diff options
context:
space:
mode:
authorGravatar Subv2014-12-16 00:33:41 -0500
committerGravatar Subv2014-12-17 19:21:38 -0500
commitea9ce0fba776eef8f9e4f3a86e71256091732a14 (patch)
tree9e698ba00993a4aff1df4d60f9fcf3cf135ee76c /src/core/hle
parentMerge pull request #293 from lioncash/sops (diff)
downloadyuzu-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.cpp1
-rw-r--r--src/core/hle/kernel/kernel.h6
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/fs/archive.cpp51
-rw-r--r--src/core/hle/service/fs/archive.h6
-rw-r--r--src/core/hle/service/fs/fs_user.cpp42
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
15Handle g_main_thread = 0; 15Handle g_main_thread = 0;
16ObjectPool g_object_pool; 16ObjectPool g_object_pool;
17u64 g_program_id = 0;
17 18
18ObjectPool::ObjectPool() { 19ObjectPool::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:
151extern ObjectPool g_object_pool; 151extern ObjectPool g_object_pool;
152extern Handle g_main_thread; 152extern 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?
158extern u64 g_program_id;
159
154/// Initialize the kernel 160/// Initialize the kernel
155void Init(); 161void 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.
18enum class ErrorDescription : u32 { 18enum 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
386ResultCode 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
370void ArchiveInit() { 409void 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 */
110ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); 110ResultVal<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 */
116ResultCode FormatSaveData();
117
112/// Initialize archives 118/// Initialize archives
113void ArchiveInit(); 119void 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) {
50static void OpenFile(Service::Interface* self) { 50static 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 */
405static 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 */
420static 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
401const FSUserInterface::FunctionInfo FunctionTable[] = { 429const 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"},