mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-26 03:20:05 +00:00
Implement FS::ControlArchive and IPC::CheckBufferMappingTranslation
This commit is contained in:
parent
4021ed79d9
commit
bba140a3ce
@ -103,12 +103,12 @@ bool Exists(const std::string& filename) {
|
|||||||
u64 GetFileModificationTimestamp(const std::string& filepath) {
|
u64 GetFileModificationTimestamp(const std::string& filepath) {
|
||||||
|
|
||||||
if (FileUtil::Exists(filepath)) {
|
if (FileUtil::Exists(filepath)) {
|
||||||
struct stat64 file_info;
|
struct stat file_info;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (0 == _wstat64(Common::UTF8ToUTF16W(filepath).c_str(), &file_info)) {
|
if (0 == _wstat64(Common::UTF8ToUTF16W(filepath).c_str(), &file_info)) {
|
||||||
#else
|
#else
|
||||||
if (0 == stat64(filepath.c_str(), &file_info)) {
|
if (0 == stat(filepath.c_str(), &file_info)) {
|
||||||
#endif
|
#endif
|
||||||
return static_cast<u64>(file_info.st_mtime);
|
return static_cast<u64>(file_info.st_mtime);
|
||||||
}
|
}
|
||||||
|
@ -157,4 +157,34 @@ inline DescriptorType GetDescriptorType(u32 descriptor) {
|
|||||||
return StaticBuffer;
|
return StaticBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CheckBufferMappingTranslation function
|
||||||
|
* If the translation's buffer_mapping_permission match the @param(mapping_type) type,
|
||||||
|
* this function will return a true
|
||||||
|
*/
|
||||||
|
inline bool CheckBufferMappingTranslation(MappedBufferPermissions mapping_type, u32 size,
|
||||||
|
u32 translation) {
|
||||||
|
if (0x8 == translation) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (mapping_type) {
|
||||||
|
case IPC::MappedBufferPermissions::R:
|
||||||
|
if (((size << 4) | 0xA) == translation) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IPC::MappedBufferPermissions::W:
|
||||||
|
if (((size << 4) | 0xC) == translation) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IPC::MappedBufferPermissions::RW:
|
||||||
|
if (((size << 4) | 0xE) == translation) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace IPC
|
} // namespace IPC
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "common/string_util.h"
|
||||||
#include "core/file_sys/archive_backend.h"
|
#include "core/file_sys/archive_backend.h"
|
||||||
#include "core/file_sys/archive_extsavedata.h"
|
#include "core/file_sys/archive_extsavedata.h"
|
||||||
#include "core/file_sys/archive_ncch.h"
|
#include "core/file_sys/archive_ncch.h"
|
||||||
@ -285,6 +286,53 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi
|
|||||||
return MakeResult<ArchiveHandle>(next_handle++);
|
return MakeResult<ArchiveHandle>(next_handle++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CheckArchiveHandle(ArchiveHandle handle) {
|
||||||
|
const auto handle_map_end_itr = handle_map.end();
|
||||||
|
for (auto itr = handle_map.begin(); itr != handle_map_end_itr; ++itr) {
|
||||||
|
if (itr->first == handle) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode CommitSavedata(ArchiveHandle handle) {
|
||||||
|
ResultCode result = RESULT_SUCCESS;
|
||||||
|
|
||||||
|
if (CheckArchiveHandle(handle)) {
|
||||||
|
result = RESULT_SUCCESS;
|
||||||
|
} else {
|
||||||
|
result = ResultCode(ErrorDescription::FS_ArchiveNotMounted, ErrorModule::FS,
|
||||||
|
ErrorSummary::NotFound, ErrorLevel::Status); // 0xC8804465
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 level = result.raw >> 27;
|
||||||
|
if (result.raw & 0x80000000) {
|
||||||
|
level -= 32;
|
||||||
|
}
|
||||||
|
if (level == 0xFFFFFFFF) {
|
||||||
|
LOG_ERROR(Service_FS, "Fatal Error : Invalid operation");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode GetTimeStamp(u32& input_buffer, u32& input_size, u32& output_buffer, u32& output_size) {
|
||||||
|
const std::string filepath = Common::UTF16ToUTF8(
|
||||||
|
std::u16string(reinterpret_cast<char16_t*>(Memory::GetPointer(input_buffer), input_size)));
|
||||||
|
|
||||||
|
u64 timestamp = FileUtil::GetFileModificationTimestamp(filepath);
|
||||||
|
|
||||||
|
if (timestamp != 0) {
|
||||||
|
Memory::WriteBlock(output_buffer, ×tamp, output_size);
|
||||||
|
LOG_DEBUG(Service_FS, "timestamp=0x016llX", timestamp);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_FS, "File was not exist, filepath :%s", filepath.c_str());
|
||||||
|
return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound,
|
||||||
|
ErrorLevel::Permanent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ResultCode CloseArchive(ArchiveHandle handle) {
|
ResultCode CloseArchive(ArchiveHandle handle) {
|
||||||
if (handle_map.erase(handle) == 0)
|
if (handle_map.erase(handle) == 0)
|
||||||
return ERR_INVALID_ARCHIVE_HANDLE;
|
return ERR_INVALID_ARCHIVE_HANDLE;
|
||||||
|
@ -84,6 +84,19 @@ protected:
|
|||||||
*/
|
*/
|
||||||
ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path);
|
ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ControlArchive action 0 : Commits save data changes
|
||||||
|
* @param handle Handle to the archive to control
|
||||||
|
*/
|
||||||
|
ResultCode CommitSavedata(ArchiveHandle handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ControlArchive action 1 : Retrieves a file's last-modified timestamp
|
||||||
|
* @param input_buffer and @param input_size will get a pathname
|
||||||
|
* @param output_buffer and @param output_size : if file exist, return the file timestamp
|
||||||
|
*/
|
||||||
|
ResultCode GetTimeStamp(u32& input_buffer, u32& input_size, u32& output_buffer, u32& output_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes an archive
|
* Closes an archive
|
||||||
* @param handle Handle to the archive to close
|
* @param handle Handle to the archive to close
|
||||||
|
@ -420,12 +420,14 @@ static void OpenDirectory(Service::Interface* self) {
|
|||||||
/**
|
/**
|
||||||
* FS_User::OpenArchive service function
|
* FS_User::OpenArchive service function
|
||||||
* Inputs:
|
* Inputs:
|
||||||
|
* 0 : Header Code [0x080C00C2]
|
||||||
* 1 : Archive ID
|
* 1 : Archive ID
|
||||||
* 2 : Archive low path type
|
* 2 : Archive low path type
|
||||||
* 3 : Archive low path size
|
* 3 : Archive low path size
|
||||||
* 4 : (LowPathSize << 14) | 2
|
* 4 : (LowPathSize << 14) | 2
|
||||||
* 5 : Archive low path
|
* 5 : Archive low path
|
||||||
* Outputs:
|
* Outputs:
|
||||||
|
* 0 : Header code
|
||||||
* 1 : Result of function, 0 on success, otherwise error code
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
* 2 : Archive handle lower word (unused)
|
* 2 : Archive handle lower word (unused)
|
||||||
* 3 : Archive handle upper word (same as file handle)
|
* 3 : Archive handle upper word (same as file handle)
|
||||||
@ -443,6 +445,8 @@ static void OpenArchive(Service::Interface* self) {
|
|||||||
archive_path.DebugStr().c_str());
|
archive_path.DebugStr().c_str());
|
||||||
|
|
||||||
ResultVal<ArchiveHandle> handle = OpenArchive(archive_id, archive_path);
|
ResultVal<ArchiveHandle> handle = OpenArchive(archive_id, archive_path);
|
||||||
|
|
||||||
|
cmd_buff[0] = IPC::MakeHeader(0x80C, 0x3, 0); // 0x080C00C0
|
||||||
cmd_buff[1] = handle.Code().raw;
|
cmd_buff[1] = handle.Code().raw;
|
||||||
if (handle.Succeeded()) {
|
if (handle.Succeeded()) {
|
||||||
cmd_buff[2] = *handle & 0xFFFFFFFF;
|
cmd_buff[2] = *handle & 0xFFFFFFFF;
|
||||||
@ -455,6 +459,96 @@ static void OpenArchive(Service::Interface* self) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FS_User::ControlArchive service function
|
||||||
|
* Inputs:
|
||||||
|
* 0 : Header code [0x080D0144]
|
||||||
|
* 1-2 : u64, Archive Handle
|
||||||
|
* 3 : Action
|
||||||
|
* 4 : Input Size
|
||||||
|
* 5 : Output Size
|
||||||
|
* 6 : (inputSize << 4) | 0xA
|
||||||
|
* 7 : void* Input
|
||||||
|
* 8 : (outputSize << 4) | 0xC
|
||||||
|
* 9 : void* Output
|
||||||
|
* Outputs:
|
||||||
|
* 0 : Header code
|
||||||
|
* 1 : Result code
|
||||||
|
* Notes:
|
||||||
|
* Action:
|
||||||
|
* 0 : Commits save data changes.
|
||||||
|
* Input : None
|
||||||
|
* Output : None
|
||||||
|
* 1 : Retrieves a file's last-modified timestamp
|
||||||
|
* Input : u16*, UTF-16 Path
|
||||||
|
* Output : u64, Time Stamp
|
||||||
|
* 30877 : Calls FSPXI command 0x00560102(unknown)
|
||||||
|
* Input : u16*, 12 bytes
|
||||||
|
* Output : 16 bytes
|
||||||
|
*/
|
||||||
|
static void ControlArchive(Service::Interface* self) {
|
||||||
|
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
|
|
||||||
|
ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]);
|
||||||
|
u32 action = cmd_buff[3];
|
||||||
|
u32 input_size = cmd_buff[4];
|
||||||
|
u32 output_size = cmd_buff[5];
|
||||||
|
u32 input_translation = cmd_buff[6];
|
||||||
|
u32 input_buffer = cmd_buff[7];
|
||||||
|
u32 output_translation = cmd_buff[8];
|
||||||
|
u32 output_buffer = cmd_buff[9];
|
||||||
|
|
||||||
|
if (!IPC::CheckBufferMappingTranslation(IPC::MappedBufferPermissions::R, input_size,
|
||||||
|
input_translation)) {
|
||||||
|
cmd_buff[0] = IPC::MakeHeader(0x0, 1, 0); // 0x40
|
||||||
|
cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS,
|
||||||
|
ErrorSummary::WrongArgument, ErrorLevel::Permanent)
|
||||||
|
.raw; // 0xD9001830
|
||||||
|
LOG_ERROR(Service_FS, "Check input_buffer_mapping_translation failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IPC::CheckBufferMappingTranslation(IPC::MappedBufferPermissions::W, output_size,
|
||||||
|
output_translation)) {
|
||||||
|
cmd_buff[0] = IPC::MakeHeader(0x0, 1, 0); // 0x40
|
||||||
|
cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS,
|
||||||
|
ErrorSummary::WrongArgument, ErrorLevel::Permanent)
|
||||||
|
.raw; // 0xD9001830
|
||||||
|
LOG_ERROR(Service_FS, "Check output_buffer_mapping_translation failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case 0: // Action 0 : Commits save data changes.
|
||||||
|
cmd_buff[0] = IPC::MakeHeader(0x80D, 1, 4); // 0x080d0044
|
||||||
|
cmd_buff[1] = CommitSavedata(archive_handle).raw;
|
||||||
|
cmd_buff[2] = input_translation;
|
||||||
|
cmd_buff[3] = input_buffer;
|
||||||
|
cmd_buff[4] = output_translation;
|
||||||
|
cmd_buff[5] = output_buffer;
|
||||||
|
LOG_WARNING(Service_FS, "(STUBBED) Commits save data changes, archive_handle=0x%08X",
|
||||||
|
archive_handle);
|
||||||
|
break;
|
||||||
|
case 1: // Action 1 : Retrieves a file's last-modified timestamp.
|
||||||
|
cmd_buff[0] = IPC::MakeHeader(0x80D, 1, 4); // 0x080d0044
|
||||||
|
cmd_buff[1] = GetTimeStamp(input_buffer, input_size, output_buffer, output_size).raw;
|
||||||
|
cmd_buff[2] = input_translation;
|
||||||
|
cmd_buff[3] = input_buffer;
|
||||||
|
cmd_buff[4] = output_translation;
|
||||||
|
cmd_buff[5] = output_buffer;
|
||||||
|
LOG_WARNING(Service_FS, "Retrieves a file's last-modified timestamp");
|
||||||
|
break;
|
||||||
|
case 30877:
|
||||||
|
default:
|
||||||
|
cmd_buff[0] = IPC::MakeHeader(0x80D, 1, 0);
|
||||||
|
cmd_buff[1] = ResultCode(ErrorDescription::NotImplemented, ErrorModule::FS,
|
||||||
|
ErrorSummary::NotSupported, ErrorLevel::Permanent)
|
||||||
|
.raw;
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FS_User::CloseArchive service function
|
* FS_User::CloseArchive service function
|
||||||
* Inputs:
|
* Inputs:
|
||||||
@ -462,13 +556,15 @@ static void OpenArchive(Service::Interface* self) {
|
|||||||
* 1 : Archive handle low word
|
* 1 : Archive handle low word
|
||||||
* 2 : Archive handle high word
|
* 2 : Archive handle high word
|
||||||
* Outputs:
|
* Outputs:
|
||||||
* 0 : ??? TODO(yuriks): Verify return header
|
* 0 : Header code
|
||||||
* 1 : Result of function, 0 on success, otherwise error code
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
*/
|
*/
|
||||||
static void CloseArchive(Service::Interface* self) {
|
static void CloseArchive(Service::Interface* self) {
|
||||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
|
|
||||||
ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]);
|
ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]);
|
||||||
|
|
||||||
|
cmd_buff[0] = IPC::MakeHeader(0x80E, 0x1, 0); // 0x080E0040
|
||||||
cmd_buff[1] = CloseArchive(archive_handle).raw;
|
cmd_buff[1] = CloseArchive(archive_handle).raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -928,7 +1024,7 @@ const Interface::FunctionInfo FunctionTable[] = {
|
|||||||
{0x080A0244, RenameDirectory, "RenameDirectory"},
|
{0x080A0244, RenameDirectory, "RenameDirectory"},
|
||||||
{0x080B0102, OpenDirectory, "OpenDirectory"},
|
{0x080B0102, OpenDirectory, "OpenDirectory"},
|
||||||
{0x080C00C2, OpenArchive, "OpenArchive"},
|
{0x080C00C2, OpenArchive, "OpenArchive"},
|
||||||
{0x080D0144, nullptr, "ControlArchive"},
|
{0x080D0144, ControlArchive, "ControlArchive"},
|
||||||
{0x080E0080, CloseArchive, "CloseArchive"},
|
{0x080E0080, CloseArchive, "CloseArchive"},
|
||||||
{0x080F0180, FormatThisUserSaveData, "FormatThisUserSaveData"},
|
{0x080F0180, FormatThisUserSaveData, "FormatThisUserSaveData"},
|
||||||
{0x08100200, CreateLegacySystemSaveData, "CreateLegacySystemSaveData"},
|
{0x08100200, CreateLegacySystemSaveData, "CreateLegacySystemSaveData"},
|
||||||
|
Loading…
Reference in New Issue
Block a user