Implement FS::ControlArchive and IPC::CheckBufferMappingTranslation

This commit is contained in:
JamePeng 2016-10-02 15:54:06 +08:00
parent 4021ed79d9
commit bba140a3ce
5 changed files with 191 additions and 4 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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, &timestamp, 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;

View File

@ -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

View File

@ -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"},