Add Artic Base support (#105)

* Add Artic Base support

* Add Android support
This commit is contained in:
PabloMK7 2024-05-12 20:17:06 +02:00 committed by GitHub
parent 572d3ab71c
commit 24c6ec5e6a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
83 changed files with 5592 additions and 516 deletions

View file

@ -58,6 +58,11 @@ public:
: RequestBuilder(
context, Header{MakeHeader(command_id, normal_params_size, translate_params_size)}) {}
RequestBuilder(Kernel::HLERequestContext& context, unsigned normal_params_size,
unsigned translate_params_size)
: RequestBuilder(context, Header{MakeHeader(context.CommandID(), normal_params_size,
translate_params_size)}) {}
// Validate on destruction, as there shouldn't be any case where we don't want it
~RequestBuilder() {
ValidateHeader();

View file

@ -206,6 +206,11 @@ public:
return {cmd_buf[0]};
}
/// Returns the Command ID from the IPC command buffer.
u16 CommandID() const {
return static_cast<u16>(CommandHeader().command_id.Value());
}
/**
* Returns the session through which this request was made. This can be used as a map key to
* access per-client data on services.

View file

@ -266,7 +266,7 @@ ResultVal<std::size_t> CIAFile::WriteContentData(u64 offset, std::size_t length,
}
ResultVal<std::size_t> CIAFile::Write(u64 offset, std::size_t length, bool flush,
const u8* buffer) {
bool update_timestamp, const u8* buffer) {
written += length;
// TODO(shinyquagsire23): Can we assume that things will only be written in sequence?
@ -347,7 +347,7 @@ bool CIAFile::SetSize(u64 size) const {
return false;
}
bool CIAFile::Close() const {
bool CIAFile::Close() {
bool complete =
install_state >= CIAInstallState::TMDLoaded &&
content_written.size() == container.GetTitleMetadata().GetContentCount() &&
@ -419,7 +419,7 @@ ResultVal<std::size_t> TicketFile::Read(u64 offset, std::size_t length, u8* buff
}
ResultVal<std::size_t> TicketFile::Write(u64 offset, std::size_t length, bool flush,
const u8* buffer) {
bool update_timestamp, const u8* buffer) {
written += length;
data.resize(written);
std::memcpy(data.data() + offset, buffer, length);
@ -434,7 +434,7 @@ bool TicketFile::SetSize(u64 size) const {
return false;
}
bool TicketFile::Close() const {
bool TicketFile::Close() {
FileSys::Ticket ticket;
if (ticket.Load(data, 0) == Loader::ResultStatus::Success) {
LOG_WARNING(Service_AM, "Discarding ticket for {:#016X}.", ticket.GetTitleID());
@ -480,7 +480,7 @@ InstallStatus InstallCIA(const std::string& path,
while (total_bytes_read != file_size) {
std::size_t bytes_read = file.ReadBytes(buffer.data(), buffer.size());
auto result = installFile.Write(static_cast<u64>(total_bytes_read), bytes_read, true,
static_cast<u8*>(buffer.data()));
false, static_cast<u8*>(buffer.data()));
if (update_callback) {
update_callback(total_bytes_read, file_size);
@ -590,7 +590,8 @@ InstallStatus InstallFromNus(u64 title_id, int version) {
const u64 offset =
Common::AlignUp(current_offset + data.size(), FileSys::CIA_SECTION_ALIGNMENT);
data.resize(offset - current_offset, 0);
const auto result = install_file.Write(current_offset, data.size(), true, data.data());
const auto result =
install_file.Write(current_offset, data.size(), true, false, data.data());
if (result.Failed()) {
LOG_ERROR(Service_AM, "CIA file installation aborted with error code {:08x}",
result.Code().raw);
@ -1464,9 +1465,9 @@ public:
return file->backend->Read(offset + file_offset, length, buffer);
}
ResultVal<std::size_t> Write(u64 offset, std::size_t length, bool flush,
ResultVal<std::size_t> Write(u64 offset, std::size_t length, bool flush, bool update_timestamp,
const u8* buffer) override {
return file->backend->Write(offset + file_offset, length, flush, buffer);
return file->backend->Write(offset + file_offset, length, flush, update_timestamp, buffer);
}
u64 GetSize() const override {
@ -1475,7 +1476,7 @@ public:
bool SetSize(u64 size) const override {
return false;
}
bool Close() const override {
bool Close() override {
return false;
}
void Flush() const override {}

View file

@ -111,11 +111,11 @@ public:
Result WriteTicket();
Result WriteTitleMetadata();
ResultVal<std::size_t> WriteContentData(u64 offset, std::size_t length, const u8* buffer);
ResultVal<std::size_t> Write(u64 offset, std::size_t length, bool flush,
ResultVal<std::size_t> Write(u64 offset, std::size_t length, bool flush, bool update_timestamp,
const u8* buffer) override;
u64 GetSize() const override;
bool SetSize(u64 size) const override;
bool Close() const override;
bool Close() override;
void Flush() const override;
private:
@ -146,11 +146,11 @@ public:
~TicketFile();
ResultVal<std::size_t> Read(u64 offset, std::size_t length, u8* buffer) const override;
ResultVal<std::size_t> Write(u64 offset, std::size_t length, bool flush,
ResultVal<std::size_t> Write(u64 offset, std::size_t length, bool flush, bool update_timestamp,
const u8* buffer) override;
u64 GetSize() const override;
bool SetSize(u64 size) const override;
bool Close() const override;
bool Close() override;
void Flush() const override;
private:

View file

@ -217,7 +217,7 @@ bool Module::LoadSharedFont() {
const FileSys::Path file_path(std::vector<u8>(20, 0));
FileSys::Mode open_mode = {};
open_mode.read_flag.Assign(1);
auto file_result = archive.OpenFile(file_path, open_mode);
auto file_result = archive.OpenFile(file_path, open_mode, 0);
if (file_result.Failed())
return false;

View file

@ -75,7 +75,7 @@ Result OnlineService::InitializeSession(u64 init_program_id) {
boss_system_save_data_archive = std::move(archive_result).Unwrap();
} else if (archive_result.Code() == FileSys::ResultNotFound) {
// If the archive didn't exist, create the files inside
systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0);
systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0, 0, 0);
// Open it again to get a valid archive now that the folder exists
auto create_archive_result = systemsavedata_factory.Open(archive_path, 0);

View file

@ -116,7 +116,7 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) {
std::vector<u8> program_id(8);
u64_le le_program_id = cecd->system.Kernel().GetCurrentProcess()->codeset->program_id;
std::memcpy(program_id.data(), &le_program_id, sizeof(u64));
session_data->file->Write(0, sizeof(u64), true, program_id.data());
session_data->file->Write(0, sizeof(u64), true, false, program_id.data());
session_data->file->Close();
}
}
@ -373,7 +373,7 @@ void Module::Interface::Write(Kernel::HLERequestContext& ctx) {
}
[[maybe_unused]] const u32 bytes_written = static_cast<u32>(
session_data->file->Write(0, buffer.size(), true, buffer.data()).Unwrap());
session_data->file->Write(0, buffer.size(), true, false, buffer.data()).Unwrap());
session_data->file->Close();
rb.Push(ResultSuccess);
@ -435,7 +435,7 @@ void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) {
msg_header.forward_count, msg_header.user_data);
[[maybe_unused]] const u32 bytes_written =
static_cast<u32>(message->Write(0, buffer_size, true, buffer.data()).Unwrap());
static_cast<u32>(message->Write(0, buffer_size, true, false, buffer.data()).Unwrap());
message->Close();
rb.Push(ResultSuccess);
@ -522,7 +522,7 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) {
std::memcpy(buffer.data() + hmac_offset, hmac_digest.data(), hmac_size);
[[maybe_unused]] const u32 bytes_written =
static_cast<u32>(message->Write(0, buffer_size, true, buffer.data()).Unwrap());
static_cast<u32>(message->Write(0, buffer_size, true, false, buffer.data()).Unwrap());
message->Close();
rb.Push(ResultSuccess);
@ -607,7 +607,7 @@ void Module::Interface::SetData(Kernel::HLERequestContext& ctx) {
cecd->CheckAndUpdateFile(CecDataPathType::OutboxIndex, ncch_program_id, buffer);
file->Write(0, buffer.size(), true, buffer.data());
file->Write(0, buffer.size(), true, false, buffer.data());
file->Close();
}
}
@ -764,8 +764,8 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) {
cecd->CheckAndUpdateFile(path_type, ncch_program_id, buffer);
}
[[maybe_unused]] const u32 bytes_written =
static_cast<u32>(file->Write(0, buffer.size(), true, buffer.data()).Unwrap());
[[maybe_unused]] const u32 bytes_written = static_cast<u32>(
file->Write(0, buffer.size(), true, false, buffer.data()).Unwrap());
file->Close();
rb.Push(ResultSuccess);
@ -1409,7 +1409,7 @@ Module::Module(Core::System& system) : system(system) {
cecd_system_save_data_archive = std::move(archive_result).Unwrap();
} else {
// Format the archive to create the directories
systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0);
systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0, 0, 0);
// Open it again to get a valid archive now that the folder exists
cecd_system_save_data_archive = systemsavedata_factory.Open(archive_path, 0).Unwrap();
@ -1442,7 +1442,7 @@ Module::Module(Core::System& system) : system(system) {
eventlog_buffer[1] = 0x41;
eventlog_buffer[2] = 0x12;
eventlog->Write(0, eventlog_size, true, eventlog_buffer.data());
eventlog->Write(0, eventlog_size, true, false, eventlog_buffer.data());
eventlog->Close();
/// MBoxList____ resides within the root CEC/ directory.
@ -1464,7 +1464,7 @@ Module::Module(Core::System& system) : system(system) {
// mboxlist_buffer[2-3] are already zeroed
mboxlist_buffer[4] = 0x01;
mboxlist->Write(0, mboxlist_size, true, mboxlist_buffer.data());
mboxlist->Write(0, mboxlist_size, true, false, mboxlist_buffer.data());
mboxlist->Close();
}
}

View file

@ -565,7 +565,7 @@ Result Module::UpdateConfigNANDSavegame() {
ASSERT_MSG(config_result.Succeeded(), "could not open file");
auto config = std::move(config_result).Unwrap();
config->Write(0, CONFIG_SAVEFILE_SIZE, 1, cfg_config_file_buffer.data());
config->Write(0, CONFIG_SAVEFILE_SIZE, true, false, cfg_config_file_buffer.data());
return ResultSuccess;
}
@ -625,7 +625,7 @@ Result Module::LoadConfigNANDSaveFile() {
// If the archive didn't exist, create the files inside
if (archive_result.Code() == FileSys::ResultNotFound) {
// Format the archive to create the directories
systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0);
systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0, 0, 0);
// Open it again to get a valid archive now that the folder exists
cfg_system_save_data_archive = systemsavedata_factory.Open(archive_path, 0).Unwrap();

View file

@ -67,10 +67,24 @@ ResultVal<ArchiveHandle> ArchiveManager::OpenArchive(ArchiveIdCode id_code,
}
Result ArchiveManager::CloseArchive(ArchiveHandle handle) {
if (handle_map.erase(handle) == 0)
auto itr = handle_map.find(handle);
if (itr != handle_map.end()) {
itr->second->Close();
} else {
return FileSys::ResultInvalidArchiveHandle;
else
return ResultSuccess;
}
handle_map.erase(itr);
return ResultSuccess;
}
Result ArchiveManager::ControlArchive(ArchiveHandle handle, u32 action, u8* input,
size_t input_size, u8* output, size_t output_size) {
auto itr = handle_map.find(handle);
if (itr != handle_map.end()) {
return itr->second->Control(action, input, input_size, output, output_size);
} else {
return FileSys::ResultInvalidArchiveHandle;
}
}
// TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in
@ -90,14 +104,14 @@ Result ArchiveManager::RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFacto
std::pair<ResultVal<std::shared_ptr<File>>, std::chrono::nanoseconds>
ArchiveManager::OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path,
const FileSys::Mode mode) {
const FileSys::Mode mode, u32 attributes) {
ArchiveBackend* archive = GetArchive(archive_handle);
if (archive == nullptr) {
return std::make_pair(FileSys::ResultInvalidArchiveHandle, std::chrono::nanoseconds{0});
}
const std::chrono::nanoseconds open_timeout_ns{archive->GetOpenDelayNs()};
auto backend = archive->OpenFile(path, mode);
auto backend = archive->OpenFile(path, mode, attributes);
if (backend.Failed()) {
return std::make_pair(backend.Code(), open_timeout_ns);
}
@ -151,21 +165,21 @@ Result ArchiveManager::DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archi
}
Result ArchiveManager::CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path,
u64 file_size) {
u64 file_size, u32 attributes) {
ArchiveBackend* archive = GetArchive(archive_handle);
if (archive == nullptr)
return FileSys::ResultInvalidArchiveHandle;
return archive->CreateFile(path, file_size);
return archive->CreateFile(path, file_size, attributes);
}
Result ArchiveManager::CreateDirectoryFromArchive(ArchiveHandle archive_handle,
const FileSys::Path& path) {
const FileSys::Path& path, u32 attributes) {
ArchiveBackend* archive = GetArchive(archive_handle);
if (archive == nullptr)
return FileSys::ResultInvalidArchiveHandle;
return archive->CreateDirectory(path);
return archive->CreateDirectory(path, attributes);
}
Result ArchiveManager::RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
@ -210,13 +224,15 @@ ResultVal<u64> ArchiveManager::GetFreeBytesInArchive(ArchiveHandle archive_handl
Result ArchiveManager::FormatArchive(ArchiveIdCode id_code,
const FileSys::ArchiveFormatInfo& format_info,
const FileSys::Path& path, u64 program_id) {
const FileSys::Path& path, u64 program_id,
u32 directory_buckets, u32 file_buckets) {
auto archive_itr = id_code_map.find(id_code);
if (archive_itr == id_code_map.end()) {
return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
}
return archive_itr->second->Format(path, format_info, program_id);
return archive_itr->second->Format(path, format_info, program_id, directory_buckets,
file_buckets);
}
ResultVal<FileSys::ArchiveFormatInfo> ArchiveManager::GetArchiveFormatInfo(
@ -229,10 +245,10 @@ ResultVal<FileSys::ArchiveFormatInfo> ArchiveManager::GetArchiveFormatInfo(
return archive->second->GetFormatInfo(archive_path, program_id);
}
Result ArchiveManager::CreateExtSaveData(MediaType media_type, u32 high, u32 low,
Result ArchiveManager::CreateExtSaveData(MediaType media_type, u8 unknown, u32 high, u32 low,
std::span<const u8> smdh_icon,
const FileSys::ArchiveFormatInfo& format_info,
u64 program_id) {
u64 program_id, u64 total_size) {
// Construct the binary path to the archive first
FileSys::Path path =
FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
@ -246,37 +262,26 @@ Result ArchiveManager::CreateExtSaveData(MediaType media_type, u32 high, u32 low
auto ext_savedata = static_cast<FileSys::ArchiveFactory_ExtSaveData*>(archive->second.get());
Result result = ext_savedata->Format(path, format_info, program_id);
Result result = ext_savedata->FormatAsExtData(path, format_info, unknown, program_id,
total_size, smdh_icon);
if (result.IsError()) {
return result;
}
ext_savedata->WriteIcon(path, smdh_icon);
return ResultSuccess;
}
Result ArchiveManager::DeleteExtSaveData(MediaType media_type, u32 high, u32 low) {
// Construct the binary path to the archive first
FileSys::Path path =
FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
Result ArchiveManager::DeleteExtSaveData(MediaType media_type, u8 unknown, u32 high, u32 low) {
auto archive = id_code_map.find(media_type == MediaType::NAND ? ArchiveIdCode::SharedExtSaveData
: ArchiveIdCode::ExtSaveData);
std::string media_type_directory;
if (media_type == MediaType::NAND) {
media_type_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir);
} else if (media_type == MediaType::SDMC) {
media_type_directory = FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir);
} else {
LOG_ERROR(Service_FS, "Unsupported media type {}", media_type);
return ResultUnknown; // TODO(Subv): Find the right error code
if (archive == id_code_map.end()) {
return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
}
// Delete all directories (/user, /boss) and the icon file.
std::string base_path =
FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND);
std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path);
if (FileUtil::Exists(extsavedata_path) && !FileUtil::DeleteDirRecursively(extsavedata_path))
return ResultUnknown; // TODO(Subv): Find the right error code
return ResultSuccess;
auto ext_savedata = static_cast<FileSys::ArchiveFactory_ExtSaveData*>(archive->second.get());
return ext_savedata->DeleteExtData(media_type, unknown, high, low);
}
Result ArchiveManager::DeleteSystemSaveData(u32 high, u32 low) {
@ -317,6 +322,24 @@ ResultVal<ArchiveResource> ArchiveManager::GetArchiveResource(MediaType media_ty
return resource;
}
Result ArchiveManager::SetSaveDataSecureValue(ArchiveHandle archive_handle, u32 secure_value_slot,
u64 secure_value, bool flush) {
ArchiveBackend* archive = GetArchive(archive_handle);
if (archive == nullptr) {
return FileSys::ResultInvalidArchiveHandle;
}
return archive->SetSaveDataSecureValue(secure_value_slot, secure_value, flush);
}
ResultVal<std::tuple<bool, bool, u64>> ArchiveManager::GetSaveDataSecureValue(
ArchiveHandle archive_handle, u32 secure_value_slot) {
ArchiveBackend* archive = GetArchive(archive_handle);
if (archive == nullptr) {
return FileSys::ResultInvalidArchiveHandle;
}
return archive->GetSaveDataSecureValue(secure_value_slot);
}
void ArchiveManager::RegisterArchiveTypes() {
// TODO(Subv): Add the other archive types (see here for the known types:
// http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes).
@ -337,7 +360,7 @@ void ArchiveManager::RegisterArchiveTypes() {
sdmc_directory);
// Create the SaveData archive
auto sd_savedata_source = std::make_shared<FileSys::ArchiveSource_SDSaveData>(sdmc_directory);
sd_savedata_source = std::make_shared<FileSys::ArchiveSource_SDSaveData>(sdmc_directory);
auto savedata_factory = std::make_unique<FileSys::ArchiveFactory_SaveData>(sd_savedata_source);
RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData);
auto other_savedata_permitted_factory =
@ -373,6 +396,23 @@ void ArchiveManager::RegisterArchiveTypes() {
RegisterArchiveType(std::move(selfncch_factory), ArchiveIdCode::SelfNCCH);
}
bool ArchiveManager::ArchiveIsSlow(ArchiveIdCode archive_id) {
auto itr = id_code_map.find(archive_id);
if (itr == id_code_map.end() || itr->second.get() == nullptr) {
return false;
}
return itr->second->IsSlow();
}
bool ArchiveManager::ArchiveIsSlow(ArchiveHandle archive_handle) {
ArchiveBackend* archive = GetArchive(archive_handle);
if (archive == nullptr) {
return false;
}
return archive->IsSlow();
}
void ArchiveManager::RegisterSelfNCCH(Loader::AppLoader& app_loader) {
auto itr = id_code_map.find(ArchiveIdCode::SelfNCCH);
if (itr == id_code_map.end()) {
@ -385,6 +425,35 @@ void ArchiveManager::RegisterSelfNCCH(Loader::AppLoader& app_loader) {
factory->Register(app_loader);
}
void ArchiveManager::RegisterArticSaveDataSource(
std::shared_ptr<Network::ArticBase::Client>& client) {
if (!sd_savedata_source.get()) {
LOG_ERROR(Service_FS, "Could not register artic save data source.");
return;
}
sd_savedata_source->RegisterArtic(client);
}
void ArchiveManager::RegisterArticExtData(std::shared_ptr<Network::ArticBase::Client>& client) {
for (auto it : {ArchiveIdCode::ExtSaveData, ArchiveIdCode::SharedExtSaveData,
ArchiveIdCode::BossExtSaveData}) {
auto itr = id_code_map.find(it);
if (itr == id_code_map.end() || itr->second.get() == nullptr) {
continue;
}
reinterpret_cast<FileSys::ArchiveFactory_ExtSaveData*>(itr->second.get())
->RegisterArtic(client);
}
}
void ArchiveManager::RegisterArticNCCH(std::shared_ptr<Network::ArticBase::Client>& client) {
auto itr = id_code_map.find(ArchiveIdCode::NCCH);
if (itr == id_code_map.end() || itr->second.get() == nullptr) {
return;
}
reinterpret_cast<FileSys::ArchiveFactory_NCCH*>(itr->second.get())->RegisterArtic(client);
}
ArchiveManager::ArchiveManager(Core::System& system) : system(system) {
RegisterArchiveTypes();
}

View file

@ -12,9 +12,11 @@
#include <boost/serialization/unordered_map.hpp>
#include "common/common_types.h"
#include "core/file_sys/archive_backend.h"
#include "core/file_sys/archive_source_sd_savedata.h"
#include "core/hle/result.h"
#include "core/hle/service/fs/directory.h"
#include "core/hle/service/fs/file.h"
#include "network/artic_base/artic_base_client.h"
/// The unique system identifier hash, also known as ID0
static constexpr char SYSTEM_ID[]{"00000000000000000000000000000000"};
@ -67,6 +69,19 @@ struct ArchiveResource {
};
static_assert(sizeof(ArchiveResource) == 0x10, "ArchiveResource has incorrect size");
struct ExtSaveDataInfo {
u8 media_type;
u8 unknown;
u16 reserved1;
u32 save_id_low;
u32 save_id_high;
u32 reserved2;
};
static_assert(sizeof(ExtSaveDataInfo) == 0x10, "ExtSaveDataInfo struct has incorrect size");
static_assert(std::is_trivial<ExtSaveDataInfo>(), "ExtSaveDataInfo should be trivial");
static_assert(std::is_trivially_copyable<ExtSaveDataInfo>(),
"ExtSaveDataInfo should be trivially copyable");
using FileSys::ArchiveBackend;
using FileSys::ArchiveFactory;
@ -90,6 +105,9 @@ public:
*/
Result CloseArchive(ArchiveHandle handle);
Result ControlArchive(ArchiveHandle handle, u32 action, u8* input, size_t input_size,
u8* output, size_t output_size);
/**
* Open a File from an Archive
* @param archive_handle Handle to an open Archive object
@ -98,7 +116,8 @@ public:
* @return Pair containing the opened File object and the open delay
*/
std::pair<ResultVal<std::shared_ptr<File>>, std::chrono::nanoseconds> OpenFileFromArchive(
ArchiveHandle archive_handle, const FileSys::Path& path, FileSys::Mode mode);
ArchiveHandle archive_handle, const FileSys::Path& path, FileSys::Mode mode,
u32 attributes);
/**
* Delete a File from an Archive
@ -146,7 +165,7 @@ public:
* @return File creation result code
*/
Result CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path,
u64 file_size);
u64 file_size, u32 attributes);
/**
* Create a Directory from an Archive
@ -154,7 +173,8 @@ public:
* @param path Path to the Directory inside of the Archive
* @return Whether creation of directory succeeded
*/
Result CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
Result CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path,
u32 attributes);
/**
* Rename a Directory between two Archives
@ -195,7 +215,8 @@ public:
* @return Result 0 on success or the corresponding code on error
*/
Result FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info,
const FileSys::Path& path, u64 program_id);
const FileSys::Path& path, u64 program_id, u32 directory_buckets,
u32 file_buckets);
/**
* Retrieves the format info about the archive of the specified type and path.
@ -219,8 +240,10 @@ public:
* @param program_id the program ID of the client that requests the operation
* @return Result 0 on success or the corresponding code on error
*/
Result CreateExtSaveData(MediaType media_type, u32 high, u32 low, std::span<const u8> smdh_icon,
const FileSys::ArchiveFormatInfo& format_info, u64 program_id);
Result CreateExtSaveData(MediaType media_type, u8 unknown, u32 high, u32 low,
std::span<const u8> smdh_icon,
const FileSys::ArchiveFormatInfo& format_info, u64 program_id,
u64 total_size);
/**
* Deletes the SharedExtSaveData archive for the specified extdata ID
@ -229,7 +252,7 @@ public:
* @param low The low word of the extdata id to delete
* @return Result 0 on success or the corresponding code on error
*/
Result DeleteExtSaveData(MediaType media_type, u32 high, u32 low);
Result DeleteExtSaveData(MediaType media_type, u8 unknown, u32 high, u32 low);
/**
* Deletes the SystemSaveData archive folder for the specified save data id
@ -254,9 +277,25 @@ public:
*/
ResultVal<ArchiveResource> GetArchiveResource(MediaType media_type) const;
Result SetSaveDataSecureValue(ArchiveHandle archive_handle, u32 secure_value_slot,
u64 secure_value, bool flush);
ResultVal<std::tuple<bool, bool, u64>> GetSaveDataSecureValue(ArchiveHandle archive_handle,
u32 secure_value_slot);
bool ArchiveIsSlow(ArchiveIdCode archive_id);
bool ArchiveIsSlow(ArchiveHandle archive_handle);
/// Registers a new NCCH file with the SelfNCCH archive factory
void RegisterSelfNCCH(Loader::AppLoader& app_loader);
void RegisterArticSaveDataSource(std::shared_ptr<Network::ArticBase::Client>& client);
void RegisterArticExtData(std::shared_ptr<Network::ArticBase::Client>& client);
void RegisterArticNCCH(std::shared_ptr<Network::ArticBase::Client>& client);
private:
Core::System& system;
@ -285,11 +324,17 @@ private:
std::unordered_map<ArchiveHandle, std::unique_ptr<ArchiveBackend>> handle_map;
ArchiveHandle next_handle = 1;
/**
* Savedata source
*/
std::shared_ptr<FileSys::ArchiveSource_SDSaveData> sd_savedata_source;
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& id_code_map;
ar& handle_map;
ar& next_handle;
ar& sd_savedata_source;
}
friend class boost::serialization::access;
};

View file

@ -169,10 +169,9 @@ void File::Write(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
u64 offset = rp.Pop<u64>();
u32 length = rp.Pop<u32>();
u32 flush = rp.Pop<u32>();
auto& buffer = rp.PopMappedBuffer();
LOG_TRACE(Service_FS, "Write {}: offset=0x{:x} length={}, flush=0x{:x}", GetName(), offset,
length, flush);
u32 flags = rp.Pop<u32>();
LOG_TRACE(Service_FS, "Write {}: offset=0x{:x} length={}, flags=0x{:x}", GetName(), offset,
length, flags);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
@ -182,25 +181,75 @@ void File::Write(Kernel::HLERequestContext& ctx) {
if (file->subfile) {
rb.Push(FileSys::ResultUnsupportedOpenFlags);
rb.Push<u32>(0);
rb.PushMappedBuffer(rp.PopMappedBuffer());
return;
}
bool flush = (flags & 0xFF) != 0, update_timestamp = (flags & 0xFF00) != 0;
if (!backend->AllowsCachedReads()) {
std::vector<u8> data(length);
auto& buffer = rp.PopMappedBuffer();
buffer.Read(data.data(), 0, data.size());
ResultVal<std::size_t> written =
backend->Write(offset, data.size(), flush, update_timestamp, data.data());
// Update file size
file->size = backend->GetSize();
if (written.Failed()) {
rb.Push(written.Code());
rb.Push<u32>(0);
} else {
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(*written));
}
rb.PushMappedBuffer(buffer);
return;
}
std::vector<u8> data(length);
buffer.Read(data.data(), 0, data.size());
ResultVal<std::size_t> written = backend->Write(offset, data.size(), flush != 0, data.data());
struct AsyncData {
// Input
u32 length;
u64 offset;
bool flush;
bool update_timestamp;
Kernel::MappedBuffer* buffer;
FileSessionSlot* file;
// Update file size
file->size = backend->GetSize();
// Output
ResultVal<std::size_t> written;
};
auto async_data = std::make_shared<AsyncData>();
async_data->length = length;
async_data->offset = offset;
async_data->flush = flush;
async_data->update_timestamp = update_timestamp;
async_data->buffer = &rp.PopMappedBuffer();
async_data->file = file;
if (written.Failed()) {
rb.Push(written.Code());
rb.Push<u32>(0);
} else {
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(*written));
}
rb.PushMappedBuffer(buffer);
ctx.RunAsync(
[this, async_data](Kernel::HLERequestContext& ctx) {
std::vector<u8> data(async_data->length);
async_data->buffer->Read(data.data(), 0, data.size());
async_data->written = backend->Write(async_data->offset, data.size(), async_data->flush,
async_data->update_timestamp, data.data());
// Update file size
async_data->file->size = backend->GetSize();
return 0;
},
[async_data](Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb(ctx, 2, 2);
if (async_data->written.Failed()) {
rb.Push(async_data->written.Code());
rb.Push<u32>(0);
} else {
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(*async_data->written));
}
rb.PushMappedBuffer(*async_data->buffer);
},
true);
}
void File::GetSize(Kernel::HLERequestContext& ctx) {
@ -219,17 +268,32 @@ void File::SetSize(Kernel::HLERequestContext& ctx) {
FileSessionSlot* file = GetSessionData(ctx.Session());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
// SetSize can not be called on subfiles.
if (file->subfile) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(FileSys::ResultUnsupportedOpenFlags);
return;
}
file->size = size;
backend->SetSize(size);
rb.Push(ResultSuccess);
if (!backend->AllowsCachedReads()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
file->size = size;
backend->SetSize(size);
rb.Push(ResultSuccess);
return;
}
ctx.RunAsync(
[file, size, this](Kernel::HLERequestContext& ctx) {
file->size = size;
backend->SetSize(size);
return 0;
},
[](Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb(ctx, 1, 0);
rb.Push(ResultSuccess);
},
true);
}
void File::Close(Kernel::HLERequestContext& ctx) {
@ -240,26 +304,53 @@ void File::Close(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "Closing File backend but {} clients still connected",
connected_sessions.size());
backend->Close();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(ResultSuccess);
if (!backend->AllowsCachedReads()) {
backend->Close();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(ResultSuccess);
return;
}
ctx.RunAsync(
[this](Kernel::HLERequestContext& ctx) {
backend->Close();
return 0;
},
[](Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb(ctx, 1, 0);
rb.Push(ResultSuccess);
},
true);
}
void File::Flush(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
const FileSessionSlot* file = GetSessionData(ctx.Session());
// Subfiles can not be flushed.
if (file->subfile) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(FileSys::ResultUnsupportedOpenFlags);
return;
}
backend->Flush();
rb.Push(ResultSuccess);
if (!backend->AllowsCachedReads()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
backend->Flush();
rb.Push(ResultSuccess);
}
ctx.RunAsync(
[this](Kernel::HLERequestContext& ctx) {
backend->Flush();
return 0;
},
[](Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb(ctx, 1, 0);
rb.Push(ResultSuccess);
},
true);
}
void File::SetPriority(Kernel::HLERequestContext& ctx) {

File diff suppressed because it is too large Load diff

View file

@ -9,6 +9,7 @@
#include <boost/serialization/base_object.hpp>
#include "common/common_types.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/secure_value_backend.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/service.h"
@ -77,6 +78,10 @@ public:
}
}
void RegisterSecureValueBackend(const std::shared_ptr<FileSys::SecureValueBackend>& backend) {
secure_value_backend = backend;
}
private:
void Initialize(Kernel::HLERequestContext& ctx);
@ -657,6 +662,21 @@ private:
*/
void ObsoletedGetSaveDataSecureValue(Kernel::HLERequestContext& ctx);
/**
* FS_User::ControlSecureSave service function
* Inputs:
* 1 : Action
* 2 : Input Size
* 3 : Output Size
* 4 : (Input Size << 4) | 0xA
* 5 : Input Pointer
* 6 : (Output Size << 4) | 0xC
* 7 : Output Pointer
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void ControlSecureSave(Kernel::HLERequestContext& ctx);
/**
* FS_User::SetThisSaveDataSecureValue service function.
* Inputs:
@ -722,11 +742,10 @@ private:
Core::System& system;
ArchiveManager& archives;
std::shared_ptr<FileSys::SecureValueBackend> secure_value_backend;
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
ar& priority;
}
void serialize(Archive& ar, const unsigned int);
friend class boost::serialization::access;
};

View file

@ -1969,7 +1969,7 @@ void HTTP_C::DecryptClCertA() {
FileSys::NCCHFileOpenType::NCCHData, 0, FileSys::NCCHFilePathType::RomFS, exefs_filepath);
FileSys::Mode open_mode = {};
open_mode.read_flag.Assign(1);
auto file_result = archive.OpenFile(file_path, open_mode);
auto file_result = archive.OpenFile(file_path, open_mode, 0);
if (file_result.Failed()) {
LOG_ERROR(Service_HTTP, "ClCertA file missing");
return;

View file

@ -151,7 +151,7 @@ void Module::Interface::ResetNotifications(Kernel::HLERequestContext& ctx) {
FileSys::Path archive_path(news_system_savedata_id);
// Format the SystemSaveData archive 0x00010035
systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0);
systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0, 0, 0);
news->news_system_save_data_archive = systemsavedata_factory.Open(archive_path, 0).Unwrap();
@ -655,7 +655,7 @@ Result Module::LoadNewsDBSavedata() {
// If the archive didn't exist, create the files inside
if (archive_result.Code() == FileSys::ResultNotFound) {
// Format the archive to create the directories
systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0);
systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0, 0, 0);
// Open it again to get a valid archive now that the folder exists
news_system_save_data_archive = systemsavedata_factory.Open(archive_path, 0).Unwrap();
@ -722,7 +722,7 @@ Result Module::SaveFileToSavedata(std::string filename, std::span<const u8> buff
ASSERT_MSG(result.Succeeded(), "could not open file");
auto file = std::move(result).Unwrap();
file->Write(0, buffer.size(), 1, buffer.data());
file->Write(0, buffer.size(), true, false, buffer.data());
file->Close();
return ResultSuccess;

View file

@ -158,7 +158,7 @@ static void WriteGameCoinData(GameCoin gamecoin_data) {
// If the archive didn't exist, create the files inside
if (archive_result.Code() == FileSys::ResultNotFormatted) {
// Format the archive to create the directories
extdata_archive_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0);
extdata_archive_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0, 0, 0);
// Open it again to get a valid archive now that the folder exists
archive = extdata_archive_factory.Open(archive_path, 0).Unwrap();
// Create the game coin file
@ -174,7 +174,8 @@ static void WriteGameCoinData(GameCoin gamecoin_data) {
auto gamecoin_result = archive->OpenFile(gamecoin_path, open_mode);
if (gamecoin_result.Succeeded()) {
auto gamecoin = std::move(gamecoin_result).Unwrap();
gamecoin->Write(0, sizeof(GameCoin), true, reinterpret_cast<const u8*>(&gamecoin_data));
gamecoin->Write(0, sizeof(GameCoin), true, false,
reinterpret_cast<const u8*>(&gamecoin_data));
gamecoin->Close();
}
}

View file

@ -19,6 +19,7 @@
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/result.h"
#include "core/hle/service/soc/soc_u.h"
#include "network/socket_manager.h"
#ifdef _WIN32
#include <winsock2.h>
@ -2221,17 +2222,12 @@ SOC_U::SOC_U() : ServiceFramework("soc:U", 18) {
RegisterHandlers(functions);
#ifdef _WIN32
WSADATA data;
WSAStartup(MAKEWORD(2, 2), &data);
#endif
Network::SocketManager::EnableSockets();
}
SOC_U::~SOC_U() {
CloseAndDeleteAllSockets();
#ifdef _WIN32
WSACleanup();
#endif
Network::SocketManager::DisableSockets();
}
std::optional<SOC_U::InterfaceInfo> SOC_U::GetDefaultInterfaceInfo() {