mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 23:40:14 +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) {
|
||||
|
||||
if (FileUtil::Exists(filepath)) {
|
||||
struct stat64 file_info;
|
||||
struct stat file_info;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (0 == _wstat64(Common::UTF8ToUTF16W(filepath).c_str(), &file_info)) {
|
||||
#else
|
||||
if (0 == stat64(filepath.c_str(), &file_info)) {
|
||||
if (0 == stat(filepath.c_str(), &file_info)) {
|
||||
#endif
|
||||
return static_cast<u64>(file_info.st_mtime);
|
||||
}
|
||||
|
@ -157,4 +157,34 @@ inline DescriptorType GetDescriptorType(u32 descriptor) {
|
||||
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
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/file_sys/archive_backend.h"
|
||||
#include "core/file_sys/archive_extsavedata.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++);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (handle_map.erase(handle) == 0)
|
||||
return ERR_INVALID_ARCHIVE_HANDLE;
|
||||
|
@ -84,6 +84,19 @@ protected:
|
||||
*/
|
||||
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
|
||||
* @param handle Handle to the archive to close
|
||||
|
@ -420,12 +420,14 @@ static void OpenDirectory(Service::Interface* self) {
|
||||
/**
|
||||
* FS_User::OpenArchive service function
|
||||
* Inputs:
|
||||
* 0 : Header Code [0x080C00C2]
|
||||
* 1 : Archive ID
|
||||
* 2 : Archive low path type
|
||||
* 3 : Archive low path size
|
||||
* 4 : (LowPathSize << 14) | 2
|
||||
* 5 : Archive low path
|
||||
* Outputs:
|
||||
* 0 : Header code
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : Archive handle lower word (unused)
|
||||
* 3 : Archive handle upper word (same as file handle)
|
||||
@ -443,6 +445,8 @@ static void OpenArchive(Service::Interface* self) {
|
||||
archive_path.DebugStr().c_str());
|
||||
|
||||
ResultVal<ArchiveHandle> handle = OpenArchive(archive_id, archive_path);
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x80C, 0x3, 0); // 0x080C00C0
|
||||
cmd_buff[1] = handle.Code().raw;
|
||||
if (handle.Succeeded()) {
|
||||
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
|
||||
* Inputs:
|
||||
@ -462,13 +556,15 @@ static void OpenArchive(Service::Interface* self) {
|
||||
* 1 : Archive handle low word
|
||||
* 2 : Archive handle high word
|
||||
* Outputs:
|
||||
* 0 : ??? TODO(yuriks): Verify return header
|
||||
* 0 : Header code
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
static void CloseArchive(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -928,7 +1024,7 @@ const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x080A0244, RenameDirectory, "RenameDirectory"},
|
||||
{0x080B0102, OpenDirectory, "OpenDirectory"},
|
||||
{0x080C00C2, OpenArchive, "OpenArchive"},
|
||||
{0x080D0144, nullptr, "ControlArchive"},
|
||||
{0x080D0144, ControlArchive, "ControlArchive"},
|
||||
{0x080E0080, CloseArchive, "CloseArchive"},
|
||||
{0x080F0180, FormatThisUserSaveData, "FormatThisUserSaveData"},
|
||||
{0x08100200, CreateLegacySystemSaveData, "CreateLegacySystemSaveData"},
|
||||
|
Loading…
Reference in New Issue
Block a user