mirror of
https://github.com/PabloMK7/citra.git
synced 2025-11-30 12:28:47 +00:00
Add Artic Base support (#105)
* Add Artic Base support * Add Android support
This commit is contained in:
parent
572d3ab71c
commit
24c6ec5e6a
83 changed files with 5592 additions and 516 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue