diff --git a/common/defaults/system_settings.ini b/common/defaults/system_settings.ini
index 33d216373..ea59c681f 100644
--- a/common/defaults/system_settings.ini
+++ b/common/defaults/system_settings.ini
@@ -20,6 +20,12 @@
; for restoration on new game launch. 1 = always save toggles,
; 0 = only save toggles if toggle file exists.
; dmnt_always_save_cheat_toggles = u8!0x0
+; Enable writing to BIS partitions for HBL.
+; This is probably undesirable for normal usage.
+; enable_hbl_bis_write = u8!0x0
+; Enable reading the CAL0 partition for HBL.
+; This is probably undesirable for normal usage.
+; enable_hbl_cal_read = u8!0x0
; Controls whether fs.mitm should redirect save files
; to directories on the sd card.
; 0 = Do not redirect, 1 = Redirect.
diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp
new file mode 100644
index 000000000..b57b1da41
--- /dev/null
+++ b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include "fs_shim.h"
+#include "fs_mitm_service.hpp"
+#include "fsmitm_boot0storage.hpp"
+
+namespace ams::mitm::fs {
+
+ using namespace ams::fs;
+
+ namespace {
+
+ bool GetSettingsItemBooleanValue(const char *name, const char *key) {
+ u8 tmp = 0;
+ AMS_ASSERT(settings::fwdbg::GetSettingsItemValue(&tmp, sizeof(tmp), name, key) == sizeof(tmp));
+ return (tmp != 0);
+ }
+
+ }
+
+ Result FsMitmService::OpenBisStorage(sf::Out> out, u32 _bis_partition_id) {
+ const ::FsBisPartitionId bis_partition_id = static_cast<::FsBisPartitionId>(_bis_partition_id);
+
+ /* Try to open a storage for the partition. */
+ FsStorage bis_storage;
+ R_TRY(fsOpenBisStorageFwd(this->forward_service.get(), &bis_storage, bis_partition_id));
+ const sf::cmif::DomainObjectId target_object_id{bis_storage.s.object_id};
+
+ const bool is_sysmodule = ncm::IsSystemProgramId(this->client_info.program_id);
+ const bool is_hbl = this->client_info.override_status.IsHbl();
+ const bool can_write_bis = is_sysmodule || (is_hbl && GetSettingsItemBooleanValue("atmosphere", "enable_hbl_bis_write"));
+ const bool can_read_cal = is_sysmodule || (is_hbl && GetSettingsItemBooleanValue("atmosphere", "enable_hbl_cal_read"));
+
+ /* Allow HBL to write to boot1 (safe firm) + package2. */
+ /* This is needed to not break compatibility with ChoiDujourNX, which does not check for write access before beginning an update. */
+ /* TODO: get fixed so that this can be turned off without causing bricks :/ */
+ const bool is_package2 = (FsBisPartitionId_BootConfigAndPackage2Part1 <= bis_partition_id && bis_partition_id <= FsBisPartitionId_BootConfigAndPackage2Part6);
+ const bool is_boot1 = bis_partition_id == FsBisPartitionId_BootPartition2Root;
+ const bool can_write_bis_for_choi_support = is_hbl && (is_package2 || is_boot1);
+
+ /* Set output storage. */
+ if (bis_partition_id == FsBisPartitionId_BootPartition1Root) {
+ out.SetValue(std::make_shared(new Boot0Storage(bis_storage, this->client_info)), target_object_id);
+ } else if (bis_partition_id == FsBisPartitionId_CalibrationBinary) {
+ /* PRODINFO should *never* be writable. */
+ /* If we have permissions, create a read only storage. */
+ if (can_read_cal) {
+ out.SetValue(std::make_shared(new ReadOnlyStorageAdapter(new RemoteStorage(bis_storage))), target_object_id);
+ } else {
+ /* If we can't read cal, return permission denied. */
+ fsStorageClose(&bis_storage);
+ return fs::ResultPermissionDenied();
+ }
+ } else {
+ if (can_write_bis || can_write_bis_for_choi_support) {
+ /* We can write, so create a writable storage. */
+ out.SetValue(std::make_shared(new RemoteStorage(bis_storage)), target_object_id);
+ } else {
+ /* We can only read, so create a readable storage. */
+ out.SetValue(std::make_shared(new ReadOnlyStorageAdapter(new RemoteStorage(bis_storage))), target_object_id);
+ }
+ }
+
+ return ResultSuccess();
+ }
+
+}
diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.hpp b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.hpp
index 9e842200b..725152e34 100644
--- a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.hpp
+++ b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.hpp
@@ -16,26 +16,63 @@
#pragma once
#include
+#include "fsmitm_istorage_interface.hpp"
namespace ams::mitm::fs {
+ /* TODO: Consider re-enabling the mitm flag logic. */
+
class FsMitmService : public sf::IMitmServiceObject {
private:
enum class CommandId {
- /* TODO */
+ OpenFileSystemDeprecated = 0,
+
+ SetCurrentProcess = 1,
+ OpenFileSystemWithPatch = 7,
+ OpenFileSystemWithId = 8,
+
+ OpenSdCardFileSystem = 18,
+
+ OpenSaveDataFileSystem = 51,
+
+ OpenBisStorage = 12,
+ OpenDataStorageByCurrentProcess = 200,
+ OpenDataStorageByDataId = 202,
};
public:
static bool ShouldMitm(const sm::MitmProcessInfo &client_info) {
- /* TODO */
- return false;
+ static std::atomic_bool has_launched_qlaunch = false;
+
+ /* TODO: intercepting everything seems to cause issues with sleep mode, for some reason. */
+ /* Figure out why, and address it. */
+ /* TODO: This may be because pre-rewrite code really mismanaged domain objects in a way that would cause bad things. */
+ /* Need to verify if this is fixed now. */
+ if (client_info.program_id == ncm::ProgramId::AppletQlaunch || client_info.program_id == ncm::ProgramId::AppletMaintenanceMenu) {
+ has_launched_qlaunch = true;
+ }
+
+ return has_launched_qlaunch || client_info.program_id == ncm::ProgramId::Ns || !ncm::IsSystemProgramId(client_info.program_id);
}
public:
SF_MITM_SERVICE_OBJECT_CTOR(FsMitmService) { /* ... */ }
protected:
- /* TODO */
+ /* Overridden commands. */
+ /* Result OpenFileSystemWithPatch(Out> out, u64 program_id, u32 filesystem_type); */
+ /* Result OpenFileSystemWithId(Out> out, InPointer path, u64 program_id, u32 filesystem_type); */
+ /* Result OpenSdCardFileSystem(Out> out); */
+ /* Result OpenSaveDataFileSystem(Out> out, u8 space_id, FsSave save_struct); */
+ Result OpenBisStorage(sf::Out> out, u32 bis_partition_id);
+ /* Result OpenDataStorageByCurrentProcess(Out> out); */
+ /* Result OpenDataStorageByDataId(Out> out, u64 data_id, u8 storage_id); */
public:
DEFINE_SERVICE_DISPATCH_TABLE {
- /* TODO */
+ /* MAKE_SERVICE_COMMAND_META(OpenFileSystemWithPatch, hos::Version_200), */
+ /* MAKE_SERVICE_COMMAND_META(OpenFileSystemWithId, hos::Version_200), */
+ /* MAKE_SERVICE_COMMAND_META(OpenSdCardFileSystem), */
+ /* MAKE_SERVICE_COMMAND_META(OpenSaveDataFileSystem), */
+ MAKE_SERVICE_COMMAND_META(OpenBisStorage),
+ /* MAKE_SERVICE_COMMAND_META(OpenDataStorageByCurrentProcess), */
+ /* MAKE_SERVICE_COMMAND_META(OpenDataStorageByDataId), */
};
};
diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_shim.c b/stratosphere/ams_mitm/source/fs_mitm/fs_shim.c
new file mode 100644
index 000000000..5cae82712
--- /dev/null
+++ b/stratosphere/ams_mitm/source/fs_mitm/fs_shim.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include "fs_shim.h"
+
+/* Missing fsp-srv commands. */
+Result fsOpenBisStorageFwd(Service* s, FsStorage* out, FsBisPartitionId partition_id) {
+ const u32 tmp = partition_id;
+ return serviceDispatchIn(s, 12, tmp,
+ .out_num_objects = 1,
+ .out_objects = &out->s,
+ );
+}
diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_shim.h b/stratosphere/ams_mitm/source/fs_mitm/fs_shim.h
new file mode 100644
index 000000000..2756be20b
--- /dev/null
+++ b/stratosphere/ams_mitm/source/fs_mitm/fs_shim.h
@@ -0,0 +1,19 @@
+/**
+ * @file fs_shim.h
+ * @brief Filesystem Services (fs) IPC wrapper for fs.mitm.
+ * @author SciresM
+ * @copyright libnx Authors
+ */
+#pragma once
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Missing fsp-srv commands. */
+Result fsOpenBisStorageFwd(Service* s, FsStorage* out, FsBisPartitionId partition_id);
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file
diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_boot0storage.cpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_boot0storage.cpp
new file mode 100644
index 000000000..0b0dac800
--- /dev/null
+++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_boot0storage.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include "fsmitm_boot0storage.hpp"
+
+namespace ams::mitm::fs {
+
+ using namespace ams::fs;
+
+ namespace {
+
+ os::Mutex g_boot0_access_mutex;
+ u8 g_boot0_bct_buffer[Boot0Storage::BctEndOffset];
+
+ }
+
+ bool Boot0Storage::CanModifyBctPublicKey() {
+ if (exosphere::IsRcmBugPatched()) {
+ /* RCM bug patched. */
+ /* Only allow NS to update the BCT pubks. */
+ /* AutoRCM on a patched unit will cause a brick, so homebrew should NOT be allowed to write. */
+ return this->client_info.program_id == ncm::ProgramId::Ns;
+ } else {
+ /* RCM bug unpatched. */
+ /* Allow homebrew but not NS to update the BCT pubks. */
+ return this->client_info.override_status.IsHbl();
+ }
+ }
+
+ Result Boot0Storage::Read(s64 offset, void *_buffer, size_t size) {
+ std::scoped_lock lk{g_boot0_access_mutex};
+
+ /* Check if we have nothing to do. */
+ if (size == 0) {
+ return ResultSuccess();
+ }
+
+ return Base::Read(offset, _buffer, size);
+ }
+
+ Result Boot0Storage::Write(s64 offset, const void *_buffer, size_t size) {
+ std::scoped_lock lk{g_boot0_access_mutex};
+
+ const u8 *buffer = static_cast(_buffer);
+
+ /* Check if we have nothing to do. */
+ if (size == 0) {
+ return ResultSuccess();
+ }
+
+ /* Protect the EKS region from writes. */
+ if (offset <= EksStart) {
+ if (offset + size < EksStart) {
+ /* Fall through, no need to do anything here. */
+ } else {
+ if (offset + size > EksEnd) {
+ /* Perform portion of write falling past end of keyblobs. */
+ const s64 diff = EksEnd - offset;
+ R_TRY(Base::Write(EksEnd, buffer + diff, size - diff));
+ }
+ /* Adjust size to avoid writing end of data. */
+ size = EksStart - offset;
+ }
+ } else if (offset < EksEnd) {
+ if (offset + size <= EksEnd) {
+ /* Ignore writes falling strictly within the region. */
+ return ResultSuccess();
+ } else {
+ /* Only write past the end of the region. */
+ const s64 diff = EksEnd - offset;
+ buffer += diff;
+ size -= diff;
+ offset = EksEnd;
+ }
+ }
+
+ /* If we have nothing to write, succeed immediately. */
+ if (size == 0) {
+ return ResultSuccess();
+ }
+
+ /* We want to protect AutoRCM from NS on ipatched units. If we can modify bct pubks or we're not touching any of them, proceed. */
+ if (this->CanModifyBctPublicKey() || offset >= BctEndOffset || (util::AlignUp(offset, BctSize) >= BctEndOffset && (offset % BctSize) >= BctPubkEnd)) {
+ return Base::Write(offset, buffer, size);
+ }
+
+ /* Handle any data written past the end of the pubk region. */
+ if (offset + size > BctEndOffset) {
+ const u64 diff = BctEndOffset - offset;
+ R_TRY(Base::Write(BctEndOffset, buffer + diff, size - diff));
+ size = diff;
+ }
+
+ /* Read in the current BCT region. */
+ R_TRY(Base::Read(0, g_boot0_bct_buffer, BctEndOffset));
+
+ /* Update the bct buffer. */
+ for (u64 cur_offset = offset; cur_offset < BctEndOffset && cur_offset < offset + size; cur_offset++) {
+ const u64 cur_bct_relative_ofs = cur_offset % BctSize;
+ if (cur_bct_relative_ofs < BctPubkStart || BctPubkEnd <= cur_bct_relative_ofs) {
+ g_boot0_bct_buffer[cur_offset] = buffer[cur_offset - offset];
+ }
+ }
+
+ return Base::Write(0, g_boot0_bct_buffer, BctEndOffset);
+ }
+
+}
diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_boot0storage.hpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_boot0storage.hpp
new file mode 100644
index 000000000..f2f241c0b
--- /dev/null
+++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_boot0storage.hpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include
+
+namespace ams::mitm::fs {
+
+ template
+ class SectoredStorageAdapter : public Base {
+ static_assert(std::is_base_of::value);
+ private:
+ u8 sector_buf[SectorSize];
+ public:
+ /* Inherit constructors. */
+ using Base::Base;
+ public:
+ virtual Result Read(s64 offset, void *_buffer, size_t size) override {
+ u8 *buffer = static_cast(_buffer);
+
+ const s64 seek = util::AlignDown(offset, SectorSize);
+ const s64 sector_ofs = offset - seek;
+
+ /* Check if we have nothing to do. */
+ if (size == 0) {
+ return ResultSuccess();
+ }
+
+ /* Fast case. */
+ if (sector_ofs == 0 && util::IsAligned(size, SectorSize)) {
+ return Base::Read(offset, buffer, size);
+ }
+
+ R_TRY(Base::Read(seek, this->sector_buf, SectorSize));
+
+ if (size + sector_ofs <= SectorSize) {
+ /* Staying within the sector. */
+ std::memcpy(buffer, this->sector_buf + sector_ofs, size);
+ } else {
+ /* Leaving the sector. */
+ const size_t size_in_sector = SectorSize - sector_ofs;
+ std::memcpy(buffer, this->sector_buf + sector_ofs, size_in_sector);
+ size -= size_in_sector;
+
+ /* Read as many guaranteed aligned sectors as we can. */
+ const size_t aligned_remaining_size = util::AlignDown(size, SectorSize);
+ if (aligned_remaining_size) {
+ R_TRY(Base::Read(offset + size_in_sector, buffer + size_in_sector, aligned_remaining_size));
+ size -= aligned_remaining_size;
+ }
+
+ /* Read any leftover data. */
+ if (size) {
+ R_TRY(Base::Read(offset + size_in_sector + aligned_remaining_size, this->sector_buf, SectorSize));
+ std::memcpy(buffer + size_in_sector + aligned_remaining_size, this->sector_buf, size);
+ }
+ }
+
+ return ResultSuccess();
+ }
+
+ virtual Result Write(s64 offset, const void *_buffer, size_t size) override {
+ const u8 *buffer = static_cast(_buffer);
+
+ const s64 seek = util::AlignDown(offset, SectorSize);
+ const s64 sector_ofs = offset - seek;
+
+ /* Check if we have nothing to do. */
+ if (size == 0) {
+ return ResultSuccess();
+ }
+
+ /* Fast case. */
+ if (sector_ofs == 0 && util::IsAligned(size, SectorSize)) {
+ return Base::Write(offset, buffer, size);
+ }
+
+ /* Load existing sector data. */
+ R_TRY(Base::Read(seek, this->sector_buf, SectorSize));
+
+ if (size + sector_ofs <= SectorSize) {
+ /* Staying within the sector. */
+ std::memcpy(this->sector_buf + sector_ofs, buffer, size);
+ R_TRY(Base::Write(seek, this->sector_buf, SectorSize));
+ } else {
+ /* Leaving the sector. */
+ const size_t size_in_sector = SectorSize - sector_ofs;
+ std::memcpy(this->sector_buf + sector_ofs, buffer, size_in_sector);
+ R_TRY(Base::Write(seek, this->sector_buf, SectorSize));
+ size -= size_in_sector;
+
+ /* Write as many guaranteed aligned sectors as we can. */
+ const size_t aligned_remaining_size = util::AlignDown(size, SectorSize);
+ if (aligned_remaining_size) {
+ R_TRY(Base::Write(offset + size_in_sector, buffer + size_in_sector, aligned_remaining_size));
+ size -= aligned_remaining_size;
+ }
+
+ /* Write any leftover data. */
+ if (size) {
+ R_TRY(Base::Read(offset + size_in_sector + aligned_remaining_size, this->sector_buf, SectorSize));
+ std::memcpy(this->sector_buf, buffer + size_in_sector + aligned_remaining_size, size);
+ R_TRY(Base::Write(offset + size_in_sector + aligned_remaining_size, this->sector_buf, SectorSize));
+ }
+ }
+
+ return ResultSuccess();
+ }
+ };
+
+ /* Represents an RCM-preserving BOOT0 partition. */
+ class Boot0Storage : public SectoredStorageAdapter {
+ public:
+ using Base = SectoredStorageAdapter;
+
+ static constexpr s64 BctEndOffset = 0xFC000;
+ static constexpr s64 BctSize = static_cast(ams::updater::BctSize);
+ static constexpr s64 BctPubkStart = 0x210;
+ static constexpr s64 BctPubkSize = 0x100;
+ static constexpr s64 BctPubkEnd = BctPubkStart + BctPubkSize;
+
+ static constexpr s64 EksStart = 0x180000;
+ static constexpr s64 EksSize = static_cast(ams::updater::EksSize);
+ static constexpr s64 EksEnd = EksStart + EksSize;
+ private:
+ sm::MitmProcessInfo client_info;
+ private:
+ bool CanModifyBctPublicKey();
+ public:
+ Boot0Storage(FsStorage *s, const sm::MitmProcessInfo &c) : Base(s), client_info(c) { /* ... */ }
+ Boot0Storage(FsStorage s, const sm::MitmProcessInfo &c) : Base(s), client_info(c) { /* ... */ }
+ public:
+ virtual Result Read(s64 offset, void *_buffer, size_t size) override;
+ virtual Result Write(s64 offset, const void *_buffer, size_t size) override;
+ };
+
+}
diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_istorage_interface.cpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_istorage_interface.cpp
new file mode 100644
index 000000000..2effb8295
--- /dev/null
+++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_istorage_interface.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include "fsmitm_istorage_interface.hpp"
+
+namespace ams::mitm::fs {
+
+ using namespace ams::fs;
+
+ Result IStorageInterface::Read(s64 offset, const sf::OutNonSecureBuffer &buffer, s64 size) {
+ /* TODO: N retries on ResultDataCorrupted, we may want to eventually. */
+ R_UNLESS(offset >= 0, fs::ResultInvalidOffset());
+ R_UNLESS(size >= 0, fs::ResultInvalidSize());
+ return this->base_storage->Read(offset, buffer.GetPointer(), size);
+ }
+
+ Result IStorageInterface::Write(s64 offset, const sf::InNonSecureBuffer &buffer, s64 size) {
+ /* TODO: N increases thread priority temporarily when writing. We may want to eventually. */
+ R_UNLESS(offset >= 0, fs::ResultInvalidOffset());
+ R_UNLESS(size >= 0, fs::ResultInvalidSize());
+ return this->base_storage->Write(offset, buffer.GetPointer(), size);
+ }
+
+ Result IStorageInterface::Flush() {
+ return this->base_storage->Flush();
+ }
+
+ Result IStorageInterface::SetSize(s64 size) {
+ R_UNLESS(size >= 0, fs::ResultInvalidSize());
+ return this->base_storage->SetSize(size);
+ }
+
+ Result IStorageInterface::GetSize(sf::Out out) {
+ return this->base_storage->GetSize(out.GetPointer());
+ }
+
+ Result IStorageInterface::OperateRange(sf::Out out, s32 op_id, s64 offset, s64 size) {
+ /* N includes this redundant check, so we will too. */
+ R_UNLESS(out.GetPointer() != nullptr, fs::ResultNullptrArgument());
+
+ out->Clear();
+ if (op_id == static_cast(fs::OperationId::QueryRange)) {
+ fs::StorageQueryRangeInfo info;
+ R_TRY(this->base_storage->OperateRange(&info, sizeof(info), fs::OperationId::QueryRange, offset, size, nullptr, 0));
+ out->Merge(info);
+ }
+
+ return ResultSuccess();
+ }
+
+}
diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_istorage_interface.hpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_istorage_interface.hpp
new file mode 100644
index 000000000..3c98f1bbf
--- /dev/null
+++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_istorage_interface.hpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+
+namespace ams::mitm::fs {
+
+ class IStorageInterface : public sf::IServiceObject {
+ private:
+ enum class CommandId {
+ Read = 0,
+ Write = 1,
+ Flush = 2,
+ SetSize = 3,
+ GetSize = 4,
+ OperateRange = 5,
+ };
+ private:
+ std::unique_ptr base_storage;
+ public:
+ IStorageInterface(ams::fs::IStorage *s) : base_storage(s) { /* ... */ }
+ IStorageInterface(std::unique_ptr s) : base_storage(std::move(s)) { /* ... */ }
+ private:
+ /* Command API. */
+ virtual Result Read(s64 offset, const sf::OutNonSecureBuffer &buffer, s64 size) final;
+ virtual Result Write(s64 offset, const sf::InNonSecureBuffer &buffer, s64 size) final;
+ virtual Result Flush() final;
+ virtual Result SetSize(s64 size) final;
+ virtual Result GetSize(sf::Out out) final;
+ virtual Result OperateRange(sf::Out out, s32 op_id, s64 offset, s64 size) final;
+ public:
+ DEFINE_SERVICE_DISPATCH_TABLE {
+ /* 1.0.0- */
+ MAKE_SERVICE_COMMAND_META(Read),
+ MAKE_SERVICE_COMMAND_META(Write),
+ MAKE_SERVICE_COMMAND_META(Flush),
+ MAKE_SERVICE_COMMAND_META(SetSize),
+ MAKE_SERVICE_COMMAND_META(GetSize),
+
+ /* 4.0.0- */
+ MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_400),
+ };
+ };
+
+}
diff --git a/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp b/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp
index 783315b17..f28fc576c 100644
--- a/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp
+++ b/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp
@@ -322,6 +322,14 @@ namespace ams::settings::fwdbg {
/* Set to "normal" for normal reboot, "rcm" for rcm reboot. */
R_ASSERT(ParseSettingsItemValue("atmosphere", "power_menu_reboot_function", "str!payload"));
+ /* Enable writing to BIS partitions for HBL. */
+ /* This is probably undesirable for normal usage. */
+ R_ASSERT(ParseSettingsItemValue("atmosphere", "enable_hbl_bis_write", "u8!0x0"));
+
+ /* Enable HBL to read the CAL0 partition. */
+ /* This is probably undesirable for normal usage. */
+ R_ASSERT(ParseSettingsItemValue("atmosphere", "enable_hbl_cal_read", "u8!0x0"));
+
/* Controls whether dmnt cheats should be toggled on or off by */
/* default. 1 = toggled on by default, 0 = toggled off by default. */
R_ASSERT(ParseSettingsItemValue("atmosphere", "dmnt_cheats_enabled_by_default", "u8!0x1"));
diff --git a/stratosphere/libstratosphere/include/stratosphere.hpp b/stratosphere/libstratosphere/include/stratosphere.hpp
index 0a1363660..19ba7185c 100644
--- a/stratosphere/libstratosphere/include/stratosphere.hpp
+++ b/stratosphere/libstratosphere/include/stratosphere.hpp
@@ -48,3 +48,6 @@
#include "stratosphere/sm.hpp"
#include "stratosphere/spl.hpp"
#include "stratosphere/updater.hpp"
+
+/* Include FS last. */
+#include "stratosphere/fs.hpp"
diff --git a/stratosphere/libstratosphere/include/stratosphere/fs.hpp b/stratosphere/libstratosphere/include/stratosphere/fs.hpp
new file mode 100644
index 000000000..d1347e3a5
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/fs.hpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include "fs/fs_common.hpp"
+#include "fs/fsa/fs_ifile.hpp"
+#include "fs/fsa/fs_idirectory.hpp"
+#include "fs/fsa/fs_ifilesystem.hpp"
+#include "fs/fs_remote_filesystem.hpp"
+#include "fs/fs_istorage.hpp"
+#include "fs/fs_remote_storage.hpp"
+#include "fs/fs_query_range.hpp"
diff --git a/stratosphere/libstratosphere/include/stratosphere/fs/fs_common.hpp b/stratosphere/libstratosphere/include/stratosphere/fs/fs_common.hpp
new file mode 100644
index 000000000..cbeaeeded
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/fs/fs_common.hpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+#include "../os.hpp"
+#include "../ncm.hpp"
+#include "../sf.hpp"
diff --git a/stratosphere/libstratosphere/include/stratosphere/fs/fs_directory.hpp b/stratosphere/libstratosphere/include/stratosphere/fs/fs_directory.hpp
new file mode 100644
index 000000000..01c8eb2d5
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/fs/fs_directory.hpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include "fs_common.hpp"
+
+namespace ams::fs {
+
+ using DirectoryEntry = ::FsDirectoryEntry;
+
+}
diff --git a/stratosphere/libstratosphere/include/stratosphere/fs/fs_file.hpp b/stratosphere/libstratosphere/include/stratosphere/fs/fs_file.hpp
new file mode 100644
index 000000000..f7872f512
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/fs/fs_file.hpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include "fs_common.hpp"
+
+namespace ams::fs {
+
+ struct ReadOption {
+ u32 value;
+
+ static const ReadOption None;
+ };
+
+ inline constexpr const ReadOption ReadOption::None = {FsReadOption_None};
+
+ inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) {
+ return lhs.value == rhs.value;
+ }
+
+ inline constexpr bool operator!=(const ReadOption &lhs, const ReadOption &rhs) {
+ return !(lhs == rhs);
+ }
+
+ static_assert(std::is_pod::value && sizeof(ReadOption) == sizeof(u32));
+
+ struct WriteOption {
+ u32 value;
+
+ constexpr inline bool HasFlushFlag() const {
+ return this->value & FsWriteOption_Flush;
+ }
+
+ static const WriteOption None;
+ static const WriteOption Flush;
+ };
+
+ inline constexpr const WriteOption WriteOption::None = {FsWriteOption_None};
+ inline constexpr const WriteOption WriteOption::Flush = {FsWriteOption_Flush};
+
+ inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) {
+ return lhs.value == rhs.value;
+ }
+
+ inline constexpr bool operator!=(const WriteOption &lhs, const WriteOption &rhs) {
+ return !(lhs == rhs);
+ }
+
+ static_assert(std::is_pod::value && sizeof(WriteOption) == sizeof(u32));
+
+}
diff --git a/stratosphere/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp b/stratosphere/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp
new file mode 100644
index 000000000..86581f3d3
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include "fs_common.hpp"
+
+namespace ams::fs {
+
+ enum OpenMode {
+ OpenMode_Read = ::FsOpenMode_Read,
+ OpenMode_Write = ::FsOpenMode_Write,
+ OpenMode_Append = ::FsOpenMode_Append,
+
+ OpenMode_ReadWrite = (OpenMode_Read | OpenMode_Write),
+ OpenMode_All = (OpenMode_ReadWrite | OpenMode_Append),
+ };
+
+ enum OpenDirectoryMode {
+ OpenDirectoryMode_Directory = ::FsDirOpenMode_ReadDirs,
+ OpenDirectoryMode_File = ::FsDirOpenMode_ReadFiles,
+
+ OpenDirectoryMode_All = (OpenDirectoryMode_Directory | OpenDirectoryMode_File),
+
+ /* TODO: Separate enum, like N? */
+ OpenDirectoryMode_NotRequireFileSize = ::FsDirOpenMode_NoFileSize,
+ };
+
+ enum DirectoryEntryType {
+ DirectoryEntryType_Directory = ::FsDirEntryType_Dir,
+ DirectoryEntryType_File = ::FsDirEntryType_File,
+ };
+
+ enum CreateOption {
+ CreateOption_BigFile = ::FsCreateOption_BigFile,
+ };
+
+ using FileTimeStampRaw = ::FsTimeStampRaw;
+
+}
diff --git a/stratosphere/libstratosphere/include/stratosphere/fs/fs_istorage.hpp b/stratosphere/libstratosphere/include/stratosphere/fs/fs_istorage.hpp
new file mode 100644
index 000000000..8a462582f
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/fs/fs_istorage.hpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include "fs_common.hpp"
+#include "fs_file.hpp"
+#include "fs_operate_range.hpp"
+
+namespace ams::fs {
+
+ class IStorage {
+ public:
+ virtual ~IStorage() { /* ... */ }
+
+ virtual Result Read(s64 offset, void *buffer, size_t size) = 0;
+
+ virtual Result Write(s64 offset, const void *buffer, size_t size) {
+ return fs::ResultUnsupportedOperation();
+ }
+
+ virtual Result Flush() = 0;
+
+ virtual Result SetSize(s64 size) {
+ return fs::ResultUnsupportedOperation();
+ }
+
+ virtual Result GetSize(s64 *out) = 0;
+
+ virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
+ return fs::ResultUnsupportedOperation();
+ }
+
+ virtual Result OperateRange(OperationId op_id, s64 offset, s64 size) {
+ return this->OperateRange(nullptr, 0, op_id, offset, size, nullptr, 0);
+ }
+ public:
+ static inline bool IsRangeValid(s64 offset, s64 size, s64 total_size) {
+ return offset >= 0 &&
+ size >= 0 &&
+ size <= total_size &&
+ offset <= (total_size - size);
+ }
+
+ static inline bool IsRangeValid(s64 offset, size_t size, s64 total_size) {
+ return IsRangeValid(offset, static_cast(size), total_size);
+ }
+
+ static inline bool IsOffsetAndSizeValid(s64 offset, s64 size) {
+ return offset >= 0 &&
+ size >= 0 &&
+ offset <= (offset + size);
+ }
+
+ static inline bool IsOffsetAndSizeValid(s64 offset, size_t size) {
+ return IsOffsetAndSizeValid(offset, static_cast(size));
+ }
+ };
+
+ class ReadOnlyStorageAdapter : public IStorage {
+ private:
+ std::shared_ptr shared_storage;
+ std::unique_ptr unique_storage;
+ IStorage *storage;
+ public:
+ ReadOnlyStorageAdapter(IStorage *s) : unique_storage(s) {
+ this->storage = this->unique_storage.get();
+ }
+ ReadOnlyStorageAdapter(std::shared_ptr s) : shared_storage(s) {
+ this->storage = this->shared_storage.get();
+ }
+ ReadOnlyStorageAdapter(std::unique_ptr s) : unique_storage(std::move(s)) {
+ this->storage = this->unique_storage.get();
+ }
+
+ virtual ~ReadOnlyStorageAdapter() { /* ... */ }
+ public:
+ virtual Result Read(s64 offset, void *buffer, size_t size) {
+ return this->storage->Read(offset, buffer, size);
+ }
+
+ virtual Result Flush() {
+ return this->storage->Flush();
+ }
+
+ virtual Result GetSize(s64 *out) {
+ return this->storage->GetSize(out);
+ }
+
+ virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
+ return this->storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size);
+ }
+ };
+
+}
diff --git a/stratosphere/libstratosphere/include/stratosphere/fs/fs_operate_range.hpp b/stratosphere/libstratosphere/include/stratosphere/fs/fs_operate_range.hpp
new file mode 100644
index 000000000..3896da2e2
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/fs/fs_operate_range.hpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include "fs_common.hpp"
+
+namespace ams::fs {
+
+ enum class OperationId : u64 {
+ Clear = ::FsOperationId_Clear,
+ ClearSignature = ::FsOperationId_ClearSignature,
+ InvalidateCache = ::FsOperationId_InvalidateCache,
+ QueryRange = ::FsOperationId_QueryRange,
+ };
+
+}
diff --git a/stratosphere/libstratosphere/include/stratosphere/fs/fs_query_range.hpp b/stratosphere/libstratosphere/include/stratosphere/fs/fs_query_range.hpp
new file mode 100644
index 000000000..9bab0e67d
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/fs/fs_query_range.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include "fs_common.hpp"
+
+namespace ams::fs {
+
+ struct QueryRangeInfo {
+ u32 aes_ctr_key_type;
+ u32 speed_emulation_type;
+ u32 reserved[0x38 / sizeof(u32)];
+
+ void Clear() {
+ this->aes_ctr_key_type = 0;
+ this->speed_emulation_type = 0;
+ std::memset(this->reserved, 0, sizeof(this->reserved));
+ }
+
+ void Merge(const QueryRangeInfo &rhs) {
+ this->aes_ctr_key_type |= rhs.aes_ctr_key_type;
+ this->speed_emulation_type |= rhs.speed_emulation_type;
+ }
+ };
+
+ static_assert(std::is_pod::value);
+ static_assert(sizeof(QueryRangeInfo) == 0x40);
+ static_assert(sizeof(QueryRangeInfo) == sizeof(::FsRangeInfo));
+
+ using FileQueryRangeInfo = QueryRangeInfo;
+ using StorageQueryRangeInfo = QueryRangeInfo;
+
+}
diff --git a/stratosphere/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp b/stratosphere/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp
new file mode 100644
index 000000000..8aaee50f9
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include "fs_common.hpp"
+#include "fsa/fs_ifile.hpp"
+#include "fsa/fs_idirectory.hpp"
+#include "fsa/fs_ifilesystem.hpp"
+
+namespace ams::fs {
+
+ class RemoteFile : public fsa::IFile {
+ private:
+ std::unique_ptr<::FsFile> base_file;
+ public:
+ RemoteFile(::FsFile *f) : base_file(f) { /* ... */ }
+ RemoteFile(std::unique_ptr<::FsFile> f) : base_file(std::move(f)) { /* ... */ }
+ RemoteFile(::FsFile f) {
+ this->base_file = std::make_unique<::FsFile>(f);
+ }
+
+ virtual ~RemoteFile() { fsFileClose(this->base_file.get()); }
+ public:
+ virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const ReadOption &option) override final {
+ return fsFileRead(this->base_file.get(), offset, buffer, size, option.value, out);
+ }
+
+ virtual Result GetSizeImpl(s64 *out) override final {
+ return fsFileGetSize(this->base_file.get(), reinterpret_cast(out));
+ }
+
+ virtual Result FlushImpl() override final {
+ return fsFileFlush(this->base_file.get());
+ }
+
+ virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const WriteOption &option) override final {
+ return fsFileWrite(this->base_file.get(), offset, buffer, size, option.value);
+ }
+
+ virtual Result SetSizeImpl(s64 size) override final {
+ return fsFileSetSize(this->base_file.get(), size);
+ }
+
+ virtual Result OperateRangeImpl(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final {
+ /* TODO: How should this be handled? */
+ return fs::ResultNotImplemented();
+ }
+ };
+
+ class RemoteDirectory : public fsa::IDirectory {
+ private:
+ std::unique_ptr<::FsDir> base_dir;
+ public:
+ RemoteDirectory(::FsDir *d) : base_dir(d) { /* ... */ }
+ RemoteDirectory(std::unique_ptr<::FsDir> d) : base_dir(std::move(d)) { /* ... */ }
+ RemoteDirectory(::FsDir d) {
+ this->base_dir = std::make_unique<::FsDir>(d);
+ }
+
+ virtual ~RemoteDirectory() { fsDirClose(this->base_dir.get()); }
+ public:
+ virtual Result ReadImpl(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override final {
+ return fsDirRead(this->base_dir.get(), 0, reinterpret_cast(out_count), max_entries, out_entries);
+ }
+
+ virtual Result GetEntryCountImpl(s64 *out) override final {
+ return fsDirGetEntryCount(this->base_dir.get(), reinterpret_cast(out));
+ }
+ };
+
+ class RemoteFileSystem : public fsa::IFileSystem {
+ private:
+ std::unique_ptr<::FsFileSystem> base_fs;
+ public:
+ RemoteFileSystem(::FsFileSystem *fs) : base_fs(fs) { /* ... */ }
+ RemoteFileSystem(std::unique_ptr<::FsFileSystem> fs) : base_fs(std::move(fs)) { /* ... */ }
+ RemoteFileSystem(::FsFileSystem fs) {
+ this->base_fs = std::make_unique<::FsFileSystem>(fs);
+ }
+
+ virtual ~RemoteFileSystem() { fsFsClose(this->base_fs.get()); }
+ public:
+ virtual Result CreateFileImpl(const char *path, s64 size, int flags) override final {
+ return fsFsCreateFile(this->base_fs.get(), path, size, flags);
+ }
+
+ virtual Result DeleteFileImpl(const char *path) override final {
+ return fsFsDeleteFile(this->base_fs.get(), path);
+ }
+
+ virtual Result CreateDirectoryImpl(const char *path) override final {
+ return fsFsCreateDirectory(this->base_fs.get(), path);
+ }
+
+ virtual Result DeleteDirectoryImpl(const char *path) override final {
+ return fsFsDeleteDirectory(this->base_fs.get(), path);
+ }
+
+ virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override final {
+ return fsFsDeleteDirectoryRecursively(this->base_fs.get(), path);
+ }
+
+ virtual Result RenameFileImpl(const char *old_path, const char *new_path) override final {
+ return fsFsRenameFile(this->base_fs.get(), old_path, new_path);
+ }
+
+ virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override final {
+ return fsFsRenameDirectory(this->base_fs.get(), old_path, new_path);
+ }
+
+ virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const char *path) override final {
+ static_assert(sizeof(::FsDirEntryType) == sizeof(DirectoryEntryType));
+ return fsFsGetEntryType(this->base_fs.get(), path, reinterpret_cast<::FsDirEntryType *>(out));
+ }
+
+ virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, OpenMode mode) override final {
+ FsFile f;
+ R_TRY(fsFsOpenFile(this->base_fs.get(), path, mode, &f));
+
+ *out_file = std::make_unique(f);
+ return ResultSuccess();
+ }
+
+ virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) override final {
+ FsDir d;
+ R_TRY(fsFsOpenDirectory(this->base_fs.get(), path, mode, &d));
+
+ *out_dir = std::make_unique(d);
+ return ResultSuccess();
+ }
+
+ virtual Result CommitImpl() override final {
+ return fsFsCommit(this->base_fs.get());
+ }
+
+
+ virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) {
+ return fsFsGetFreeSpace(this->base_fs.get(), path, reinterpret_cast(out));
+ }
+
+ virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) {
+ return fsFsGetTotalSpace(this->base_fs.get(), path, reinterpret_cast(out));
+ }
+
+ virtual Result CleanDirectoryRecursivelyImpl(const char *path) {
+ return fsFsCleanDirectoryRecursively(this->base_fs.get(), path);
+ }
+
+ virtual Result GetFileTimeStampRawImpl(FileTimeStampRaw *out, const char *path) {
+ static_assert(sizeof(FileTimeStampRaw) == sizeof(::FsTimeStampRaw));
+ return fsFsGetFileTimeStampRaw(this->base_fs.get(), path, reinterpret_cast<::FsTimeStampRaw *>(out));
+ }
+
+ virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryType query, const char *path) {
+ return fsFsQueryEntry(this->base_fs.get(), dst, dst_size, src, src_size, path, static_cast(query));
+ }
+ };
+
+}
diff --git a/stratosphere/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp b/stratosphere/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp
new file mode 100644
index 000000000..07b08c947
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include "fs_common.hpp"
+#include "fs_istorage.hpp"
+
+namespace ams::fs {
+
+ class RemoteStorage : public IStorage {
+ private:
+ std::unique_ptr<::FsStorage> base_storage;
+ public:
+ RemoteStorage(::FsStorage *s) : base_storage(s) { /* ... */ }
+ RemoteStorage(std::unique_ptr<::FsStorage> s) : base_storage(std::move(s)) { /* ... */ }
+ RemoteStorage(::FsStorage s) {
+ this->base_storage = std::make_unique<::FsStorage>(s);
+ }
+
+ virtual ~RemoteStorage() { fsStorageClose(this->base_storage.get()); }
+ public:
+ virtual Result Read(s64 offset, void *buffer, size_t size) override {
+ return fsStorageRead(this->base_storage.get(), offset, buffer, size);
+ };
+
+ virtual Result Write(s64 offset, const void *buffer, size_t size) override {
+ return fsStorageWrite(this->base_storage.get(), offset, buffer, size);
+ };
+
+ virtual Result Flush() override {
+ return fsStorageFlush(this->base_storage.get());
+ };
+
+ virtual Result GetSize(s64 *out_size) override {
+ return fsStorageGetSize(this->base_storage.get(), reinterpret_cast(out_size));
+ };
+
+ virtual Result SetSize(s64 size) override {
+ return fsStorageSetSize(this->base_storage.get(), size);
+ };
+
+ virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
+ /* TODO: How to deal with this? */
+ return fs::ResultUnsupportedOperation();
+ };
+ };
+
+}
diff --git a/stratosphere/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp b/stratosphere/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp
new file mode 100644
index 000000000..ab3e06b48
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include "../fs_common.hpp"
+#include "../fs_directory.hpp"
+
+namespace ams::fs::fsa {
+
+ class IDirectory {
+ public:
+ virtual ~IDirectory() { /* ... */ }
+
+ Result Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) {
+ R_UNLESS(out_count != nullptr, fs::ResultNullptrArgument());
+ if (max_entries == 0) {
+ *out_count = 0;
+ return ResultSuccess();
+ }
+ R_UNLESS(out_entries != nullptr, fs::ResultNullptrArgument());
+ R_UNLESS(max_entries > 0, fs::ResultInvalidArgument());
+ return this->ReadImpl(out_count, out_entries, max_entries);
+ }
+
+ Result GetEntryCount(s64 *out) {
+ R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
+ return this->GetEntryCountImpl(out);
+ }
+ protected:
+ /* ...? */
+ private:
+ virtual Result ReadImpl(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) = 0;
+ virtual Result GetEntryCountImpl(s64 *out) = 0;
+ };
+
+}
diff --git a/stratosphere/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp b/stratosphere/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp
new file mode 100644
index 000000000..e81cae59f
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include "../fs_common.hpp"
+#include "../fs_file.hpp"
+#include "../fs_operate_range.hpp"
+
+namespace ams::fs::fsa {
+
+ class IFile {
+ public:
+ virtual ~IFile() { /* ... */ }
+
+ Result Read(size_t *out, s64 offset, void *buffer, size_t size, const ReadOption &option) {
+ R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
+ if (size == 0) {
+ *out = 0;
+ return ResultSuccess();
+ }
+ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
+ R_UNLESS(offset >= 0, fs::ResultOutOfRange());
+ const s64 signed_size = static_cast(size);
+ R_UNLESS(signed_size >= 0, fs::ResultOutOfRange());
+ R_UNLESS((std::numeric_limits::max() - offset) >= signed_size, fs::ResultOutOfRange());
+ return this->ReadImpl(out, offset, buffer, size, option);
+ }
+
+ Result Read(size_t *out, s64 offset, void *buffer, size_t size) {
+ return this->Read(out, offset, buffer, size, ReadOption::None);
+ }
+
+ Result GetSize(s64 *out) {
+ R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
+ return this->GetSizeImpl(out);
+ }
+
+ Result Flush() {
+ return this->FlushImpl();
+ }
+
+ Result Write(s64 offset, const void *buffer, size_t size, const WriteOption &option) {
+ if (size == 0) {
+ if (option.HasFlushFlag()) {
+ R_TRY(this->Flush());
+ }
+ return ResultSuccess();
+ }
+ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
+ R_UNLESS(offset >= 0, fs::ResultOutOfRange());
+ const s64 signed_size = static_cast(size);
+ R_UNLESS(signed_size >= 0, fs::ResultOutOfRange());
+ R_UNLESS((std::numeric_limits::max() - offset) >= signed_size, fs::ResultOutOfRange());
+ return this->WriteImpl(offset, buffer, size, option);
+ }
+
+ Result SetSize(s64 size) {
+ R_UNLESS(size >= 0, fs::ResultOutOfRange());
+ return this->SetSizeImpl(size);
+ }
+
+ Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
+ return this->OperateRangeImpl(dst, dst_size, op_id, offset, size, src, src_size);
+ }
+
+ Result OperateRange(OperationId op_id, s64 offset, s64 size) {
+ return this->OperateRangeImpl(nullptr, 0, op_id, offset, size, nullptr, 0);
+ }
+ protected:
+ /* ...? */
+ private:
+ virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const ReadOption &option) = 0;
+ virtual Result GetSizeImpl(s64 *out) = 0;
+ virtual Result FlushImpl() = 0;
+ virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const WriteOption &option) = 0;
+ virtual Result SetSizeImpl(s64 size) = 0;
+ virtual Result OperateRangeImpl(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) = 0;
+ };
+
+}
diff --git a/stratosphere/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp b/stratosphere/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp
new file mode 100644
index 000000000..98a7a9e4b
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include "../fs_common.hpp"
+#include "../fs_filesystem.hpp"
+
+namespace ams::fs::fsa {
+
+ class IFile;
+ class IDirectory;
+
+ enum class QueryType {
+ SetArchiveBit = FsFileSystemQueryType_SetArchiveBit
+ };
+
+ class IFileSystem {
+ public:
+ virtual ~IFileSystem() { /* ... */ }
+
+ Result CreateFile(const char *path, s64 size, int option) {
+ R_UNLESS(path != nullptr, fs::ResultInvalidPath());
+ R_UNLESS(size >= 0, fs::ResultOutOfRange());
+ return this->CreateFileImpl(path, size, option);
+ }
+
+ Result CreateFile(const char *path, s64 size) {
+ return this->CreateFile(path, size, 0);
+ }
+
+ Result DeleteFile(const char *path) {
+ R_UNLESS(path != nullptr, fs::ResultInvalidPath());
+ return this->DeleteFileImpl(path);
+ }
+
+ Result CreateDirectory(const char *path) {
+ R_UNLESS(path != nullptr, fs::ResultInvalidPath());
+ return this->CreateDirectoryImpl(path);
+ }
+
+ Result DeleteDirectory(const char *path) {
+ R_UNLESS(path != nullptr, fs::ResultInvalidPath());
+ return this->DeleteDirectoryImpl(path);
+ }
+
+ Result DeleteDirectoryRecursively(const char *path) {
+ R_UNLESS(path != nullptr, fs::ResultInvalidPath());
+ return this->DeleteDirectoryRecursivelyImpl(path);
+ }
+
+ Result RenameFile(const char *old_path, const char *new_path) {
+ R_UNLESS(old_path != nullptr, fs::ResultInvalidPath());
+ R_UNLESS(new_path != nullptr, fs::ResultInvalidPath());
+ return this->RenameFileImpl(old_path, new_path);
+ }
+
+ Result RenameDirectory(const char *old_path, const char *new_path) {
+ R_UNLESS(old_path != nullptr, fs::ResultInvalidPath());
+ R_UNLESS(new_path != nullptr, fs::ResultInvalidPath());
+ return this->RenameDirectoryImpl(old_path, new_path);
+ }
+
+ Result GetEntryType(DirectoryEntryType *out, const char *path) {
+ R_UNLESS(path != nullptr, fs::ResultInvalidPath());
+ R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
+ return this->GetEntryTypeImpl(out, path);
+ }
+
+ Result OpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) {
+ R_UNLESS(path != nullptr, fs::ResultInvalidPath());
+ R_UNLESS(out_file != nullptr, fs::ResultNullptrArgument());
+ R_UNLESS((mode & OpenMode_ReadWrite) != 0, fs::ResultInvalidArgument());
+ R_UNLESS((mode & ~OpenMode_All) == 0, fs::ResultInvalidArgument());
+ return this->OpenFileImpl(out_file, path, mode);
+ }
+
+ Result OpenDirectory(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) {
+ R_UNLESS(path != nullptr, fs::ResultInvalidPath());
+ R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument());
+ R_UNLESS((mode & OpenDirectoryMode_All) != 0, fs::ResultInvalidArgument());
+ R_UNLESS((mode & ~OpenDirectoryMode_All) == 0, fs::ResultInvalidArgument());
+ return this->OpenDirectoryImpl(out_dir, path, mode);
+ }
+
+ Result Commit() {
+ return this->CommitImpl();
+ }
+
+ Result GetFreeSpaceSize(s64 *out, const char *path) {
+ R_UNLESS(path != nullptr, fs::ResultInvalidPath());
+ R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
+ return this->GetFreeSpaceSizeImpl(out, path);
+ }
+
+ Result GetTotalSpaceSize(s64 *out, const char *path) {
+ R_UNLESS(path != nullptr, fs::ResultInvalidPath());
+ R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
+ return this->GetTotalSpaceSizeImpl(out, path);
+ }
+
+ Result CleanDirectoryRecursively(const char *path) {
+ R_UNLESS(path != nullptr, fs::ResultInvalidPath());
+ return this->CleanDirectoryRecursivelyImpl(path);
+ }
+
+ Result GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) {
+ R_UNLESS(path != nullptr, fs::ResultInvalidPath());
+ R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
+ return this->GetFileTimeStampRawImpl(out, path);
+ }
+
+ Result QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, QueryType query, const char *path) {
+ R_UNLESS(path != nullptr, fs::ResultInvalidPath());
+ return this->QueryEntryImpl(dst, dst_size, src, src_size, query, path);
+ }
+
+ /* These aren't accessible as commands. */
+
+ Result CommitProvisionally(s64 counter) {
+ return this->CommitProvisionallyImpl(counter);
+ }
+
+ Result Rollback() {
+ return this->RollbackImpl();
+ }
+
+ Result Flush() {
+ return this->FlushImpl();
+ }
+
+ protected:
+ /* ...? */
+ private:
+ virtual Result CreateFileImpl(const char *path, s64 size, int flags) = 0;
+ virtual Result DeleteFileImpl(const char *path) = 0;
+ virtual Result CreateDirectoryImpl(const char *path) = 0;
+ virtual Result DeleteDirectoryImpl(const char *path) = 0;
+ virtual Result DeleteDirectoryRecursivelyImpl(const char *path) = 0;
+ virtual Result RenameFileImpl(const char *old_path, const char *new_path) = 0;
+ virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) = 0;
+ virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const char *path) = 0;
+ virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, OpenMode mode) = 0;
+ virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) = 0;
+ virtual Result CommitImpl() = 0;
+
+ virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) {
+ return fs::ResultNotImplemented();
+ }
+
+ virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) {
+ return fs::ResultNotImplemented();
+ }
+
+ virtual Result CleanDirectoryRecursivelyImpl(const char *path) = 0;
+
+ virtual Result GetFileTimeStampRawImpl(FileTimeStampRaw *out, const char *path) {
+ return fs::ResultNotImplemented();
+ }
+
+ virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, QueryType query, const char *path) {
+ return fs::ResultNotImplemented();
+ }
+
+ /* These aren't accessible as commands. */
+ virtual Result CommitProvisionallyImpl(s64 counter) {
+ return fs::ResultNotImplemented();
+ }
+
+ virtual Result RollbackImpl() {
+ return fs::ResultNotImplemented();
+ }
+
+ virtual Result FlushImpl() {
+ return fs::ResultNotImplemented();
+ }
+ };
+
+}
diff --git a/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_manager.hpp b/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_manager.hpp
index 27d70b847..0627aed2c 100644
--- a/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_manager.hpp
+++ b/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_manager.hpp
@@ -51,6 +51,8 @@ namespace ams::sf::cmif {
explicit Domain(ServerDomainManager *m) : manager(m) { /* ... */ }
~Domain();
+ void DestroySelf();
+
virtual ServerDomainBase *GetServerDomain() override final {
return static_cast(this);
}
@@ -116,10 +118,9 @@ namespace ams::sf::cmif {
}
return new (storage) Domain(this);
}
-
- inline void FreeDomainServiceObject(DomainServiceObject *object) {
- static_cast(object)->~Domain();
- this->FreeDomain(object);
+ public:
+ static void DestroyDomainServiceObject(DomainServiceObject *obj) {
+ static_cast(obj)->DestroySelf();
}
};
diff --git a/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp b/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp
index 9dbea1009..77758190e 100644
--- a/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp
+++ b/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp
@@ -103,6 +103,8 @@ namespace ams::sf::cmif {
class MitmDomainServiceObject : public DomainServiceObject{};
+ static_assert(sizeof(DomainServiceObject) == sizeof(MitmDomainServiceObject));
+
template<>
struct ServiceDispatchTraits {
static_assert(std::is_base_of::value, "DomainServiceObject must derive from sf::IServiceObject");
diff --git a/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp b/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp
index 6d5c45274..38cdd574c 100644
--- a/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp
+++ b/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp
@@ -32,10 +32,6 @@ namespace ams::sf::hipc {
inline cmif::DomainServiceObject *AllocateDomainServiceObject() {
return cmif::ServerDomainManager::AllocateDomainServiceObject();
}
-
- inline void FreeDomainServiceObject(cmif::DomainServiceObject *object) {
- cmif::ServerDomainManager::FreeDomainServiceObject(object);
- }
};
}
diff --git a/stratosphere/libstratosphere/source/ams/ams_exosphere_api.cpp b/stratosphere/libstratosphere/source/ams/ams_exosphere_api.cpp
index 9d97f2c69..f1233ec3f 100644
--- a/stratosphere/libstratosphere/source/ams/ams_exosphere_api.cpp
+++ b/stratosphere/libstratosphere/source/ams/ams_exosphere_api.cpp
@@ -58,7 +58,7 @@ namespace ams::exosphere {
namespace {
inline Result GetRcmBugPatched(bool *out) {
- u64 tmp;
+ u64 tmp = 0;
R_TRY(spl::smc::ConvertResult(spl::smc::GetConfig(&tmp, 1, SplConfigItem_ExosphereHasRcmBugPatch)));
*out = (tmp != 0);
return ResultSuccess();
diff --git a/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_domain_manager.cpp b/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_domain_manager.cpp
index 6be09d7cd..67b9ccb8e 100644
--- a/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_domain_manager.cpp
+++ b/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_domain_manager.cpp
@@ -31,6 +31,12 @@ namespace ams::sf::cmif {
}
}
+ void ServerDomainManager::Domain::DestroySelf() {
+ ServerDomainManager *manager = this->manager;
+ this->~Domain();
+ manager->FreeDomain(this);
+ }
+
Result ServerDomainManager::Domain::ReserveIds(DomainObjectId *out_ids, size_t count) {
for (size_t i = 0; i < count; i++) {
Entry *entry = this->manager->entry_manager.AllocateEntry();
diff --git a/stratosphere/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp b/stratosphere/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp
index 85c4aa419..fcf827375 100644
--- a/stratosphere/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp
+++ b/stratosphere/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp
@@ -63,7 +63,7 @@ namespace ams::sf::hipc {
/* Allocate a domain. */
auto domain = this->manager->AllocateDomainServiceObject();
R_UNLESS(domain, sf::hipc::ResultOutOfDomains());
- auto domain_guard = SCOPE_GUARD { this->manager->FreeDomainServiceObject(domain); };
+ auto domain_guard = SCOPE_GUARD { cmif::ServerDomainManager::DestroyDomainServiceObject(static_cast(domain)); };
cmif::DomainObjectId object_id = cmif::InvalidDomainObjectId;
@@ -80,8 +80,8 @@ namespace ams::sf::hipc {
/* Create new object. */
cmif::MitmDomainServiceObject *domain_ptr = static_cast(domain);
- new_holder = cmif::ServiceObjectHolder(std::move(std::shared_ptr(domain_ptr, [&](cmif::MitmDomainServiceObject *obj) {
- this->manager->FreeDomainServiceObject(domain);
+ new_holder = cmif::ServiceObjectHolder(std::move(std::shared_ptr(domain_ptr, [](cmif::MitmDomainServiceObject *obj) {
+ cmif::ServerDomainManager::DestroyDomainServiceObject(static_cast(obj));
})));
} else {
/* We're not a mitm session. Reserve a new object in the domain. */
@@ -89,8 +89,8 @@ namespace ams::sf::hipc {
/* Create new object. */
cmif::DomainServiceObject *domain_ptr = static_cast(domain);
- new_holder = cmif::ServiceObjectHolder(std::move(std::shared_ptr(domain_ptr, [&](cmif::DomainServiceObject *obj) {
- this->manager->FreeDomainServiceObject(domain);
+ new_holder = cmif::ServiceObjectHolder(std::move(std::shared_ptr(domain_ptr, [](cmif::DomainServiceObject *obj) {
+ cmif::ServerDomainManager::DestroyDomainServiceObject(static_cast(obj));
})));
}