Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66db154adc | ||
|
|
eecd33250d | ||
|
|
887adf93ac | ||
|
|
a923b8431f | ||
| 15822d0960 | |||
|
|
0e9cd964c0 | ||
|
|
36cc9a9f49 | ||
|
|
f5cd912604 | ||
|
|
c8b7316581 |
@@ -70,11 +70,11 @@ namespace ams::fs {
|
|||||||
virtual Result Read(s64 offset, void *buffer, size_t size) override;
|
virtual Result Read(s64 offset, void *buffer, size_t size) override;
|
||||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override;
|
virtual Result Write(s64 offset, const void *buffer, size_t size) override;
|
||||||
virtual Result Flush() override;
|
virtual Result Flush() override;
|
||||||
virtual Result GetSize(s64 *out_size) override;
|
|
||||||
virtual Result SetSize(s64 size) override;
|
virtual Result SetSize(s64 size) override;
|
||||||
|
virtual Result GetSize(s64 *out_size) override;
|
||||||
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override;
|
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ACCURATE_TO_VERSION: Unknown */
|
/* ACCURATE_TO_VERSION: Unknown */
|
||||||
class FileStorageBasedFileSystem : public FileStorage {
|
class FileStorageBasedFileSystem : public FileStorage {
|
||||||
NON_COPYABLE(FileStorageBasedFileSystem);
|
NON_COPYABLE(FileStorageBasedFileSystem);
|
||||||
@@ -86,7 +86,7 @@ namespace ams::fs {
|
|||||||
|
|
||||||
Result Initialize(std::shared_ptr<fs::fsa::IFileSystem> base_file_system, const fs::Path &path, fs::OpenMode mode);
|
Result Initialize(std::shared_ptr<fs::fsa::IFileSystem> base_file_system, const fs::Path &path, fs::OpenMode mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileHandleStorage : public IStorage, public impl::Newable {
|
class FileHandleStorage : public IStorage, public impl::Newable {
|
||||||
private:
|
private:
|
||||||
static constexpr s64 InvalidSize = -1;
|
static constexpr s64 InvalidSize = -1;
|
||||||
@@ -114,5 +114,5 @@ namespace ams::fs {
|
|||||||
virtual Result SetSize(s64 size) override;
|
virtual Result SetSize(s64 size) override;
|
||||||
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override;
|
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere/fs/fs_common.hpp>
|
||||||
|
#include <stratosphere/fs/fs_file.hpp>
|
||||||
|
#include <stratosphere/fs/fs_istorage.hpp>
|
||||||
|
#include <stratosphere/fs/fs_operate_range.hpp>
|
||||||
|
|
||||||
|
namespace ams::fs {
|
||||||
|
|
||||||
|
class IStorageForBatchRead : public IStorage {
|
||||||
|
public:
|
||||||
|
virtual ~IStorageForBatchRead() { /* ... */ }
|
||||||
|
|
||||||
|
virtual Result BatchRead(void *out0, void *out1, void *out2, void *out3, void *out4, void *out5, void *out6, const void *in) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ReadOnlyStorageAdapterForBatchRead : public IStorageForBatchRead {
|
||||||
|
private:
|
||||||
|
std::shared_ptr<IStorageForBatchRead> m_shared_storage;
|
||||||
|
std::unique_ptr<IStorageForBatchRead> m_unique_storage;
|
||||||
|
IStorageForBatchRead *m_storage;
|
||||||
|
public:
|
||||||
|
explicit ReadOnlyStorageAdapterForBatchRead(IStorageForBatchRead *s) : m_unique_storage(s) {
|
||||||
|
m_storage = m_unique_storage.get();
|
||||||
|
}
|
||||||
|
explicit ReadOnlyStorageAdapterForBatchRead(std::shared_ptr<IStorageForBatchRead> s) : m_shared_storage(s) {
|
||||||
|
m_storage = m_shared_storage.get();
|
||||||
|
}
|
||||||
|
explicit ReadOnlyStorageAdapterForBatchRead(std::unique_ptr<IStorageForBatchRead> s) : m_unique_storage(std::move(s)) {
|
||||||
|
m_storage = m_unique_storage.get();
|
||||||
|
}
|
||||||
|
explicit ReadOnlyStorageAdapterForBatchRead(IStorage *s) : m_unique_storage(static_cast<IStorageForBatchRead *>(s)) {
|
||||||
|
m_storage = m_unique_storage.get();
|
||||||
|
}
|
||||||
|
explicit ReadOnlyStorageAdapterForBatchRead(std::shared_ptr<IStorage> s) : m_shared_storage(std::static_pointer_cast<IStorageForBatchRead>(s)) {
|
||||||
|
m_storage = m_shared_storage.get();
|
||||||
|
}
|
||||||
|
explicit ReadOnlyStorageAdapterForBatchRead(std::unique_ptr<IStorage> s) : m_unique_storage(std::unique_ptr<IStorageForBatchRead>(static_cast<IStorageForBatchRead *>(s.release()))) {
|
||||||
|
m_storage = m_unique_storage.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~ReadOnlyStorageAdapterForBatchRead() { /* ... */ }
|
||||||
|
public:
|
||||||
|
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
||||||
|
R_RETURN(m_storage->Read(offset, buffer, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
||||||
|
/* TODO: Better result? Is it possible to get a more specific one? */
|
||||||
|
AMS_UNUSED(offset, buffer, size);
|
||||||
|
R_THROW(fs::ResultUnsupportedOperation());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result Flush() override {
|
||||||
|
R_RETURN(m_storage->Flush());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result SetSize(s64 size) override {
|
||||||
|
/* TODO: Better result? Is it possible to get a more specific one? */
|
||||||
|
AMS_UNUSED(size);
|
||||||
|
R_THROW(fs::ResultUnsupportedOperation());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result GetSize(s64 *out) override {
|
||||||
|
R_RETURN(m_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 {
|
||||||
|
R_RETURN(m_storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result BatchRead(void *out0, void *out1, void *out2, void *out3, void *out4, void *out5, void *out6, const void *in) override {
|
||||||
|
/* TODO */
|
||||||
|
AMS_UNUSED(out0, out1, out2, out3, out4, out5, out6, in);
|
||||||
|
R_THROW(fs::ResultUnsupportedOperation());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept PointerToStorageForBatchRead = ::ams::util::RawOrSmartPointerTo<T, ::ams::fs::IStorageForBatchRead>;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere/fs/fs_common.hpp>
|
#include <stratosphere/fs/fs_common.hpp>
|
||||||
#include <stratosphere/fs/fs_istorage.hpp>
|
#include <stratosphere/fs/fs_istorage.hpp>
|
||||||
|
#include <stratosphere/fs/fs_istorage_for_batch_read.hpp>
|
||||||
#include <stratosphere/fs/impl/fs_newable.hpp>
|
#include <stratosphere/fs/impl/fs_newable.hpp>
|
||||||
|
|
||||||
namespace ams::fs {
|
namespace ams::fs {
|
||||||
@@ -33,29 +34,72 @@ namespace ams::fs {
|
|||||||
public:
|
public:
|
||||||
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
||||||
R_RETURN(fsStorageRead(std::addressof(m_base_storage), offset, buffer, size));
|
R_RETURN(fsStorageRead(std::addressof(m_base_storage), offset, buffer, size));
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
||||||
R_RETURN(fsStorageWrite(std::addressof(m_base_storage), offset, buffer, size));
|
R_RETURN(fsStorageWrite(std::addressof(m_base_storage), offset, buffer, size));
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual Result Flush() override {
|
virtual Result Flush() override {
|
||||||
R_RETURN(fsStorageFlush(std::addressof(m_base_storage)));
|
R_RETURN(fsStorageFlush(std::addressof(m_base_storage)));
|
||||||
};
|
}
|
||||||
|
|
||||||
|
virtual Result SetSize(s64 size) override {
|
||||||
|
R_RETURN(fsStorageSetSize(std::addressof(m_base_storage), size));
|
||||||
|
}
|
||||||
|
|
||||||
virtual Result GetSize(s64 *out_size) override {
|
virtual Result GetSize(s64 *out_size) override {
|
||||||
R_RETURN(fsStorageGetSize(std::addressof(m_base_storage), out_size));
|
R_RETURN(fsStorageGetSize(std::addressof(m_base_storage), out_size));
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual Result SetSize(s64 size) override {
|
|
||||||
R_RETURN(fsStorageSetSize(std::addressof(m_base_storage), 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 {
|
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? */
|
/* TODO: How to deal with this? */
|
||||||
AMS_UNUSED(dst, dst_size, op_id, offset, size, src, src_size);
|
AMS_UNUSED(dst, dst_size, op_id, offset, size, src, src_size);
|
||||||
R_THROW(fs::ResultUnsupportedOperation());
|
R_THROW(fs::ResultUnsupportedOperation());
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class RemoteStorageForBatchRead : public IStorageForBatchRead, public impl::Newable {
|
||||||
|
NON_COPYABLE(RemoteStorageForBatchRead);
|
||||||
|
NON_MOVEABLE(RemoteStorageForBatchRead);
|
||||||
|
private:
|
||||||
|
::FsStorageForBatchRead m_base_storage;
|
||||||
|
public:
|
||||||
|
RemoteStorageForBatchRead(::FsStorageForBatchRead &s) : m_base_storage(s) { /* ... */}
|
||||||
|
|
||||||
|
virtual ~RemoteStorageForBatchRead() { fsStorageForBatchReadClose(std::addressof(m_base_storage)); }
|
||||||
|
public:
|
||||||
|
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
||||||
|
R_RETURN(fsStorageForBatchReadRead(std::addressof(m_base_storage), offset, buffer, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
||||||
|
R_RETURN(fsStorageForBatchReadWrite(std::addressof(m_base_storage), offset, buffer, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result Flush() override {
|
||||||
|
R_RETURN(fsStorageForBatchReadFlush(std::addressof(m_base_storage)));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result SetSize(s64 size) override {
|
||||||
|
R_RETURN(fsStorageForBatchReadSetSize(std::addressof(m_base_storage), size));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result GetSize(s64 *out_size) override {
|
||||||
|
R_RETURN(fsStorageForBatchReadGetSize(std::addressof(m_base_storage), out_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? */
|
||||||
|
AMS_UNUSED(dst, dst_size, op_id, offset, size, src, src_size);
|
||||||
|
R_THROW(fs::ResultUnsupportedOperation());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result BatchRead(void *out0, void *out1, void *out2, void *out3, void *out4, void *out5, void *out6, const void *in) override {
|
||||||
|
/* TODO */
|
||||||
|
AMS_UNUSED(out0, out1, out2, out3, out4, out5, out6, in);
|
||||||
|
R_THROW(fs::ResultUnsupportedOperation());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere/fs/fs_common.hpp>
|
#include <stratosphere/fs/fs_common.hpp>
|
||||||
#include <stratosphere/fs/fs_istorage.hpp>
|
#include <stratosphere/fs/fs_istorage.hpp>
|
||||||
|
#include <stratosphere/fs/fs_istorage_for_batch_read.hpp>
|
||||||
#include <stratosphere/fs/impl/fs_newable.hpp>
|
#include <stratosphere/fs/impl/fs_newable.hpp>
|
||||||
|
|
||||||
namespace ams::fs::impl {
|
namespace ams::fs::impl {
|
||||||
@@ -33,22 +34,22 @@ namespace ams::fs::impl {
|
|||||||
virtual Result Read(s64 offset, void *buffer, size_t size) override final {
|
virtual Result Read(s64 offset, void *buffer, size_t size) override final {
|
||||||
R_RETURN(m_x->Read(offset, sf::OutNonSecureBuffer(buffer, size), static_cast<s64>(size)));
|
R_RETURN(m_x->Read(offset, sf::OutNonSecureBuffer(buffer, size), static_cast<s64>(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result GetSize(s64 *out) override final {
|
|
||||||
R_RETURN(m_x->GetSize(out));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Result Flush() override final {
|
|
||||||
R_RETURN(m_x->Flush());
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override final {
|
virtual Result Write(s64 offset, const void *buffer, size_t size) override final {
|
||||||
R_RETURN(m_x->Write(offset, sf::InNonSecureBuffer(buffer, size), static_cast<s64>(size)));
|
R_RETURN(m_x->Write(offset, sf::InNonSecureBuffer(buffer, size), static_cast<s64>(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Result Flush() override final {
|
||||||
|
R_RETURN(m_x->Flush());
|
||||||
|
}
|
||||||
|
|
||||||
virtual Result SetSize(s64 size) override final {
|
virtual Result SetSize(s64 size) override final {
|
||||||
R_RETURN(m_x->SetSize(size));
|
R_RETURN(m_x->SetSize(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Result GetSize(s64 *out) override final {
|
||||||
|
R_RETURN(m_x->GetSize(out));
|
||||||
|
}
|
||||||
|
|
||||||
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final {
|
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final {
|
||||||
AMS_UNUSED(src, src_size);
|
AMS_UNUSED(src, src_size);
|
||||||
@@ -72,5 +73,64 @@ namespace ams::fs::impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename StorageInterfaceForBatchRead>
|
||||||
|
class StorageServiceObjectAdapterForBatchRead : public ::ams::fs::impl::Newable, public ::ams::fs::IStorageForBatchRead {
|
||||||
|
NON_COPYABLE(StorageServiceObjectAdapterForBatchRead);
|
||||||
|
NON_MOVEABLE(StorageServiceObjectAdapterForBatchRead);
|
||||||
|
private:
|
||||||
|
sf::SharedPointer<StorageInterfaceForBatchRead> m_x;
|
||||||
|
public:
|
||||||
|
explicit StorageServiceObjectAdapterForBatchRead(sf::SharedPointer<StorageInterfaceForBatchRead> &&o) : m_x(o) { /* ... */}
|
||||||
|
virtual ~StorageServiceObjectAdapterForBatchRead() { /* ... */ }
|
||||||
|
public:
|
||||||
|
virtual Result Read(s64 offset, void *buffer, size_t size) override final {
|
||||||
|
R_RETURN(m_x->Read(offset, sf::OutNonSecureBuffer(buffer, size), static_cast<s64>(size)));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result Write(s64 offset, const void *buffer, size_t size) override final {
|
||||||
|
R_RETURN(m_x->Write(offset, sf::InNonSecureBuffer(buffer, size), static_cast<s64>(size)));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result Flush() override final {
|
||||||
|
R_RETURN(m_x->Flush());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result SetSize(s64 size) override final {
|
||||||
|
R_RETURN(m_x->SetSize(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result GetSize(s64 *out) override final {
|
||||||
|
R_RETURN(m_x->GetSize(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final {
|
||||||
|
AMS_UNUSED(src, src_size);
|
||||||
|
switch (op_id) {
|
||||||
|
case OperationId::Invalidate:
|
||||||
|
{
|
||||||
|
fs::QueryRangeInfo dummy_range_info;
|
||||||
|
R_RETURN(m_x->OperateRange(std::addressof(dummy_range_info), static_cast<s32>(op_id), offset, size));
|
||||||
|
}
|
||||||
|
case OperationId::QueryRange:
|
||||||
|
{
|
||||||
|
R_UNLESS(dst != nullptr, fs::ResultNullptrArgument());
|
||||||
|
R_UNLESS(dst_size == sizeof(fs::QueryRangeInfo), fs::ResultInvalidSize());
|
||||||
|
|
||||||
|
R_RETURN(m_x->OperateRange(reinterpret_cast<fs::QueryRangeInfo *>(dst), static_cast<s32>(op_id), offset, size));
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
R_THROW(fs::ResultUnsupportedOperateRangeForStorageServiceObjectAdapter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result BatchRead(void *out0, void *out1, void *out2, void *out3, void *out4, void *out5, void *out6, const void *in) override final {
|
||||||
|
/* TODO */
|
||||||
|
AMS_UNUSED(out0, out1, out2, out3, out4, out5, out6, in);
|
||||||
|
R_THROW(fs::ResultUnsupportedOperation());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,12 @@
|
|||||||
#include <stratosphere/fs/fs_query_range.hpp>
|
#include <stratosphere/fs/fs_query_range.hpp>
|
||||||
#include <stratosphere/fssystem/fssystem_utility.hpp>
|
#include <stratosphere/fssystem/fssystem_utility.hpp>
|
||||||
#include <stratosphere/fssrv/sf/fssrv_sf_istorage.hpp>
|
#include <stratosphere/fssrv/sf/fssrv_sf_istorage.hpp>
|
||||||
|
#include <stratosphere/fssrv/sf/fssrv_sf_istorage_for_batch_read.hpp>
|
||||||
|
|
||||||
namespace ams::fs {
|
namespace ams::fs {
|
||||||
|
|
||||||
class IStorage;
|
class IStorage;
|
||||||
|
class IStorageForBatchRead;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,6 +46,16 @@ namespace ams::fssrv::impl {
|
|||||||
Result OperateRange(ams::sf::Out<fs::StorageQueryRangeInfo> out, s32 op_id, s64 offset, s64 size);
|
Result OperateRange(ams::sf::Out<fs::StorageQueryRangeInfo> out, s32 op_id, s64 offset, s64 size);
|
||||||
};
|
};
|
||||||
static_assert(fssrv::sf::IsIStorage<StorageInterfaceAdapter>);
|
static_assert(fssrv::sf::IsIStorage<StorageInterfaceAdapter>);
|
||||||
|
|
||||||
|
class StorageInterfaceAdapterForBatchRead : public StorageInterfaceAdapter {
|
||||||
|
NON_COPYABLE(StorageInterfaceAdapterForBatchRead);
|
||||||
|
public:
|
||||||
|
explicit StorageInterfaceAdapterForBatchRead(std::shared_ptr<fs::IStorageForBatchRead> &&storage) : StorageInterfaceAdapter(storage) { /* ... */ }
|
||||||
|
public:
|
||||||
|
/* Command API. */
|
||||||
|
Result BatchRead(const ams::sf::OutNonSecureBuffer &out0, const ams::sf::OutNonSecureBuffer &out1, const ams::sf::OutNonSecureBuffer &out2, const ams::sf::OutNonSecureBuffer &out3, const ams::sf::OutNonSecureBuffer &out4, const ams::sf::OutNonSecureBuffer &out5, const ams::sf::OutNonSecureBuffer &out6, const ams::sf::InBuffer &in);
|
||||||
|
};
|
||||||
|
static_assert(fssrv::sf::IsIStorageForBatchRead<StorageInterfaceAdapterForBatchRead>);
|
||||||
|
|
||||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||||
class RemoteStorage {
|
class RemoteStorage {
|
||||||
@@ -82,6 +94,47 @@ namespace ams::fssrv::impl {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
static_assert(fssrv::sf::IsIStorage<RemoteStorage>);
|
static_assert(fssrv::sf::IsIStorage<RemoteStorage>);
|
||||||
|
|
||||||
|
class RemoteStorageForBatchRead {
|
||||||
|
NON_COPYABLE(RemoteStorageForBatchRead);
|
||||||
|
NON_MOVEABLE(RemoteStorageForBatchRead);
|
||||||
|
private:
|
||||||
|
::FsStorageForBatchRead m_base_storage;
|
||||||
|
public:
|
||||||
|
RemoteStorageForBatchRead(::FsStorageForBatchRead &s) : m_base_storage(s) { /* ... */}
|
||||||
|
|
||||||
|
virtual ~RemoteStorageForBatchRead() { fsStorageForBatchReadClose(std::addressof(m_base_storage)); }
|
||||||
|
public:
|
||||||
|
Result Read(s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size) {
|
||||||
|
R_RETURN(fsStorageForBatchReadRead(std::addressof(m_base_storage), offset, buffer.GetPointer(), size));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size) {
|
||||||
|
R_RETURN(fsStorageForBatchReadWrite(std::addressof(m_base_storage), offset, buffer.GetPointer(), size));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Flush(){
|
||||||
|
R_RETURN(fsStorageForBatchReadFlush(std::addressof(m_base_storage)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetSize(s64 size) {
|
||||||
|
R_RETURN(fsStorageForBatchReadSetSize(std::addressof(m_base_storage), size));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetSize(ams::sf::Out<s64> out) {
|
||||||
|
R_RETURN(fsStorageForBatchReadGetSize(std::addressof(m_base_storage), out.GetPointer()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result OperateRange(ams::sf::Out<fs::StorageQueryRangeInfo> out, s32 op_id, s64 offset, s64 size) {
|
||||||
|
static_assert(sizeof(::FsRangeInfo) == sizeof(fs::StorageQueryRangeInfo));
|
||||||
|
R_RETURN(fsStorageForBatchReadOperateRange(std::addressof(m_base_storage), static_cast<::FsOperationId>(op_id), offset, size, reinterpret_cast<::FsRangeInfo *>(out.GetPointer())));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result BatchRead(const ams::sf::OutNonSecureBuffer &out0, const ams::sf::OutNonSecureBuffer &out1, const ams::sf::OutNonSecureBuffer &out2, const ams::sf::OutNonSecureBuffer &out3, const ams::sf::OutNonSecureBuffer &out4, const ams::sf::OutNonSecureBuffer &out5, const ams::sf::OutNonSecureBuffer &out6, const ams::sf::InBuffer &in) {
|
||||||
|
R_RETURN(fsStorageForBatchReadBatchRead(std::addressof(m_base_storage), out0.GetPointer(), out1.GetPointer(), out2.GetPointer(), out3.GetPointer(), out4.GetPointer(), out5.GetPointer(), out6.GetPointer(), in.GetPointer()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(fssrv::sf::IsIStorageForBatchRead<RemoteStorageForBatchRead>);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/sf.hpp>
|
||||||
|
#include <stratosphere/fs/fs_file.hpp>
|
||||||
|
#include <stratosphere/fs/fs_query_range.hpp>
|
||||||
|
|
||||||
|
#define AMS_FSSRV_I_STORAGE_FOR_BATCH_READ_INTERFACE_INFO(C, H) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 0, Result, Read, (s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size), (offset, buffer, size)) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 1, Result, Write, (s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size), (offset, buffer, size)) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 2, Result, Flush, (), ()) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 3, Result, SetSize, (s64 size), (size)) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 4, Result, GetSize, (ams::sf::Out<s64> out), (out)) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 5, Result, OperateRange, (ams::sf::Out<ams::fs::StorageQueryRangeInfo> out, s32 op_id, s64 offset, s64 size), (out, op_id, offset, size)) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 10, Result, BatchRead, (const ams::sf::OutNonSecureBuffer &out0, const ams::sf::OutNonSecureBuffer &out1, const ams::sf::OutNonSecureBuffer &out2, const ams::sf::OutNonSecureBuffer &out3, const ams::sf::OutNonSecureBuffer &out4, const ams::sf::OutNonSecureBuffer &out5, const ams::sf::OutNonSecureBuffer &out6, const ams::sf::InBuffer &in), (out0, out1, out2, out3, out4, out5, out6, in))
|
||||||
|
|
||||||
|
AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IStorageForBatchRead, AMS_FSSRV_I_STORAGE_FOR_BATCH_READ_INTERFACE_INFO, 0xCD2D5606)
|
||||||
@@ -158,7 +158,40 @@ namespace ams::socket {
|
|||||||
char *ai_canonname;
|
char *ai_canonname;
|
||||||
AddrInfo *ai_next;
|
AddrInfo *ai_next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* NOTE: We are using the c-ares structs under ams::socket. */
|
||||||
|
/* Should we include c-ares instead somewhere? */
|
||||||
|
struct ares_addrinfo_node {
|
||||||
|
int ai_ttl;
|
||||||
|
int ai_flags;
|
||||||
|
int ai_family;
|
||||||
|
int ai_socktype;
|
||||||
|
int ai_protocol;
|
||||||
|
socklen_t ai_addrlen;
|
||||||
|
struct sockaddr *ai_addr;
|
||||||
|
struct ares_addrinfo_node *ai_next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ares_addrinfo_cname {
|
||||||
|
int ttl;
|
||||||
|
char *alias;
|
||||||
|
char *name;
|
||||||
|
struct ares_addrinfo_cname *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ares_addrinfo {
|
||||||
|
struct ares_addrinfo_cname *cnames;
|
||||||
|
struct ares_addrinfo_node *nodes;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ares_addrinfo_hints {
|
||||||
|
int ai_flags;
|
||||||
|
int ai_family;
|
||||||
|
int ai_socktype;
|
||||||
|
int ai_protocol;
|
||||||
|
};
|
||||||
|
|
||||||
struct TimeVal {
|
struct TimeVal {
|
||||||
long tv_sec;
|
long tv_sec;
|
||||||
long tv_usec;
|
long tv_usec;
|
||||||
|
|||||||
@@ -58,6 +58,11 @@ namespace ams::fs {
|
|||||||
Result FileStorage::Flush() {
|
Result FileStorage::Flush() {
|
||||||
R_RETURN(m_base_file->Flush());
|
R_RETURN(m_base_file->Flush());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result FileStorage::SetSize(s64 size) {
|
||||||
|
m_size = InvalidSize;
|
||||||
|
R_RETURN(m_base_file->SetSize(size));
|
||||||
|
}
|
||||||
|
|
||||||
Result FileStorage::GetSize(s64 *out_size) {
|
Result FileStorage::GetSize(s64 *out_size) {
|
||||||
R_TRY(this->UpdateSize());
|
R_TRY(this->UpdateSize());
|
||||||
@@ -65,11 +70,6 @@ namespace ams::fs {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FileStorage::SetSize(s64 size) {
|
|
||||||
m_size = InvalidSize;
|
|
||||||
R_RETURN(m_base_file->SetSize(size));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result FileStorage::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
|
Result FileStorage::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
|
||||||
switch (op_id) {
|
switch (op_id) {
|
||||||
case OperationId::Invalidate:
|
case OperationId::Invalidate:
|
||||||
@@ -102,7 +102,7 @@ namespace ams::fs {
|
|||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FileHandleStorage::UpdateSize() {
|
Result FileHandleStorage::UpdateSize() {
|
||||||
R_SUCCEED_IF(m_size != InvalidSize);
|
R_SUCCEED_IF(m_size != InvalidSize);
|
||||||
R_RETURN(GetFileSize(std::addressof(m_size), m_handle));
|
R_RETURN(GetFileSize(std::addressof(m_size), m_handle));
|
||||||
@@ -149,6 +149,11 @@ namespace ams::fs {
|
|||||||
Result FileHandleStorage::Flush() {
|
Result FileHandleStorage::Flush() {
|
||||||
R_RETURN(FlushFile(m_handle));
|
R_RETURN(FlushFile(m_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result FileHandleStorage::SetSize(s64 size) {
|
||||||
|
m_size = InvalidSize;
|
||||||
|
R_RETURN(SetFileSize(m_handle, size));
|
||||||
|
}
|
||||||
|
|
||||||
Result FileHandleStorage::GetSize(s64 *out_size) {
|
Result FileHandleStorage::GetSize(s64 *out_size) {
|
||||||
R_TRY(this->UpdateSize());
|
R_TRY(this->UpdateSize());
|
||||||
@@ -156,11 +161,6 @@ namespace ams::fs {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FileHandleStorage::SetSize(s64 size) {
|
|
||||||
m_size = InvalidSize;
|
|
||||||
R_RETURN(SetFileSize(m_handle, size));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result FileHandleStorage::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
|
Result FileHandleStorage::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
|
||||||
AMS_UNUSED(src, src_size);
|
AMS_UNUSED(src, src_size);
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace ams::fssrv::impl {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result StorageInterfaceAdapter::Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size) {
|
Result StorageInterfaceAdapter::Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size) {
|
||||||
/* Check pre-conditions. */
|
/* Check pre-conditions. */
|
||||||
R_UNLESS(0 <= offset, fs::ResultInvalidOffset());
|
R_UNLESS(0 <= offset, fs::ResultInvalidOffset());
|
||||||
R_UNLESS(0 <= size, fs::ResultInvalidSize());
|
R_UNLESS(0 <= size, fs::ResultInvalidSize());
|
||||||
@@ -42,16 +42,16 @@ namespace ams::fssrv::impl {
|
|||||||
R_RETURN(m_base_storage->Write(offset, buffer.GetPointer(), size));
|
R_RETURN(m_base_storage->Write(offset, buffer.GetPointer(), size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result StorageInterfaceAdapter::Flush() {
|
Result StorageInterfaceAdapter::Flush() {
|
||||||
R_RETURN(m_base_storage->Flush());
|
R_RETURN(m_base_storage->Flush());
|
||||||
}
|
}
|
||||||
|
|
||||||
Result StorageInterfaceAdapter::SetSize(s64 size) {
|
Result StorageInterfaceAdapter::SetSize(s64 size) {
|
||||||
R_UNLESS(size >= 0, fs::ResultInvalidSize());
|
R_UNLESS(size >= 0, fs::ResultInvalidSize());
|
||||||
R_RETURN(m_base_storage->SetSize(size));
|
R_RETURN(m_base_storage->SetSize(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result StorageInterfaceAdapter::GetSize(ams::sf::Out<s64> out) {
|
Result StorageInterfaceAdapter::GetSize(ams::sf::Out<s64> out) {
|
||||||
R_RETURN(m_base_storage->GetSize(out.GetPointer()));
|
R_RETURN(m_base_storage->GetSize(out.GetPointer()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,5 +72,11 @@ namespace ams::fssrv::impl {
|
|||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result StorageInterfaceAdapterForBatchRead::BatchRead(const ams::sf::OutNonSecureBuffer &out0, const ams::sf::OutNonSecureBuffer &out1, const ams::sf::OutNonSecureBuffer &out2, const ams::sf::OutNonSecureBuffer &out3, const ams::sf::OutNonSecureBuffer &out4, const ams::sf::OutNonSecureBuffer &out5, const ams::sf::OutNonSecureBuffer &out6, const ams::sf::InBuffer &in) {
|
||||||
|
/* TODO */
|
||||||
|
AMS_UNUSED(out0, out1, out2, out3, out4, out5, out6, in);
|
||||||
|
R_THROW(fs::ResultUnsupportedOperation());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ namespace ams::os {
|
|||||||
|
|
||||||
/* Create the critical section. */
|
/* Create the critical section. */
|
||||||
util::ConstructAt(shared_memory->cs_shared_memory);
|
util::ConstructAt(shared_memory->cs_shared_memory);
|
||||||
|
|
||||||
|
/* Set state to initialized. */
|
||||||
|
shared_memory->state = SharedMemoryType::State_Initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ namespace ams::os {
|
|||||||
|
|
||||||
/* Create the critical section. */
|
/* Create the critical section. */
|
||||||
util::ConstructAt(tmem->cs_transfer_memory);
|
util::ConstructAt(tmem->cs_transfer_memory);
|
||||||
|
|
||||||
|
/* Set state to created. */
|
||||||
|
tmem->state = TransferMemoryType::State_Created;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,20 @@
|
|||||||
#include "sfdnsres_shim.h"
|
#include "sfdnsres_shim.h"
|
||||||
|
|
||||||
namespace ams::mitm::socket::resolver {
|
namespace ams::mitm::socket::resolver {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct AresAddrInfoQuery {
|
||||||
|
std::string hostname;
|
||||||
|
ams::socket::InAddrT redirect_addr;
|
||||||
|
u16 redirect_port;
|
||||||
|
const struct ams::socket::ares_addrinfo_hints *hint;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<ssize_t, std::unique_ptr<AresAddrInfoQuery>> g_ares_addr_info_queries;
|
||||||
|
ssize_t g_current_ares_addr_info_query_id;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t SerializeRedirectedHostEnt(u8 * const dst, size_t dst_size, const char *hostname, ams::socket::InAddrT redirect_addr) {
|
ssize_t SerializeRedirectedHostEnt(u8 * const dst, size_t dst_size, const char *hostname, ams::socket::InAddrT redirect_addr) {
|
||||||
struct in_addr addr = { .s_addr = redirect_addr };
|
struct in_addr addr = { .s_addr = redirect_addr };
|
||||||
@@ -85,6 +99,97 @@ namespace ams::mitm::socket::resolver {
|
|||||||
AMS_ABORT_UNLESS(result >= 0);
|
AMS_ABORT_UNLESS(result >= 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t QueueAresAddrInfoQuery(const char *hostname, ams::socket::InAddrT redirect_addr, u16 redirect_port, const struct ams::socket::ares_addrinfo_hints *hint) {
|
||||||
|
ssize_t query_id = g_current_ares_addr_info_query_id;
|
||||||
|
|
||||||
|
AresAddrInfoQuery query;
|
||||||
|
query.hostname = hostname;
|
||||||
|
query.redirect_addr = redirect_addr;
|
||||||
|
query.redirect_port = redirect_port;
|
||||||
|
query.hint = hint;
|
||||||
|
|
||||||
|
g_ares_addr_info_queries.emplace(query_id, std::make_unique<AresAddrInfoQuery>(query));
|
||||||
|
|
||||||
|
/* NOTE: This really just increases ad infinitum. Should we bother checking it? */
|
||||||
|
++g_current_ares_addr_info_query_id;
|
||||||
|
|
||||||
|
return query_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t DequeueAresAddrInfoQuery(u8 * const dst, size_t dst_size, u32 query_id) {
|
||||||
|
AresAddrInfoQuery *query = nullptr;
|
||||||
|
|
||||||
|
for (auto it = g_ares_addr_info_queries.begin(); it != g_ares_addr_info_queries.end(); ++it) {
|
||||||
|
if (it->first == static_cast<ssize_t>(query_id)) {
|
||||||
|
query = it->second.get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ams::socket::ares_addrinfo_node node = {
|
||||||
|
.ai_ttl = 0,
|
||||||
|
.ai_flags = AF_UNSPEC,
|
||||||
|
.ai_family = 0,
|
||||||
|
.ai_socktype = 0,
|
||||||
|
.ai_protocol = 0,
|
||||||
|
.ai_addrlen = 0,
|
||||||
|
.ai_next = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (query->hint != nullptr) {
|
||||||
|
std::memcpy(reinterpret_cast<void *>(std::addressof(node.ai_flags)), reinterpret_cast<const void *>(query->hint), sizeof(struct ams::socket::ares_addrinfo_hints));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (node.ai_family) {
|
||||||
|
case AF_UNSPEC: node.ai_family = AF_INET; break;
|
||||||
|
case AF_INET: node.ai_family = AF_INET; break;
|
||||||
|
case AF_INET6: AMS_ABORT("Redirected INET6 not supported"); break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.ai_socktype == 0) {
|
||||||
|
node.ai_socktype = SOCK_STREAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.ai_protocol == 0) {
|
||||||
|
node.ai_protocol = IPPROTO_TCP;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct sockaddr_in sin = {
|
||||||
|
.sin_family = AF_INET,
|
||||||
|
.sin_port = ams::socket::InetHtons(query->redirect_port),
|
||||||
|
.sin_addr = { .s_addr = query->redirect_addr },
|
||||||
|
.sin_zero = {},
|
||||||
|
};
|
||||||
|
|
||||||
|
node.ai_addrlen = sizeof(sin);
|
||||||
|
node.ai_addr = (struct sockaddr *)(std::addressof(sin));
|
||||||
|
|
||||||
|
struct ams::socket::ares_addrinfo ai {
|
||||||
|
.cnames = nullptr,
|
||||||
|
.nodes = std::addressof(node),
|
||||||
|
.name = const_cast<char *>(query->hostname.c_str()),
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto result = serializer::DNSSerializer::ToBuffer(dst, dst_size, ai);
|
||||||
|
AMS_ABORT_UNLESS(result >= 0);
|
||||||
|
g_ares_addr_info_queries.erase(query_id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CancelAresAddrInfoQuery(u32 query_id) {
|
||||||
|
for (auto it = g_ares_addr_info_queries.begin(); it != g_ares_addr_info_queries.end(); ++it) {
|
||||||
|
if (it->first == static_cast<ssize_t>(query_id)) {
|
||||||
|
g_ares_addr_info_queries.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Result ResolverImpl::GetHostByNameRequest(u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &name, sf::Out<u32> out_host_error, sf::Out<u32> out_errno, const sf::OutBuffer &out_hostent, sf::Out<u32> out_size) {
|
Result ResolverImpl::GetHostByNameRequest(u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &name, sf::Out<u32> out_host_error, sf::Out<u32> out_errno, const sf::OutBuffer &out_hostent, sf::Out<u32> out_size) {
|
||||||
AMS_UNUSED(cancel_handle, client_pid, use_nsd_resolve);
|
AMS_UNUSED(cancel_handle, client_pid, use_nsd_resolve);
|
||||||
@@ -208,6 +313,83 @@ namespace ams::mitm::socket::resolver {
|
|||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ResolverImpl::ReportTelemetry(const sf::ClientProcessId &client_pid, const sf::InBuffer &telemetry, u32 version) {
|
||||||
|
/* NOTE: As of 23.0.0 this command does nothing. We mitm it anyway for future proofing. */
|
||||||
|
AMS_UNUSED(client_pid, telemetry, version);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ResolverImpl::QueryAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &node, const sf::InAutoSelectBuffer &srv, const sf::InAutoSelectBuffer &serialized_hint, sf::Out<u32> out_query_id, u32 fd, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_retval, sf::Out<s32> out_errno) {
|
||||||
|
AMS_UNUSED(client_pid, fd, options_version, options, num_options);
|
||||||
|
|
||||||
|
const char *hostname = reinterpret_cast<const char *>(node.GetPointer());
|
||||||
|
|
||||||
|
LogDebug("[%016lx]: QueryAddrInfoRequestWithOptions(%s, %s)\n", m_client_info.program_id.value, hostname, reinterpret_cast<const char *>(srv.GetPointer()));
|
||||||
|
|
||||||
|
R_UNLESS(hostname != nullptr, sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
|
ams::socket::InAddrT redirect_addr = {};
|
||||||
|
R_UNLESS(GetRedirectedHostByName(std::addressof(redirect_addr), hostname), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
|
u16 port = 0;
|
||||||
|
if (srv.GetPointer() != nullptr) {
|
||||||
|
for (const char *cur = reinterpret_cast<const char *>(srv.GetPointer()); *cur != 0; ++cur) {
|
||||||
|
AMS_ABORT_UNLESS(std::isdigit(static_cast<unsigned char>(*cur)));
|
||||||
|
port *= 10;
|
||||||
|
port += *cur - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogDebug("[%016lx]: Queueing redirection %s:%u to %u.%u.%u.%u\n", m_client_info.program_id.value, hostname, port, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
|
||||||
|
|
||||||
|
const bool use_hint = serialized_hint.GetPointer() != nullptr;
|
||||||
|
struct ams::socket::ares_addrinfo_hints hint = {};
|
||||||
|
if (use_hint) {
|
||||||
|
AMS_ABORT_UNLESS(serializer::DNSSerializer::FromBuffer(hint, serialized_hint.GetPointer(), serialized_hint.GetSize()) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto query_id = QueueAresAddrInfoQuery(hostname, redirect_addr, port, use_hint ? std::addressof(hint) : nullptr);
|
||||||
|
|
||||||
|
LogDebug("[%016lx]: Queued query with id 0x%lx\n", m_client_info.program_id.value, query_id);
|
||||||
|
|
||||||
|
/* Forward the query. The provided socket EventFd must be signalled by having bsdsocket write 1 to the associated socket. */
|
||||||
|
/* This is fine though, we only care about replacing with our redirection during fetch. */
|
||||||
|
R_TRY(sfdnsresQueryAddrInfoRequestWithOptionsFwd(m_forward_service.get(), static_cast<u64>(client_pid.GetValue().value), node.GetPointer(), node.GetSize(), srv.GetPointer(), srv.GetSize(), serialized_hint.GetPointer(), serialized_hint.GetSize(), reinterpret_cast<u32 *>(out_query_id.GetPointer()), fd, options_version, options.GetPointer(), options.GetSize(), num_options, reinterpret_cast<s32 *>(out_retval.GetPointer()), reinterpret_cast<s32 *>(out_errno.GetPointer())));
|
||||||
|
|
||||||
|
/* Replace with our own query. */
|
||||||
|
*out_query_id = query_id;
|
||||||
|
*out_retval = 0;
|
||||||
|
*out_errno = 0;
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ResolverImpl::FetchAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, u32 query_id, u32 version, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out<u32> out_size, sf::Out<s32> out_retval, sf::Out<s32> out_errno) {
|
||||||
|
AMS_UNUSED(client_pid, version);
|
||||||
|
|
||||||
|
LogDebug("[%016lx]: FetchAddrInfoRequestWithOptions(%d)\n", m_client_info.program_id.value, query_id);
|
||||||
|
|
||||||
|
const auto size = DequeueAresAddrInfoQuery(out_addrinfo.GetPointer(), out_addrinfo.GetSize(), query_id);
|
||||||
|
|
||||||
|
LogDebug("[%016lx]: Dequeued query with size 0x%lx\n", m_client_info.program_id.value, size);
|
||||||
|
|
||||||
|
*out_size = size;
|
||||||
|
*out_retval = 0;
|
||||||
|
*out_errno = 0;
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ResolverImpl::CancelQuery(const sf::ClientProcessId &client_pid, u32 query_id) {
|
||||||
|
AMS_UNUSED(client_pid);
|
||||||
|
|
||||||
|
LogDebug("[%016lx]: CancelQuery(%d)\n", m_client_info.program_id.value, query_id);
|
||||||
|
|
||||||
|
CancelAresAddrInfoQuery(query_id);
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
Result ResolverImpl::AtmosphereReloadHostsFile() {
|
Result ResolverImpl::AtmosphereReloadHostsFile() {
|
||||||
/* Perform a hosts file reload. */
|
/* Perform a hosts file reload. */
|
||||||
|
|||||||
@@ -16,11 +16,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#define AMS_DNS_MITM_INTERFACE_INFO(C, H) \
|
#define AMS_DNS_MITM_INTERFACE_INFO(C, H) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 2, Result, GetHostByNameRequest, (u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &name, sf::Out<u32> out_host_error, sf::Out<u32> out_errno, const sf::OutBuffer &out_hostent, sf::Out<u32> out_size), (cancel_handle, client_pid, use_nsd_resolve, name, out_host_error, out_errno, out_hostent, out_size)) \
|
AMS_SF_METHOD_INFO(C, H, 2, Result, GetHostByNameRequest, (u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &name, sf::Out<u32> out_host_error, sf::Out<u32> out_errno, const sf::OutBuffer &out_hostent, sf::Out<u32> out_size), (cancel_handle, client_pid, use_nsd_resolve, name, out_host_error, out_errno, out_hostent, out_size)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 6, Result, GetAddrInfoRequest, (u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutBuffer &out_addrinfo, sf::Out<u32> out_errno, sf::Out<s32> out_retval, sf::Out<u32> out_size), (cancel_handle, client_pid, use_nsd_resolve, node, srv, serialized_hint, out_addrinfo, out_errno, out_retval, out_size)) \
|
AMS_SF_METHOD_INFO(C, H, 6, Result, GetAddrInfoRequest, (u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutBuffer &out_addrinfo, sf::Out<u32> out_errno, sf::Out<s32> out_retval, sf::Out<u32> out_size), (cancel_handle, client_pid, use_nsd_resolve, node, srv, serialized_hint, out_addrinfo, out_errno, out_retval, out_size)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 10, Result, GetHostByNameRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &name, const sf::OutAutoSelectBuffer &out_hostent, sf::Out<u32> out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno), (client_pid, name, out_hostent, out_size, options_version, options, num_options, out_host_error, out_errno), hos::Version_5_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 10, Result, GetHostByNameRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &name, const sf::OutAutoSelectBuffer &out_hostent, sf::Out<u32> out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno), (client_pid, name, out_hostent, out_size, options_version, options, num_options, out_host_error, out_errno), hos::Version_5_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 12, Result, GetAddrInfoRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out<u32> out_size, sf::Out<s32> out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno), (client_pid, node, srv, serialized_hint, out_addrinfo, out_size, out_retval, options_version, options, num_options, out_host_error, out_errno), hos::Version_5_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 12, Result, GetAddrInfoRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out<u32> out_size, sf::Out<s32> out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno), (client_pid, node, srv, serialized_hint, out_addrinfo, out_size, out_retval, options_version, options, num_options, out_host_error, out_errno), hos::Version_5_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 16, Result, ReportTelemetry, (const sf::ClientProcessId &client_pid, const sf::InBuffer &telemetry, u32 version), (client_pid, telemetry, version), hos::Version_23_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 100, Result, QueryAddrInfoRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &node, const sf::InAutoSelectBuffer &srv, const sf::InAutoSelectBuffer &serialized_hint, sf::Out<u32> out_query_id, u32 fd, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_retval, sf::Out<s32> out_errno), (client_pid, node, srv, serialized_hint, out_query_id, fd, options_version, options, num_options, out_retval, out_errno), hos::Version_23_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 102, Result, FetchAddrInfoRequestWithOptions, (const sf::ClientProcessId &client_pid, u32 query_id, u32 version, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out<u32> out_size, sf::Out<s32> out_retval, sf::Out<s32> out_errno), (client_pid, query_id, version, out_addrinfo, out_size, out_retval, out_errno), hos::Version_23_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 104, Result, CancelQuery, (const sf::ClientProcessId &client_pid, u32 query_id), (client_pid, query_id), hos::Version_23_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 65000, Result, AtmosphereReloadHostsFile, (), ())
|
AMS_SF_METHOD_INFO(C, H, 65000, Result, AtmosphereReloadHostsFile, (), ())
|
||||||
|
|
||||||
AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::socket::resolver, IResolver, AMS_DNS_MITM_INTERFACE_INFO, 0x5935F91A)
|
AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::socket::resolver, IResolver, AMS_DNS_MITM_INTERFACE_INFO, 0x5935F91A)
|
||||||
@@ -44,7 +48,11 @@ namespace ams::mitm::socket::resolver {
|
|||||||
Result GetAddrInfoRequest(u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutBuffer &out_addrinfo, sf::Out<u32> out_errno, sf::Out<s32> out_retval, sf::Out<u32> out_size);
|
Result GetAddrInfoRequest(u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutBuffer &out_addrinfo, sf::Out<u32> out_errno, sf::Out<s32> out_retval, sf::Out<u32> out_size);
|
||||||
Result GetHostByNameRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &name, const sf::OutAutoSelectBuffer &out_hostent, sf::Out<u32> out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno);
|
Result GetHostByNameRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &name, const sf::OutAutoSelectBuffer &out_hostent, sf::Out<u32> out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno);
|
||||||
Result GetAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out<u32> out_size, sf::Out<s32> out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno);
|
Result GetAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out<u32> out_size, sf::Out<s32> out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno);
|
||||||
|
Result ReportTelemetry(const sf::ClientProcessId &client_pid, const sf::InBuffer &telemetry, u32 version);
|
||||||
|
Result QueryAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &node, const sf::InAutoSelectBuffer &srv, const sf::InAutoSelectBuffer &serialized_hint, sf::Out<u32> out_query_id, u32 fd, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_retval, sf::Out<s32> out_errno);
|
||||||
|
Result FetchAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, u32 query_id, u32 version, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out<u32> out_size, sf::Out<s32> out_retval, sf::Out<s32> out_errno);
|
||||||
|
Result CancelQuery(const sf::ClientProcessId &client_pid, u32 query_id);
|
||||||
|
|
||||||
/* Extension commands. */
|
/* Extension commands. */
|
||||||
Result AtmosphereReloadHostsFile();
|
Result AtmosphereReloadHostsFile();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -190,14 +190,20 @@ namespace ams::mitm::socket::resolver::serializer {
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (dst_size - (cur - dst) < addr_info.ai_addrlen) {
|
if (hos::GetVersion() >= hos::Version_23_0_0) {
|
||||||
|
/* 23.0.0 fixed this by returning an error instead. */
|
||||||
rc = -1;
|
rc = -1;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
} else {
|
||||||
|
if (dst_size - (cur - dst) < addr_info.ai_addrlen) {
|
||||||
|
rc = -1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* NOTE: This is clearly a nintendo bug, see the accompanying note in FromBufferInternalImpl */
|
/* NOTE: This is clearly a nintendo bug, see the accompanying note in FromBufferInternalImpl */
|
||||||
std::memmove(cur, std::addressof(addr_info.ai_addr), addr_info.ai_addrlen);
|
std::memmove(cur, std::addressof(addr_info.ai_addr), addr_info.ai_addrlen);
|
||||||
rc = addr_info.ai_addrlen;
|
rc = addr_info.ai_addrlen;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cur += rc;
|
cur += rc;
|
||||||
}
|
}
|
||||||
@@ -317,6 +323,7 @@ namespace ams::mitm::socket::resolver::serializer {
|
|||||||
} else if (IsAfInet<T>(out.ai_family)) {
|
} else if (IsAfInet<T>(out.ai_family)) {
|
||||||
out.ai_addr = static_cast<SockAddrType<T> *>(ams::socket::impl::Alloc(sizeof(SockAddrInType<T>)));
|
out.ai_addr = static_cast<SockAddrType<T> *>(ams::socket::impl::Alloc(sizeof(SockAddrInType<T>)));
|
||||||
if (out.ai_addr == nullptr) {
|
if (out.ai_addr == nullptr) {
|
||||||
|
ams::socket::SetLastError(ams::socket::Errno::ENoMem);
|
||||||
rc = -1;
|
rc = -1;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -328,6 +335,7 @@ namespace ams::mitm::socket::resolver::serializer {
|
|||||||
} else if (IsAfInet6<T>(out.ai_family)) {
|
} else if (IsAfInet6<T>(out.ai_family)) {
|
||||||
out.ai_addr = static_cast<SockAddrType<T> *>(ams::socket::impl::Alloc(sizeof(SockAddrIn6Type<T>)));
|
out.ai_addr = static_cast<SockAddrType<T> *>(ams::socket::impl::Alloc(sizeof(SockAddrIn6Type<T>)));
|
||||||
if (out.ai_addr == nullptr) {
|
if (out.ai_addr == nullptr) {
|
||||||
|
ams::socket::SetLastError(ams::socket::Errno::ENoMem);
|
||||||
rc = -1;
|
rc = -1;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -337,17 +345,24 @@ namespace ams::mitm::socket::resolver::serializer {
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out.ai_addr = static_cast<decltype(out.ai_addr)>(ams::socket::impl::Alloc(out.ai_addrlen));
|
if (hos::GetVersion() >= hos::Version_23_0_0) {
|
||||||
if (out.ai_addr == nullptr) {
|
/* 23.0.0 fixed this by returning an error instead. */
|
||||||
|
ams::socket::SetLastError(ams::socket::Errno::EInval);
|
||||||
rc = -1;
|
rc = -1;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
} else {
|
||||||
|
out.ai_addr = static_cast<decltype(out.ai_addr)>(ams::socket::impl::Alloc(out.ai_addrlen));
|
||||||
|
if (out.ai_addr == nullptr) {
|
||||||
|
rc = -1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* NOTE: This is *clearly* a nintendo bug. */
|
/* NOTE: This is *clearly* a nintendo bug. */
|
||||||
/* They obviously intend to copy to the buffer they just allocated, but instead they copy to the addrinfo structure itself. */
|
/* They obviously intend to copy to the buffer they just allocated, but instead they copy to the addrinfo structure itself. */
|
||||||
/* Probably &out.ai_addr instead of &out.ai_addr[0]? Either way, we'll implement what they do, but... */
|
/* Probably &out.ai_addr instead of &out.ai_addr[0]? Either way, we'll implement what they do, but... */
|
||||||
std::memcpy(std::addressof(out.ai_addr), cur, out.ai_addrlen);
|
std::memcpy(std::addressof(out.ai_addr), cur, out.ai_addrlen);
|
||||||
rc = out.ai_addrlen;
|
rc = out.ai_addrlen;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cur += rc;
|
cur += rc;
|
||||||
}
|
}
|
||||||
@@ -368,6 +383,7 @@ namespace ams::mitm::socket::resolver::serializer {
|
|||||||
} else if (tmp_value == AddrInfoMagic) {
|
} else if (tmp_value == AddrInfoMagic) {
|
||||||
out.ai_next = static_cast<T *>(ams::socket::impl::Alloc(sizeof(T)));
|
out.ai_next = static_cast<T *>(ams::socket::impl::Alloc(sizeof(T)));
|
||||||
if (out.ai_next == nullptr) {
|
if (out.ai_next == nullptr) {
|
||||||
|
ams::socket::SetLastError(ams::socket::Errno::ENoMem);
|
||||||
rc = -1;
|
rc = -1;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,380 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "../dnsmitm_debug.hpp"
|
||||||
|
#include "../socket_allocator.hpp"
|
||||||
|
#include "serializer.hpp"
|
||||||
|
|
||||||
|
namespace ams::mitm::socket::resolver::serializer {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/* NOTE: This is local to the nn::socket::resolver::serializer namespace. */
|
||||||
|
struct AddrInfoNodeCname {
|
||||||
|
struct ams::socket::ares_addrinfo_node *node;
|
||||||
|
char *ai_canonname;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline u32 AresMagic = 0xBEEFCAFE;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept IsAresAddrInfo = std::same_as<T, struct ams::socket::ares_addrinfo>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept IsAresAddrInfoHints = std::same_as<T, struct ams::socket::ares_addrinfo_hints>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept IsAresAddrInfoNode = std::same_as<T, struct ams::socket::ares_addrinfo_node>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept IsAddrInfoNodeCname = std::same_as<T, AddrInfoNodeCname>;
|
||||||
|
|
||||||
|
template<typename T> requires IsAresAddrInfoNode<T> || IsAddrInfoNodeCname<T>
|
||||||
|
using SockAddrInType = typename std::conditional<std::same_as<T, struct ams::socket::ares_addrinfo> || std::same_as<T, AddrInfoNodeCname>, struct sockaddr_in, struct sockaddr_in>::type;
|
||||||
|
|
||||||
|
template<typename T> requires IsAresAddrInfoNode<T> || IsAddrInfoNodeCname<T>
|
||||||
|
using SockAddrIn6Type = typename std::conditional<std::same_as<T, struct ams::socket::ares_addrinfo> || std::same_as<T, AddrInfoNodeCname>, struct sockaddr_in6, struct sockaddr_in6>::type;
|
||||||
|
|
||||||
|
template<typename T> requires IsAresAddrInfoNode<T> || IsAddrInfoNodeCname<T>
|
||||||
|
constexpr bool IsAfInet(const auto ai_family) {
|
||||||
|
if constexpr (std::same_as<T, struct ams::socket::ares_addrinfo_node> || std::same_as<T, AddrInfoNodeCname>) {
|
||||||
|
/* NOTE: Keep this in case a nn::socket::AddrInfo equivalent is ever implemented for c-ares. */
|
||||||
|
/* As of 23.0.0 only the ares_addrinfo struct is supported in the serializer. */
|
||||||
|
return ai_family == AF_INET;
|
||||||
|
} else {
|
||||||
|
return ai_family == AF_INET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsAresAddrInfoNode<T> || IsAddrInfoNodeCname<T>
|
||||||
|
constexpr bool IsAfInet6(const auto ai_family) {
|
||||||
|
if constexpr (std::same_as<T, struct ams::socket::ares_addrinfo_node> || std::same_as<T, AddrInfoNodeCname>) {
|
||||||
|
/* NOTE: Keep this in case a nn::socket::AddrInfo equivalent is ever implemented for c-ares. */
|
||||||
|
/* As of 23.0.0 only the ares_addrinfo struct is supported in the serializer. */
|
||||||
|
return ai_family == AF_INET6;
|
||||||
|
} else {
|
||||||
|
return ai_family == AF_INET6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsAresAddrInfoNode<T>
|
||||||
|
size_t AddrInfoNodeSizeOf(const T *ares_addr_info_node) {
|
||||||
|
size_t rc = 6 * sizeof(u32);
|
||||||
|
|
||||||
|
if (ares_addr_info_node->ai_addr == nullptr) {
|
||||||
|
rc += sizeof(u32);
|
||||||
|
} else if (IsAfInet<T>(ares_addr_info_node->ai_family)) {
|
||||||
|
rc += DNSSerializer::SizeOf(*reinterpret_cast<SockAddrInType<T> *>(ares_addr_info_node->ai_addr));
|
||||||
|
} else if (IsAfInet6<T>(ares_addr_info_node->ai_family)) {
|
||||||
|
rc += DNSSerializer::SizeOf(*reinterpret_cast<SockAddrIn6Type<T> *>(ares_addr_info_node->ai_addr));
|
||||||
|
} else if (ares_addr_info_node->ai_addrlen == 0) {
|
||||||
|
rc += sizeof(u32);
|
||||||
|
} else {
|
||||||
|
rc += ares_addr_info_node->ai_addrlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ares_addr_info_node->ai_next == nullptr) {
|
||||||
|
rc += sizeof(u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsAresAddrInfo<T>
|
||||||
|
size_t SizeOfImpl(const T &in) {
|
||||||
|
size_t rc = 0;
|
||||||
|
|
||||||
|
const T *ares_addr_info = std::addressof(in);
|
||||||
|
for (const struct ams::socket::ares_addrinfo_node *ares_addr_info_node = ares_addr_info->nodes; ares_addr_info_node != nullptr; ares_addr_info_node = ares_addr_info_node->ai_next) {
|
||||||
|
rc += AddrInfoNodeSizeOf(ares_addr_info_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsAresAddrInfoHints<T>
|
||||||
|
size_t SizeOfImpl(const T &) {
|
||||||
|
return 5 * sizeof(u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsAddrInfoNodeCname<T>
|
||||||
|
ssize_t ToBufferInternalImpl(u8 * const dst, size_t dst_size, const T &addr_info_node_cname) {
|
||||||
|
ssize_t rc = -1;
|
||||||
|
u8 *cur = dst;
|
||||||
|
|
||||||
|
{
|
||||||
|
const u32 value = AresMagic;
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const u32 value = static_cast<u32>(addr_info_node_cname.node->ai_flags);
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const u32 value = static_cast<u32>(addr_info_node_cname.node->ai_family);
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const u32 value = static_cast<u32>(addr_info_node_cname.node->ai_socktype);
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const u32 value = static_cast<u32>(addr_info_node_cname.node->ai_protocol);
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const u32 value = static_cast<u32>(addr_info_node_cname.node->ai_addrlen);
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if (addr_info_node_cname.node->ai_addr == nullptr || addr_info_node_cname.node->ai_addrlen == 0) {
|
||||||
|
const u32 value = 0;
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
} else if (IsAfInet<T>(addr_info_node_cname.node->ai_family)) {
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), *reinterpret_cast<SockAddrInType<T> *>(addr_info_node_cname.node->ai_addr))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
} else if (IsAfInet6<T>(addr_info_node_cname.node->ai_family)) {
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), *reinterpret_cast<SockAddrIn6Type<T> *>(addr_info_node_cname.node->ai_addr))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), addr_info_node_cname.ai_canonname)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr_info_node_cname.node->ai_next == nullptr) {
|
||||||
|
const u32 value = 0;
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = cur - dst;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsAresAddrInfo<T>
|
||||||
|
ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, const T &in) {
|
||||||
|
ssize_t rc = -1;
|
||||||
|
u8 *cur = dst;
|
||||||
|
std::memset(dst, 0, dst_size);
|
||||||
|
|
||||||
|
const size_t required = DNSSerializer::SizeOf(in);
|
||||||
|
if ((rc = DNSSerializer::CheckToBufferArguments(cur, dst_size, required, __LINE__)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddrInfoNodeCname addr_info_node_cname;
|
||||||
|
const T *ares_addr_info = std::addressof(in);
|
||||||
|
if (ares_addr_info->cnames != nullptr) {
|
||||||
|
const struct ams::socket::ares_addrinfo_cname *ares_addr_info_cname;
|
||||||
|
for (ares_addr_info_cname = ares_addr_info->cnames; ares_addr_info_cname->next != nullptr; ares_addr_info_cname = ares_addr_info_cname->next) {
|
||||||
|
/* Do nothing. */
|
||||||
|
}
|
||||||
|
addr_info_node_cname.ai_canonname = ares_addr_info_cname->name;
|
||||||
|
} else {
|
||||||
|
addr_info_node_cname.ai_canonname = ares_addr_info->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (struct ams::socket::ares_addrinfo_node *ares_addr_info_node = ares_addr_info->nodes; ares_addr_info_node != nullptr; ares_addr_info_node = ares_addr_info_node->ai_next) {
|
||||||
|
addr_info_node_cname.node = ares_addr_info_node;
|
||||||
|
if ((rc = ToBufferInternalImpl(cur, dst_size, addr_info_node_cname)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_info_node_cname.ai_canonname = nullptr;
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = cur - dst;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsAresAddrInfoHints<T>
|
||||||
|
ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, const T &in) {
|
||||||
|
ssize_t rc = -1;
|
||||||
|
u8 *cur = dst;
|
||||||
|
|
||||||
|
const size_t required = DNSSerializer::SizeOf(in);
|
||||||
|
if (dst_size < required) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const u32 value = AresMagic;
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const u32 value = static_cast<u32>(in.ai_flags);
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const u32 value = static_cast<u32>(in.ai_family);
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const u32 value = static_cast<u32>(in.ai_socktype);
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const u32 value = static_cast<u32>(in.ai_protocol);
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsAresAddrInfoHints<T>
|
||||||
|
ssize_t FromBufferImpl(T &out, const u8 *src, size_t src_size) {
|
||||||
|
ssize_t rc = 0;
|
||||||
|
const u8 *cur = src;
|
||||||
|
|
||||||
|
const size_t required = DNSSerializer::SizeOf(out);
|
||||||
|
if (src_size < required) {
|
||||||
|
ams::socket::SetLastError(ams::socket::Errno::ENoSpc);
|
||||||
|
rc = -1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memset(std::addressof(out), 0, sizeof(out));
|
||||||
|
|
||||||
|
u32 tmp_value;
|
||||||
|
|
||||||
|
{
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
|
||||||
|
return rc;
|
||||||
|
} else if (tmp_value != AresMagic) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
out.ai_flags = static_cast<decltype(out.ai_flags)>(tmp_value);
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
out.ai_family = static_cast<decltype(out.ai_family)>(tmp_value);
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
out.ai_socktype = static_cast<decltype(out.ai_socktype)>(tmp_value);
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
out.ai_protocol = static_cast<decltype(out.ai_protocol)>(tmp_value);
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = cur - src;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> size_t DNSSerializer::SizeOf(const struct ams::socket::ares_addrinfo &in) {
|
||||||
|
return SizeOfImpl(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> size_t DNSSerializer::SizeOf(const struct ams::socket::ares_addrinfo_hints &in) {
|
||||||
|
return SizeOfImpl(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: DNSSerializer::FromBuffer doesn't exist for ares_addrinfo, only DNSSerializer::ToBuffer does. */
|
||||||
|
/* Official software pairs it with the old addrinfo DNSSerializer::FromBuffer instead. */
|
||||||
|
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct ams::socket::ares_addrinfo &in) {
|
||||||
|
return ToBufferImpl(dst, dst_size, in);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct ams::socket::ares_addrinfo_hints &in) {
|
||||||
|
return ToBufferImpl(dst, dst_size, in);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::FromBuffer(struct ams::socket::ares_addrinfo_hints &out, const u8 *src, size_t src_size) {
|
||||||
|
return FromBufferImpl(out, src, src_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -55,8 +55,9 @@ namespace ams::mitm::socket::resolver::serializer {
|
|||||||
rc += DNSSerializer::SizeOf((const char **)(in.h_aliases), dummy);
|
rc += DNSSerializer::SizeOf((const char **)(in.h_aliases), dummy);
|
||||||
rc += sizeof(u32);
|
rc += sizeof(u32);
|
||||||
rc += sizeof(u32);
|
rc += sizeof(u32);
|
||||||
rc += DNSSerializer::SizeOf((const InAddrType<T> **)(in.h_addr_list), dummy);
|
if (IsAfInet<T>(in.h_addrtype)) {
|
||||||
|
rc += DNSSerializer::SizeOf((const InAddrType<T> **)(in.h_addr_list), dummy);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +151,16 @@ namespace ams::mitm::socket::resolver::serializer {
|
|||||||
cur += rc;
|
cur += rc;
|
||||||
|
|
||||||
InAddrType<T> **addrs = nullptr;
|
InAddrType<T> **addrs = nullptr;
|
||||||
if ((rc = DNSSerializer::FromBuffer(addrs, cur, src_size - (cur - src))) == -1) {
|
if (IsAfInet<T>(out.h_addrtype)) {
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(addrs, cur, src_size - (cur - src))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
} else if (IsAfInet6<T>(out.h_addrtype)) {
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(addrs, cur, src_size - (cur - src))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
out.h_addr_list = (char **)addrs;
|
out.h_addr_list = (char **)addrs;
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ namespace ams::mitm::socket::resolver::serializer {
|
|||||||
|
|
||||||
out = static_cast<T **>(ams::socket::impl::Alloc((count + 1) * sizeof(T *)));
|
out = static_cast<T **>(ams::socket::impl::Alloc((count + 1) * sizeof(T *)));
|
||||||
if (out == nullptr) {
|
if (out == nullptr) {
|
||||||
|
ams::socket::SetLastError(ams::socket::Errno::ENoMem);
|
||||||
rc = -1;
|
rc = -1;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -167,6 +168,7 @@ namespace ams::mitm::socket::resolver::serializer {
|
|||||||
for (u32 i = 0; i < count; ++i) {
|
for (u32 i = 0; i < count; ++i) {
|
||||||
out[i] = static_cast<T *>(ams::socket::impl::Alloc(sizeof(T)));
|
out[i] = static_cast<T *>(ams::socket::impl::Alloc(sizeof(T)));
|
||||||
if (out[i] == nullptr) {
|
if (out[i] == nullptr) {
|
||||||
|
ams::socket::SetLastError(ams::socket::Errno::ENoMem);
|
||||||
rc = -1;
|
rc = -1;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace ams::mitm::socket::resolver::serializer {
|
|||||||
rc += sizeof(u16);
|
rc += sizeof(u16);
|
||||||
rc += sizeof(u16);
|
rc += sizeof(u16);
|
||||||
rc += sizeof(u32);
|
rc += sizeof(u32);
|
||||||
rc += DNSSerializer::SizeOf(in.sin6_addr);
|
rc += sizeof(in.sin6_addr); /* NOTE: There is no DNSSerializer::SizeOf for in6_addr. */
|
||||||
rc += sizeof(u32);
|
rc += sizeof(u32);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ namespace ams::mitm::socket::resolver::serializer {
|
|||||||
|
|
||||||
out = static_cast<char *>(ams::socket::impl::Alloc(len));
|
out = static_cast<char *>(ams::socket::impl::Alloc(len));
|
||||||
if (out == nullptr) {
|
if (out == nullptr) {
|
||||||
|
ams::socket::SetLastError(ams::socket::Errno::ENoMem);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,6 +153,7 @@ namespace ams::mitm::socket::resolver::serializer {
|
|||||||
|
|
||||||
out = static_cast<char **>(ams::socket::impl::Alloc((count + 1) * sizeof(char *)));
|
out = static_cast<char **>(ams::socket::impl::Alloc((count + 1) * sizeof(char *)));
|
||||||
if (out == nullptr) {
|
if (out == nullptr) {
|
||||||
|
ams::socket::SetLastError(ams::socket::Errno::ENoMem);
|
||||||
rc = -1;
|
rc = -1;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -162,6 +164,7 @@ namespace ams::mitm::socket::resolver::serializer {
|
|||||||
const size_t len = std::strlen(reinterpret_cast<const char *>(cur));
|
const size_t len = std::strlen(reinterpret_cast<const char *>(cur));
|
||||||
out[i] = static_cast<char *>(ams::socket::impl::Alloc(len + 1));
|
out[i] = static_cast<char *>(ams::socket::impl::Alloc(len + 1));
|
||||||
if (out[i] == nullptr) {
|
if (out[i] == nullptr) {
|
||||||
|
ams::socket::SetLastError(ams::socket::Errno::ENoMem);
|
||||||
rc = -1;
|
rc = -1;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,3 +95,106 @@ Result sfdnsresGetAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, cons
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result sfdnsresReportTelemetryFwd(Service *s, u64 process_id, const void *telemetry, size_t telemetry_size, u32 version) {
|
||||||
|
const struct {
|
||||||
|
u32 version;
|
||||||
|
u32 padding;
|
||||||
|
u64 process_id;
|
||||||
|
} in = { version, 0, process_id };
|
||||||
|
|
||||||
|
return serviceMitmDispatchIn(s, 16, in,
|
||||||
|
.buffer_attrs = {
|
||||||
|
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In
|
||||||
|
},
|
||||||
|
.buffers = {
|
||||||
|
{ telemetry, telemetry_size }
|
||||||
|
},
|
||||||
|
.in_send_pid = true,
|
||||||
|
.override_pid = process_id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result sfdnsresQueryAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, const void *node, size_t node_size, const void *srv, size_t srv_size, const void *hint, size_t hint_size, u32 *out_query_id, u32 fd, u32 options_version, const void *option, size_t option_size, u32 num_options, s32 *out_rv, s32 *out_errno) {
|
||||||
|
const struct {
|
||||||
|
u32 fd;
|
||||||
|
u32 options_version;
|
||||||
|
u32 num_options;
|
||||||
|
u32 padding;
|
||||||
|
u64 process_id;
|
||||||
|
} in = { fd, options_version, num_options, 0, process_id };
|
||||||
|
struct {
|
||||||
|
u32 query_id;
|
||||||
|
s32 rv;
|
||||||
|
s32 errno;
|
||||||
|
} out;
|
||||||
|
|
||||||
|
Result rc = serviceMitmDispatchInOut(s, 100, in, out,
|
||||||
|
.buffer_attrs = {
|
||||||
|
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In,
|
||||||
|
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In,
|
||||||
|
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In,
|
||||||
|
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In
|
||||||
|
},
|
||||||
|
.buffers = {
|
||||||
|
{ node, node_size },
|
||||||
|
{ srv, srv_size },
|
||||||
|
{ hint, hint_size },
|
||||||
|
{ option, option_size }
|
||||||
|
},
|
||||||
|
.in_send_pid = true,
|
||||||
|
.override_pid = process_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (out_query_id) *out_query_id = out.query_id;
|
||||||
|
if (out_rv) *out_rv = out.rv;
|
||||||
|
if (out_errno) *out_errno = out.errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result sfdnsresFetchAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, u32 query_id, u32 version, void *out_ai, size_t out_ai_size, u32 *out_size, s32 *out_rv, s32 *out_errno) {
|
||||||
|
const struct {
|
||||||
|
u32 query_id;
|
||||||
|
u32 version;
|
||||||
|
u64 process_id;
|
||||||
|
} in = { query_id, version, process_id };
|
||||||
|
struct {
|
||||||
|
u32 size;
|
||||||
|
s32 rv;
|
||||||
|
s32 errno;
|
||||||
|
} out;
|
||||||
|
|
||||||
|
Result rc = serviceMitmDispatchInOut(s, 102, in, out,
|
||||||
|
.buffer_attrs = {
|
||||||
|
SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out
|
||||||
|
},
|
||||||
|
.buffers = {
|
||||||
|
{ out_ai, out_ai_size }
|
||||||
|
},
|
||||||
|
.in_send_pid = true,
|
||||||
|
.override_pid = process_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (out_size) *out_size = out.size;
|
||||||
|
if (out_rv) *out_rv = out.rv;
|
||||||
|
if (out_errno) *out_errno = out.errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result sfdnsresCancelQueryFwd(Service *s, u64 process_id, u32 query_id) {
|
||||||
|
const struct {
|
||||||
|
u32 query_id;
|
||||||
|
u32 padding;
|
||||||
|
u64 process_id;
|
||||||
|
} in = { query_id, 0, process_id };
|
||||||
|
|
||||||
|
return serviceMitmDispatchIn(s, 104, in,
|
||||||
|
.in_send_pid = true,
|
||||||
|
.override_pid = process_id,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -16,6 +16,14 @@ Result sfdnsresGetHostByNameRequestWithOptionsFwd(Service *s, u64 process_id, co
|
|||||||
|
|
||||||
Result sfdnsresGetAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, const void *node, size_t node_size, const void *srv, size_t srv_size, const void *hint, size_t hint_size, void *out_ai, size_t out_ai_size, u32 *out_size, s32 *out_rv, u32 options_version, const void *option, size_t option_size, u32 num_options, s32 *out_host_error, s32 *out_errno);
|
Result sfdnsresGetAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, const void *node, size_t node_size, const void *srv, size_t srv_size, const void *hint, size_t hint_size, void *out_ai, size_t out_ai_size, u32 *out_size, s32 *out_rv, u32 options_version, const void *option, size_t option_size, u32 num_options, s32 *out_host_error, s32 *out_errno);
|
||||||
|
|
||||||
|
Result sfdnsresReportTelemetryFwd(Service *s, u64 process_id, const void *telemetry, size_t telemetry_size, u32 version);
|
||||||
|
|
||||||
|
Result sfdnsresQueryAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, const void *node, size_t node_size, const void *srv, size_t srv_size, const void *hint, size_t hint_size, u32 *out_query_id, u32 fd, u32 options_version, const void *option, size_t option_size, u32 num_options, s32 *out_rv, s32 *out_errno);
|
||||||
|
|
||||||
|
Result sfdnsresFetchAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, u32 query_id, u32 version, void *out_ai, size_t out_ai_size, u32 *out_size, s32 *out_rv, s32 *out_errno);
|
||||||
|
|
||||||
|
Result sfdnsresCancelQueryFwd(Service *s, u64 process_id, u32 query_id);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -67,6 +67,11 @@ namespace ams::mitm::fs {
|
|||||||
constexpr ALWAYS_INLINE auto MakeSharedStorage(Arguments &&... args) {
|
constexpr ALWAYS_INLINE auto MakeSharedStorage(Arguments &&... args) {
|
||||||
return sf::CreateSharedObjectEmplaced<ams::fssrv::sf::IStorage, ams::fssrv::impl::StorageInterfaceAdapter>(std::forward<Arguments>(args)...);
|
return sf::CreateSharedObjectEmplaced<ams::fssrv::sf::IStorage, ams::fssrv::impl::StorageInterfaceAdapter>(std::forward<Arguments>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename... Arguments>
|
||||||
|
constexpr ALWAYS_INLINE auto MakeSharedStorageForBatchRead(Arguments &&... args) {
|
||||||
|
return sf::CreateSharedObjectEmplaced<ams::fssrv::sf::IStorageForBatchRead, ams::fssrv::impl::StorageInterfaceAdapterForBatchRead>(std::forward<Arguments>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
Result OpenHblWebContentFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> &out, ncm::ProgramId program_id) {
|
Result OpenHblWebContentFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> &out, ncm::ProgramId program_id) {
|
||||||
/* Verify eligibility. */
|
/* Verify eligibility. */
|
||||||
@@ -94,7 +99,7 @@ namespace ams::mitm::fs {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpenProgramSpecificWebContentFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> &out, ncm::ProgramId program_id, FsFileSystemType filesystem_type, Service *fwd, const fssrv::sf::Path *path, bool with_id) {
|
Result OpenProgramSpecificWebContentFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> &out, ncm::ProgramId program_id, FsFileSystemType filesystem_type, Service *fwd, const fssrv::sf::Path *path, bool with_id, bool with_attributes) {
|
||||||
/* Directory must exist. */
|
/* Directory must exist. */
|
||||||
R_UNLESS(HasSdManualHtmlContent(program_id), sm::mitm::ResultShouldForwardToSession());
|
R_UNLESS(HasSdManualHtmlContent(program_id), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
@@ -121,8 +126,10 @@ namespace ams::mitm::fs {
|
|||||||
/* Try to open the existing fs. */
|
/* Try to open the existing fs. */
|
||||||
FsFileSystem base_fs;
|
FsFileSystem base_fs;
|
||||||
bool opened_base_fs = false;
|
bool opened_base_fs = false;
|
||||||
if (with_id) {
|
if (with_attributes) {
|
||||||
opened_base_fs = R_SUCCEEDED(fsOpenFileSystemWithIdFwd(fwd, std::addressof(base_fs), static_cast<u64>(program_id), filesystem_type, path->str));
|
opened_base_fs = R_SUCCEEDED(fsOpenFileSystemWithIdFwd(fwd, std::addressof(base_fs), path->str, FsContentAttributes_None, static_cast<u64>(program_id), filesystem_type));
|
||||||
|
} else if (with_id) {
|
||||||
|
opened_base_fs = R_SUCCEEDED(fsOpenFileSystemWithIdObsoleteFwd(fwd, std::addressof(base_fs), path->str, static_cast<u64>(program_id), filesystem_type));
|
||||||
} else {
|
} else {
|
||||||
opened_base_fs = R_SUCCEEDED(fsOpenFileSystemWithPatchFwd(fwd, std::addressof(base_fs), static_cast<u64>(program_id), filesystem_type));
|
opened_base_fs = R_SUCCEEDED(fsOpenFileSystemWithPatchFwd(fwd, std::addressof(base_fs), static_cast<u64>(program_id), filesystem_type));
|
||||||
}
|
}
|
||||||
@@ -141,7 +148,7 @@ namespace ams::mitm::fs {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpenWebContentFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> &out, ncm::ProgramId client_program_id, ncm::ProgramId program_id, FsFileSystemType filesystem_type, Service *fwd, const fssrv::sf::Path *path, bool with_id, bool try_program_specific) {
|
Result OpenWebContentFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> &out, ncm::ProgramId client_program_id, ncm::ProgramId program_id, FsFileSystemType filesystem_type, Service *fwd, const fssrv::sf::Path *path, bool with_id, bool with_attributes, bool try_program_specific) {
|
||||||
/* Check first that we're a web applet opening web content. */
|
/* Check first that we're a web applet opening web content. */
|
||||||
R_UNLESS(ncm::IsWebAppletId(client_program_id), sm::mitm::ResultShouldForwardToSession());
|
R_UNLESS(ncm::IsWebAppletId(client_program_id), sm::mitm::ResultShouldForwardToSession());
|
||||||
R_UNLESS(filesystem_type == FsFileSystemType_ContentManual, sm::mitm::ResultShouldForwardToSession());
|
R_UNLESS(filesystem_type == FsFileSystemType_ContentManual, sm::mitm::ResultShouldForwardToSession());
|
||||||
@@ -153,7 +160,7 @@ namespace ams::mitm::fs {
|
|||||||
R_UNLESS(try_program_specific, sm::mitm::ResultShouldForwardToSession());
|
R_UNLESS(try_program_specific, sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
/* If we're not opening a HBL filesystem, just try to open a generic one. */
|
/* If we're not opening a HBL filesystem, just try to open a generic one. */
|
||||||
R_RETURN(OpenProgramSpecificWebContentFileSystem(out, program_id, filesystem_type, fwd, path, with_id));
|
R_RETURN(OpenProgramSpecificWebContentFileSystem(out, program_id, filesystem_type, fwd, path, with_id, with_attributes));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -169,12 +176,17 @@ namespace ams::mitm::fs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FsMitmService::OpenFileSystemWithPatch(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 _filesystem_type) {
|
Result FsMitmService::OpenFileSystemWithPatch(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 file_system_proxy_type) {
|
||||||
R_RETURN(OpenWebContentFileSystem(out, m_client_info.program_id, program_id, static_cast<FsFileSystemType>(_filesystem_type), m_forward_service.get(), nullptr, false, m_client_info.override_status.IsProgramSpecific()));
|
R_RETURN(OpenWebContentFileSystem(out, m_client_info.program_id, program_id, static_cast<FsFileSystemType>(file_system_proxy_type), m_forward_service.get(), nullptr, false, false, m_client_info.override_status.IsProgramSpecific()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FsMitmService::OpenFileSystemWithId(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 _filesystem_type) {
|
Result FsMitmService::OpenFileSystemWithIdObsolete(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 file_system_proxy_type) {
|
||||||
R_RETURN(OpenWebContentFileSystem(out, m_client_info.program_id, program_id, static_cast<FsFileSystemType>(_filesystem_type), m_forward_service.get(), std::addressof(path), true, m_client_info.override_status.IsProgramSpecific()));
|
R_RETURN(OpenWebContentFileSystem(out, m_client_info.program_id, program_id, static_cast<FsFileSystemType>(file_system_proxy_type), m_forward_service.get(), std::addressof(path), true, false, m_client_info.override_status.IsProgramSpecific()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FsMitmService::OpenFileSystemWithId(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, const fssrv::sf::Path &path, u8 content_attributes, ncm::ProgramId program_id, u32 file_system_proxy_type) {
|
||||||
|
AMS_UNUSED(content_attributes);
|
||||||
|
R_RETURN(OpenWebContentFileSystem(out, m_client_info.program_id, program_id, static_cast<FsFileSystemType>(file_system_proxy_type), m_forward_service.get(), std::addressof(path), true, true, m_client_info.override_status.IsProgramSpecific()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FsMitmService::OpenSdCardFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out) {
|
Result FsMitmService::OpenSdCardFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out) {
|
||||||
@@ -195,7 +207,7 @@ namespace ams::mitm::fs {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FsMitmService::OpenSaveDataFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, u8 _space_id, const fs::SaveDataAttribute &attribute) {
|
Result FsMitmService::OpenSaveDataFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute) {
|
||||||
/* We only want to intercept saves for games, right now. */
|
/* We only want to intercept saves for games, right now. */
|
||||||
const bool is_game_or_hbl = m_client_info.override_status.IsHbl() || ncm::IsApplicationId(m_client_info.program_id);
|
const bool is_game_or_hbl = m_client_info.override_status.IsHbl() || ncm::IsApplicationId(m_client_info.program_id);
|
||||||
R_UNLESS(is_game_or_hbl, sm::mitm::ResultShouldForwardToSession());
|
R_UNLESS(is_game_or_hbl, sm::mitm::ResultShouldForwardToSession());
|
||||||
@@ -210,12 +222,12 @@ namespace ams::mitm::fs {
|
|||||||
R_UNLESS(attribute.type == fs::SaveDataType::Account, sm::mitm::ResultShouldForwardToSession());
|
R_UNLESS(attribute.type == fs::SaveDataType::Account, sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
/* Get enum type for space id. */
|
/* Get enum type for space id. */
|
||||||
auto space_id = static_cast<FsSaveDataSpaceId>(_space_id);
|
auto _space_id = static_cast<FsSaveDataSpaceId>(space_id);
|
||||||
|
|
||||||
/* Verify we can open the save. */
|
/* Verify we can open the save. */
|
||||||
static_assert(sizeof(fs::SaveDataAttribute) == sizeof(::FsSaveDataAttribute));
|
static_assert(sizeof(fs::SaveDataAttribute) == sizeof(::FsSaveDataAttribute));
|
||||||
FsFileSystem save_fs;
|
FsFileSystem save_fs;
|
||||||
R_UNLESS(R_SUCCEEDED(fsOpenSaveDataFileSystemFwd(m_forward_service.get(), std::addressof(save_fs), space_id, reinterpret_cast<const FsSaveDataAttribute *>(std::addressof(attribute)))), sm::mitm::ResultShouldForwardToSession());
|
R_UNLESS(R_SUCCEEDED(fsOpenSaveDataFileSystemFwd(m_forward_service.get(), std::addressof(save_fs), _space_id, reinterpret_cast<const FsSaveDataAttribute *>(std::addressof(attribute)))), sm::mitm::ResultShouldForwardToSession());
|
||||||
std::unique_ptr<fs::fsa::IFileSystem> save_ifs = std::make_unique<fs::RemoteFileSystem>(save_fs);
|
std::unique_ptr<fs::fsa::IFileSystem> save_ifs = std::make_unique<fs::RemoteFileSystem>(save_fs);
|
||||||
|
|
||||||
/* Mount the SD card using fs.mitm's session. */
|
/* Mount the SD card using fs.mitm's session. */
|
||||||
@@ -228,7 +240,7 @@ namespace ams::mitm::fs {
|
|||||||
const ncm::ProgramId application_id = attribute.program_id == ncm::InvalidProgramId ? m_client_info.program_id : attribute.program_id;
|
const ncm::ProgramId application_id = attribute.program_id == ncm::InvalidProgramId ? m_client_info.program_id : attribute.program_id;
|
||||||
|
|
||||||
char save_dir_raw_path[0x100];
|
char save_dir_raw_path[0x100];
|
||||||
R_TRY(mitm::fs::SaveUtil::GetDirectorySaveDataPath(save_dir_raw_path, sizeof(save_dir_raw_path), application_id, space_id, attribute));
|
R_TRY(mitm::fs::SaveUtil::GetDirectorySaveDataPath(save_dir_raw_path, sizeof(save_dir_raw_path), application_id, _space_id, attribute));
|
||||||
|
|
||||||
ams::fs::Path save_dir_path;
|
ams::fs::Path save_dir_path;
|
||||||
R_TRY(save_dir_path.SetShallowBuffer(save_dir_raw_path));
|
R_TRY(save_dir_path.SetShallowBuffer(save_dir_raw_path));
|
||||||
@@ -270,12 +282,12 @@ namespace ams::mitm::fs {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FsMitmService::OpenBisStorage(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, u32 _bis_partition_id) {
|
Result FsMitmService::OpenBisStorage(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, u32 bis_partition_id) {
|
||||||
const ::FsBisPartitionId bis_partition_id = static_cast<::FsBisPartitionId>(_bis_partition_id);
|
const ::FsBisPartitionId _bis_partition_id = static_cast<::FsBisPartitionId>(bis_partition_id);
|
||||||
|
|
||||||
/* Try to open a storage for the partition. */
|
/* Try to open a storage for the partition. */
|
||||||
FsStorage bis_storage;
|
FsStorage bis_storage;
|
||||||
R_TRY(fsOpenBisStorageFwd(m_forward_service.get(), std::addressof(bis_storage), bis_partition_id));
|
R_TRY(fsOpenBisStorageFwd(m_forward_service.get(), std::addressof(bis_storage), _bis_partition_id));
|
||||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(bis_storage.s))};
|
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(bis_storage.s))};
|
||||||
|
|
||||||
const bool is_sysmodule = ncm::IsSystemProgramId(m_client_info.program_id);
|
const bool is_sysmodule = ncm::IsSystemProgramId(m_client_info.program_id);
|
||||||
@@ -285,18 +297,18 @@ namespace ams::mitm::fs {
|
|||||||
/* Allow HBL to write to boot1 (safe firm) + package2. */
|
/* 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. */
|
/* 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 :/ */
|
/* 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_package2 = (FsBisPartitionId_BootConfigAndPackage2Part1 <= _bis_partition_id && _bis_partition_id <= FsBisPartitionId_BootConfigAndPackage2Part6);
|
||||||
const bool is_boot1 = bis_partition_id == FsBisPartitionId_BootPartition2Root;
|
const bool is_boot1 = _bis_partition_id == FsBisPartitionId_BootPartition2Root;
|
||||||
const bool can_write_bis_for_choi_support = is_hbl && (is_package2 || is_boot1);
|
const bool can_write_bis_for_choi_support = is_hbl && (is_package2 || is_boot1);
|
||||||
|
|
||||||
/* Set output storage. */
|
/* Set output storage. */
|
||||||
if (bis_partition_id == FsBisPartitionId_BootPartition1Root) {
|
if (_bis_partition_id == FsBisPartitionId_BootPartition1Root) {
|
||||||
if (IsBoot0CustomPublicKey(bis_storage)) {
|
if (IsBoot0CustomPublicKey(bis_storage)) {
|
||||||
out.SetValue(MakeSharedStorage(std::make_shared<CustomPublicKeyBoot0Storage>(bis_storage, m_client_info, spl::GetSocType())), target_object_id);
|
out.SetValue(MakeSharedStorage(std::make_shared<CustomPublicKeyBoot0Storage>(bis_storage, m_client_info, spl::GetSocType())), target_object_id);
|
||||||
} else {
|
} else {
|
||||||
out.SetValue(MakeSharedStorage(std::make_shared<Boot0Storage>(bis_storage, m_client_info)), target_object_id);
|
out.SetValue(MakeSharedStorage(std::make_shared<Boot0Storage>(bis_storage, m_client_info)), target_object_id);
|
||||||
}
|
}
|
||||||
} else if (bis_partition_id == FsBisPartitionId_CalibrationBinary) {
|
} else if (_bis_partition_id == FsBisPartitionId_CalibrationBinary) {
|
||||||
out.SetValue(MakeSharedStorage(std::make_shared<CalibrationBinaryStorage>(bis_storage, m_client_info)), target_object_id);
|
out.SetValue(MakeSharedStorage(std::make_shared<CalibrationBinaryStorage>(bis_storage, m_client_info)), target_object_id);
|
||||||
} else {
|
} else {
|
||||||
if (can_write_bis || can_write_bis_for_choi_support) {
|
if (can_write_bis || can_write_bis_for_choi_support) {
|
||||||
@@ -328,24 +340,41 @@ namespace ams::mitm::fs {
|
|||||||
out.SetValue(MakeSharedStorage(GetLayeredRomfsStorage(m_client_info.program_id, data_storage, true)), target_object_id);
|
out.SetValue(MakeSharedStorage(GetLayeredRomfsStorage(m_client_info.program_id, data_storage, true)), target_object_id);
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result FsMitmService::OpenDataStorageByProgramId(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, ncm::ProgramId program_id) {
|
||||||
|
/* Only mitm if we should override contents for the current process. */
|
||||||
|
R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
Result FsMitmService::OpenDataStorageByDataId(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, ncm::DataId _data_id, u8 storage_id) {
|
/* Only mitm if there is actually an override romfs for the target program. */
|
||||||
|
R_UNLESS(mitm::fs::HasSdRomfsContent(program_id), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
|
/* Try to open the program romfs. */
|
||||||
|
FsStorage data_storage;
|
||||||
|
R_TRY(fsOpenDataStorageByProgramIdFwd(m_forward_service.get(), std::addressof(data_storage), static_cast<u64>(program_id)));
|
||||||
|
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))};
|
||||||
|
|
||||||
|
/* Get a layered storage for the program romfs. */
|
||||||
|
out.SetValue(MakeSharedStorage(GetLayeredRomfsStorage(program_id, data_storage, true)), target_object_id);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FsMitmService::OpenDataStorageByDataId(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, ncm::DataId data_id, u8 storage_id) {
|
||||||
/* Only mitm if we should override contents for the current process. */
|
/* Only mitm if we should override contents for the current process. */
|
||||||
R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
/* TODO: Decide how to handle DataId vs ProgramId for this API. */
|
/* TODO: Decide how to handle DataId vs ProgramId for this API. */
|
||||||
const ncm::ProgramId data_id = {_data_id.value};
|
const ncm::ProgramId program_or_data_id = {data_id.value};
|
||||||
|
|
||||||
/* Only mitm if there is actually an override romfs. */
|
/* Only mitm if there is actually an override romfs. */
|
||||||
R_UNLESS(mitm::fs::HasSdRomfsContent(data_id), sm::mitm::ResultShouldForwardToSession());
|
R_UNLESS(mitm::fs::HasSdRomfsContent(program_or_data_id), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
/* Try to open the data id. */
|
/* Try to open the data id. */
|
||||||
FsStorage data_storage;
|
FsStorage data_storage;
|
||||||
R_TRY(fsOpenDataStorageByDataIdFwd(m_forward_service.get(), std::addressof(data_storage), static_cast<u64>(data_id), static_cast<NcmStorageId>(storage_id)));
|
R_TRY(fsOpenDataStorageByDataIdFwd(m_forward_service.get(), std::addressof(data_storage), static_cast<u64>(program_or_data_id), static_cast<NcmStorageId>(storage_id)));
|
||||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))};
|
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))};
|
||||||
|
|
||||||
/* Get a layered storage for the data id. */
|
/* Get a layered storage for the data id. */
|
||||||
out.SetValue(MakeSharedStorage(GetLayeredRomfsStorage(data_id, data_storage, false)), target_object_id);
|
out.SetValue(MakeSharedStorage(GetLayeredRomfsStorage(program_or_data_id, data_storage, false)), target_object_id);
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,7 +398,80 @@ namespace ams::mitm::fs {
|
|||||||
out.SetValue(MakeSharedStorage(GetLayeredRomfsStorage(program_id, data_storage, true)), target_object_id);
|
out.SetValue(MakeSharedStorage(GetLayeredRomfsStorage(program_id, data_storage, true)), target_object_id);
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result FsMitmService::OpenDataStorageByPath(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, const fssrv::sf::Path &path, u8 content_attributes, u32 file_system_proxy_type) {
|
||||||
|
/* Only mitm if we should override contents for the current process. */
|
||||||
|
R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
AMS_UNUSED(out, path, content_attributes, file_system_proxy_type);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FsMitmService::OpenDataStorageByCurrentProcessForBatchRead(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorageForBatchRead>> out) {
|
||||||
|
/* Only mitm if we should override contents for the current process. */
|
||||||
|
R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
|
/* Only mitm if there is actually an override romfs. */
|
||||||
|
R_UNLESS(mitm::fs::HasSdRomfsContent(m_client_info.program_id), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
|
/* Try to open the process romfs. */
|
||||||
|
FsStorageForBatchRead data_storage;
|
||||||
|
R_TRY(fsOpenDataStorageByCurrentProcessForBatchReadFwd(m_forward_service.get(), std::addressof(data_storage)));
|
||||||
|
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))};
|
||||||
|
|
||||||
|
/* Get a layered storage for the program romfs (batch read variant). */
|
||||||
|
out.SetValue(MakeSharedStorageForBatchRead(GetLayeredRomfsStorageForBatchRead(m_client_info.program_id, data_storage, true)), target_object_id);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FsMitmService::OpenDataStorageByProgramIdForBatchRead(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorageForBatchRead>> out, ncm::ProgramId program_id) {
|
||||||
|
/* Only mitm if we should override contents for the current process. */
|
||||||
|
R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
|
/* Only mitm if there is actually an override romfs for the target program. */
|
||||||
|
R_UNLESS(mitm::fs::HasSdRomfsContent(program_id), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
|
/* Try to open the program romfs. */
|
||||||
|
FsStorageForBatchRead data_storage;
|
||||||
|
R_TRY(fsOpenDataStorageByProgramIdForBatchReadFwd(m_forward_service.get(), std::addressof(data_storage), static_cast<u64>(program_id)));
|
||||||
|
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))};
|
||||||
|
|
||||||
|
/* Get a layered storage for the program romfs (batch read variant). */
|
||||||
|
out.SetValue(MakeSharedStorageForBatchRead(GetLayeredRomfsStorageForBatchRead(program_id, data_storage, true)), target_object_id);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FsMitmService::OpenDataStorageWithProgramIndexForBatchRead(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorageForBatchRead>> out, u8 program_index) {
|
||||||
|
/* Only mitm if we should override contents for the current process. */
|
||||||
|
R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
|
/* Get the relevant program id. */
|
||||||
|
const ncm::ProgramId program_id = g_program_index_map_info_manager.GetProgramId(m_client_info.program_id, program_index);
|
||||||
|
|
||||||
|
/* If we don't know about the program or don't have content, forward. */
|
||||||
|
R_UNLESS(program_id != ncm::InvalidProgramId, sm::mitm::ResultShouldForwardToSession());
|
||||||
|
R_UNLESS(mitm::fs::HasSdRomfsContent(program_id), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
|
/* Try to open the process romfs. */
|
||||||
|
FsStorageForBatchRead data_storage;
|
||||||
|
R_TRY(fsOpenDataStorageWithProgramIndexForBatchReadFwd(m_forward_service.get(), std::addressof(data_storage), program_index));
|
||||||
|
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))};
|
||||||
|
|
||||||
|
/* Get a layered storage for the program romfs (batch read variant). */
|
||||||
|
out.SetValue(MakeSharedStorageForBatchRead(GetLayeredRomfsStorageForBatchRead(program_id, data_storage, true)), target_object_id);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FsMitmService::OpenDataStorageByPathForBatchRead(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorageForBatchRead>> out, const fssrv::sf::Path &path, u8 content_attributes, u32 file_system_proxy_type) {
|
||||||
|
/* Only mitm if we should override contents for the current process. */
|
||||||
|
R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
AMS_UNUSED(out, path, content_attributes, file_system_proxy_type);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
Result FsMitmService::RegisterProgramIndexMapInfo(const sf::InBuffer &info_buffer, s32 info_count) {
|
Result FsMitmService::RegisterProgramIndexMapInfo(const sf::InBuffer &info_buffer, s32 info_count) {
|
||||||
/* Try to register with FS. */
|
/* Try to register with FS. */
|
||||||
R_TRY(fsRegisterProgramIndexMapInfoFwd(m_forward_service.get(), info_buffer.GetPointer(), info_buffer.GetSize(), info_count));
|
R_TRY(fsRegisterProgramIndexMapInfoFwd(m_forward_service.get(), info_buffer.GetPointer(), info_buffer.GetSize(), info_count));
|
||||||
|
|||||||
@@ -17,16 +17,23 @@
|
|||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include <stratosphere/fssrv/fssrv_interface_adapters.hpp>
|
#include <stratosphere/fssrv/fssrv_interface_adapters.hpp>
|
||||||
|
|
||||||
#define AMS_FS_MITM_INTERFACE_INFO(C, H) \
|
#define AMS_FS_MITM_INTERFACE_INFO(C, H) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 7, Result, OpenFileSystemWithPatch, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 _filesystem_type), (out, program_id, _filesystem_type), hos::Version_2_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 7, Result, OpenFileSystemWithPatch, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 file_system_proxy_type), (out, program_id, file_system_proxy_type), hos::Version_2_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithId, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 _filesystem_type), (out, path, program_id, _filesystem_type), hos::Version_2_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithIdObsolete, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 file_system_proxy_type), (out, path, program_id, file_system_proxy_type), hos::Version_2_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 18, Result, OpenSdCardFileSystem, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out), (out)) \
|
AMS_SF_METHOD_INFO(C, H, 10, Result, OpenFileSystemWithId, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, const fssrv::sf::Path &path, u8 content_attributes, ncm::ProgramId program_id, u32 file_system_proxy_type), (out, path, content_attributes, program_id, file_system_proxy_type), hos::Version_16_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 51, Result, OpenSaveDataFileSystem, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, u8 space_id, const ams::fs::SaveDataAttribute &attribute), (out, space_id, attribute)) \
|
AMS_SF_METHOD_INFO(C, H, 18, Result, OpenSdCardFileSystem, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out), (out)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 12, Result, OpenBisStorage, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, u32 bis_partition_id), (out, bis_partition_id)) \
|
AMS_SF_METHOD_INFO(C, H, 51, Result, OpenSaveDataFileSystem, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, u8 space_id, const ams::fs::SaveDataAttribute &attribute), (out, space_id, attribute)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 200, Result, OpenDataStorageByCurrentProcess, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out), (out)) \
|
AMS_SF_METHOD_INFO(C, H, 12, Result, OpenBisStorage, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, u32 bis_partition_id), (out, bis_partition_id)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 202, Result, OpenDataStorageByDataId, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, ncm::DataId data_id, u8 storage_id), (out, data_id, storage_id)) \
|
AMS_SF_METHOD_INFO(C, H, 200, Result, OpenDataStorageByCurrentProcess, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out), (out)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 205, Result, OpenDataStorageWithProgramIndex, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, u8 program_index), (out, program_index), hos::Version_7_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 201, Result, OpenDataStorageByProgramId, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, ncm::ProgramId program_id), (out, program_id), hos::Version_3_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 810, Result, RegisterProgramIndexMapInfo, (const sf::InBuffer &info_buffer, s32 info_count), (info_buffer, info_count), hos::Version_7_0_0)
|
AMS_SF_METHOD_INFO(C, H, 202, Result, OpenDataStorageByDataId, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, ncm::DataId data_id, u8 storage_id), (out, data_id, storage_id)) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 205, Result, OpenDataStorageWithProgramIndex, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, u8 program_index), (out, program_index), hos::Version_7_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 206, Result, OpenDataStorageByPath, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, const fssrv::sf::Path &path, u8 content_attributes, u32 file_system_proxy_type), (out, path, content_attributes, file_system_proxy_type), hos::Version_13_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 210, Result, OpenDataStorageByCurrentProcessForBatchRead, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorageForBatchRead>> out), (out), hos::Version_23_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 211, Result, OpenDataStorageByProgramIdForBatchRead, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorageForBatchRead>> out, ncm::ProgramId program_id), (out, program_id), hos::Version_23_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 212, Result, OpenDataStorageWithProgramIndexForBatchRead, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorageForBatchRead>> out, u8 program_index), (out, program_index), hos::Version_23_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 213, Result, OpenDataStorageByPathForBatchRead, (sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorageForBatchRead>> out, const fssrv::sf::Path &path, u8 content_attributes, u32 file_system_proxy_type), (out, path, content_attributes, file_system_proxy_type), hos::Version_23_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 810, Result, RegisterProgramIndexMapInfo, (const sf::InBuffer &info_buffer, s32 info_count), (info_buffer, info_count), hos::Version_7_0_0)
|
||||||
|
|
||||||
|
|
||||||
AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::fs, IFsMitmInterface, AMS_FS_MITM_INTERFACE_INFO, 0x7DF34ED2)
|
AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::fs, IFsMitmInterface, AMS_FS_MITM_INTERFACE_INFO, 0x7DF34ED2)
|
||||||
@@ -77,14 +84,21 @@ namespace ams::mitm::fs {
|
|||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
/* Overridden commands. */
|
/* Overridden commands. */
|
||||||
Result OpenFileSystemWithPatch(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 _filesystem_type);
|
Result OpenFileSystemWithPatch(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 file_system_proxy_type);
|
||||||
Result OpenFileSystemWithId(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 _filesystem_type);
|
Result OpenFileSystemWithIdObsolete(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 file_system_proxy_type);
|
||||||
|
Result OpenFileSystemWithId(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, const fssrv::sf::Path &path, u8 content_attributes, ncm::ProgramId program_id, u32 file_system_proxy_type);
|
||||||
Result OpenSdCardFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out);
|
Result OpenSdCardFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out);
|
||||||
Result OpenSaveDataFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, u8 space_id, const ams::fs::SaveDataAttribute &attribute);
|
Result OpenSaveDataFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, u8 space_id, const ams::fs::SaveDataAttribute &attribute);
|
||||||
Result OpenBisStorage(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, u32 bis_partition_id);
|
Result OpenBisStorage(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, u32 bis_partition_id);
|
||||||
Result OpenDataStorageByCurrentProcess(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out);
|
Result OpenDataStorageByCurrentProcess(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out);
|
||||||
|
Result OpenDataStorageByProgramId(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, ncm::ProgramId program_id);
|
||||||
Result OpenDataStorageByDataId(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, ncm::DataId data_id, u8 storage_id);
|
Result OpenDataStorageByDataId(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, ncm::DataId data_id, u8 storage_id);
|
||||||
Result OpenDataStorageWithProgramIndex(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, u8 program_index);
|
Result OpenDataStorageWithProgramIndex(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, u8 program_index);
|
||||||
|
Result OpenDataStorageByPath(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, const fssrv::sf::Path &path, u8 content_attributes, u32 file_system_proxy_type);
|
||||||
|
Result OpenDataStorageByCurrentProcessForBatchRead(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorageForBatchRead>> out);
|
||||||
|
Result OpenDataStorageByProgramIdForBatchRead(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorageForBatchRead>> out, ncm::ProgramId program_id);
|
||||||
|
Result OpenDataStorageWithProgramIndexForBatchRead(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorageForBatchRead>> out, u8 program_index);
|
||||||
|
Result OpenDataStorageByPathForBatchRead(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorageForBatchRead>> out, const fssrv::sf::Path &path, u8 content_attributes, u32 file_system_proxy_type);
|
||||||
Result RegisterProgramIndexMapInfo(const sf::InBuffer &info_buffer, s32 info_count);
|
Result RegisterProgramIndexMapInfo(const sf::InBuffer &info_buffer, s32 info_count);
|
||||||
};
|
};
|
||||||
static_assert(IsIFsMitmInterface<FsMitmService>);
|
static_assert(IsIFsMitmInterface<FsMitmService>);
|
||||||
|
|||||||
@@ -23,8 +23,46 @@ static Result _fsOpenSession(Service *s, Service* out, u32 cmd_id) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result fsOpenSdCardFileSystemFwd(Service* s, FsFileSystem* out) {
|
Result fsOpenFileSystemWithPatchFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType) {
|
||||||
return _fsOpenSession(s, &out->s, 18);
|
const struct {
|
||||||
|
u32 fsType;
|
||||||
|
u64 id;
|
||||||
|
} in = { fsType, id };
|
||||||
|
|
||||||
|
return serviceDispatchIn(s, 7, in,
|
||||||
|
.out_num_objects = 1,
|
||||||
|
.out_objects = &out->s
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result fsOpenFileSystemWithIdObsoleteFwd(Service* s, FsFileSystem* out, const char* contentPath, u64 id, FsFileSystemType fsType) {
|
||||||
|
const struct {
|
||||||
|
u32 fsType;
|
||||||
|
u64 id;
|
||||||
|
} in = { fsType, id };
|
||||||
|
|
||||||
|
return serviceDispatchIn(s, 8, in,
|
||||||
|
.buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcPointer | SfBufferAttr_FixedSize },
|
||||||
|
.buffers = { { contentPath, FS_MAX_PATH } },
|
||||||
|
.out_num_objects = 1,
|
||||||
|
.out_objects = &out->s
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result fsOpenFileSystemWithIdFwd(Service* s, FsFileSystem* out, const char* contentPath, FsContentAttributes attributes, u64 id, FsFileSystemType fsType) {
|
||||||
|
const struct {
|
||||||
|
u8 attributes;
|
||||||
|
u8 pad[3];
|
||||||
|
u32 fsType;
|
||||||
|
u64 id;
|
||||||
|
} in = { attributes, {0}, fsType, id };
|
||||||
|
|
||||||
|
return serviceDispatchIn(s, 10, in,
|
||||||
|
.buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcPointer | SfBufferAttr_FixedSize },
|
||||||
|
.buffers = { { contentPath, FS_MAX_PATH } },
|
||||||
|
.out_num_objects = 1,
|
||||||
|
.out_objects = &out->s
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result fsOpenBisStorageFwd(Service* s, FsStorage* out, FsBisPartitionId partition_id) {
|
Result fsOpenBisStorageFwd(Service* s, FsStorage* out, FsBisPartitionId partition_id) {
|
||||||
@@ -35,10 +73,34 @@ Result fsOpenBisStorageFwd(Service* s, FsStorage* out, FsBisPartitionId partitio
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result fsOpenSdCardFileSystemFwd(Service* s, FsFileSystem* out) {
|
||||||
|
return _fsOpenSession(s, &out->s, 18);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result fsOpenSaveDataFileSystemFwd(Service* s, FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr) {
|
||||||
|
const struct {
|
||||||
|
u8 save_data_space_id;
|
||||||
|
u8 pad[7];
|
||||||
|
FsSaveDataAttribute attr;
|
||||||
|
} in = { (u8)save_data_space_id, {0}, *attr };
|
||||||
|
|
||||||
|
return serviceDispatchIn(s, 51, in,
|
||||||
|
.out_num_objects = 1,
|
||||||
|
.out_objects = &out->s,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out) {
|
Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out) {
|
||||||
return _fsOpenSession(s, &out->s, 200);
|
return _fsOpenSession(s, &out->s, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result fsOpenDataStorageByProgramIdFwd(Service* s, FsStorage* out, u64 id) {
|
||||||
|
return serviceDispatchIn(s, 201, id,
|
||||||
|
.out_num_objects = 1,
|
||||||
|
.out_objects = &out->s,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorage* out, u64 data_id, NcmStorageId storage_id) {
|
Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorage* out, u64 data_id, NcmStorageId storage_id) {
|
||||||
const struct {
|
const struct {
|
||||||
u8 storage_id;
|
u8 storage_id;
|
||||||
@@ -58,48 +120,57 @@ Result fsOpenDataStorageWithProgramIndexFwd(Service* s, FsStorage* out, u8 progr
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result fsRegisterProgramIndexMapInfoFwd(Service* s, const void *buf, size_t buf_size, s32 count) {
|
Result fsOpenDataStorageByPathFwd(Service* s, FsStorage* out, const char* contentPath, FsContentAttributes attributes, FsFileSystemType fsType) {
|
||||||
return serviceDispatchIn(s, 810, count,
|
const struct {
|
||||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
|
u8 attributes;
|
||||||
.buffers = { { buf, buf_size } },
|
u8 pad[3];
|
||||||
|
u32 fsType;
|
||||||
|
} in = { attributes, {0}, fsType };
|
||||||
|
|
||||||
|
return serviceDispatchIn(s, 206, in,
|
||||||
|
.buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcPointer | SfBufferAttr_FixedSize },
|
||||||
|
.buffers = { { contentPath, FS_MAX_PATH } },
|
||||||
|
.out_num_objects = 1,
|
||||||
|
.out_objects = &out->s
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result fsOpenSaveDataFileSystemFwd(Service* s, FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr) {
|
Result fsOpenDataStorageByCurrentProcessForBatchReadFwd(Service* s, FsStorageForBatchRead* out) {
|
||||||
const struct {
|
return _fsOpenSession(s, &out->s, 210);
|
||||||
u8 save_data_space_id;
|
}
|
||||||
u8 pad[7];
|
|
||||||
FsSaveDataAttribute attr;
|
|
||||||
} in = { (u8)save_data_space_id, {0}, *attr };
|
|
||||||
|
|
||||||
return serviceDispatchIn(s, 51, in,
|
Result fsOpenDataStorageByProgramIdForBatchReadFwd(Service* s, FsStorageForBatchRead* out, u64 id) {
|
||||||
|
return serviceDispatchIn(s, 211, id,
|
||||||
.out_num_objects = 1,
|
.out_num_objects = 1,
|
||||||
.out_objects = &out->s,
|
.out_objects = &out->s,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result fsOpenFileSystemWithPatchFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType) {
|
Result fsOpenDataStorageWithProgramIndexForBatchReadFwd(Service* s, FsStorageForBatchRead* out, u8 program_index) {
|
||||||
const struct {
|
return serviceDispatchIn(s, 212, program_index,
|
||||||
u32 fsType;
|
.out_num_objects = 1,
|
||||||
u64 id;
|
.out_objects = &out->s,
|
||||||
} in = { fsType, id };
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return serviceDispatchIn(s, 7, in,
|
Result fsOpenDataStorageByPathForBatchReadFwd(Service* s, FsStorageForBatchRead* out, const char* contentPath, FsContentAttributes attributes, FsFileSystemType fsType) {
|
||||||
|
const struct {
|
||||||
|
u8 attributes;
|
||||||
|
u8 pad[3];
|
||||||
|
u32 fsType;
|
||||||
|
} in = { attributes, {0}, fsType };
|
||||||
|
|
||||||
|
return serviceDispatchIn(s, 213, in,
|
||||||
|
.buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcPointer | SfBufferAttr_FixedSize },
|
||||||
|
.buffers = { { contentPath, FS_MAX_PATH } },
|
||||||
.out_num_objects = 1,
|
.out_num_objects = 1,
|
||||||
.out_objects = &out->s
|
.out_objects = &out->s
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result fsOpenFileSystemWithIdFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType, const char* contentPath) {
|
Result fsRegisterProgramIndexMapInfoFwd(Service* s, const void *buf, size_t buf_size, s32 count) {
|
||||||
const struct {
|
return serviceDispatchIn(s, 810, count,
|
||||||
u32 fsType;
|
.buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias },
|
||||||
u64 id;
|
.buffers = { { buf, buf_size } },
|
||||||
} in = { fsType, id };
|
|
||||||
|
|
||||||
return serviceDispatchIn(s, 8, in,
|
|
||||||
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
|
|
||||||
.buffers = { { contentPath, FS_MAX_PATH } },
|
|
||||||
.out_num_objects = 1,
|
|
||||||
.out_objects = &out->s
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,18 +12,26 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Missing fsp-srv commands. */
|
/* Missing fsp-srv commands. */
|
||||||
Result fsOpenSdCardFileSystemFwd(Service* s, FsFileSystem* out);
|
Result fsOpenFileSystemWithPatchFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType);
|
||||||
|
Result fsOpenFileSystemWithIdObsoleteFwd(Service* s, FsFileSystem* out, const char* contentPath, u64 id, FsFileSystemType fsType);
|
||||||
|
Result fsOpenFileSystemWithIdFwd(Service* s, FsFileSystem* out, const char* contentPath, FsContentAttributes attributes, u64 id, FsFileSystemType fsType);
|
||||||
|
|
||||||
Result fsOpenBisStorageFwd(Service* s, FsStorage* out, FsBisPartitionId partition_id);
|
Result fsOpenBisStorageFwd(Service* s, FsStorage* out, FsBisPartitionId partition_id);
|
||||||
Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out);
|
Result fsOpenSdCardFileSystemFwd(Service* s, FsFileSystem* out);
|
||||||
Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorage* out, u64 data_id, NcmStorageId storage_id);
|
|
||||||
Result fsOpenDataStorageWithProgramIndexFwd(Service* s, FsStorage* out, u8 program_index);
|
|
||||||
|
|
||||||
Result fsRegisterProgramIndexMapInfoFwd(Service* s, const void *buf, size_t buf_size, s32 count);
|
|
||||||
|
|
||||||
Result fsOpenSaveDataFileSystemFwd(Service* s, FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr);
|
Result fsOpenSaveDataFileSystemFwd(Service* s, FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr);
|
||||||
|
|
||||||
Result fsOpenFileSystemWithPatchFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType);
|
Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out);
|
||||||
Result fsOpenFileSystemWithIdFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType, const char* contentPath);
|
Result fsOpenDataStorageByProgramIdFwd(Service* s, FsStorage* out, u64 id);
|
||||||
|
Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorage* out, u64 data_id, NcmStorageId storage_id);
|
||||||
|
Result fsOpenDataStorageWithProgramIndexFwd(Service* s, FsStorage* out, u8 program_index);
|
||||||
|
Result fsOpenDataStorageByPathFwd(Service* s, FsStorage* out, const char* contentPath, FsContentAttributes attributes, FsFileSystemType fsType);
|
||||||
|
|
||||||
|
Result fsOpenDataStorageByCurrentProcessForBatchReadFwd(Service* s, FsStorageForBatchRead* out);
|
||||||
|
Result fsOpenDataStorageByProgramIdForBatchReadFwd(Service* s, FsStorageForBatchRead* out, u64 id);
|
||||||
|
Result fsOpenDataStorageWithProgramIndexForBatchReadFwd(Service* s, FsStorageForBatchRead* out, u8 program_index);
|
||||||
|
Result fsOpenDataStorageByPathForBatchReadFwd(Service* s, FsStorageForBatchRead* out, const char* contentPath, FsContentAttributes attributes, FsFileSystemType fsType);
|
||||||
|
|
||||||
|
Result fsRegisterProgramIndexMapInfoFwd(Service* s, const void *buf, size_t buf_size, s32 count);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -180,33 +180,79 @@ namespace ams::mitm::fs {
|
|||||||
CloseReference(m_impl);
|
CloseReference(m_impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
||||||
R_RETURN(m_impl->Read(offset, buffer, size));
|
R_RETURN(m_impl->Read(offset, buffer, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
||||||
|
/* TODO: Better result code? */
|
||||||
|
AMS_UNUSED(offset, buffer, size);
|
||||||
|
R_THROW(ams::fs::ResultUnsupportedOperation())
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result Flush() override {
|
||||||
|
R_RETURN(m_impl->Flush());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result SetSize(s64 size) override {
|
||||||
|
/* TODO: Better result code? */
|
||||||
|
AMS_UNUSED(size);
|
||||||
|
R_THROW(ams::fs::ResultUnsupportedOperation())
|
||||||
|
}
|
||||||
|
|
||||||
virtual Result GetSize(s64 *out_size) override {
|
virtual Result GetSize(s64 *out_size) override {
|
||||||
R_RETURN(m_impl->GetSize(out_size));
|
R_RETURN(m_impl->GetSize(out_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Result OperateRange(void *dst, size_t dst_size, ams::fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
|
||||||
|
R_RETURN(m_impl->OperateRange(dst, dst_size, op_id, offset, size, src, src_size));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class LayeredRomfsStorageForBatchRead : public ams::fs::IStorageForBatchRead {
|
||||||
|
private:
|
||||||
|
LayeredRomfsStorageImpl *m_impl;
|
||||||
|
public:
|
||||||
|
LayeredRomfsStorageForBatchRead(LayeredRomfsStorageImpl *impl) : m_impl(impl) {
|
||||||
|
OpenReference(m_impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~LayeredRomfsStorageForBatchRead() {
|
||||||
|
CloseReference(m_impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
||||||
|
R_RETURN(m_impl->Read(offset, buffer, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
||||||
|
/* TODO: Better result code? */
|
||||||
|
AMS_UNUSED(offset, buffer, size);
|
||||||
|
R_THROW(ams::fs::ResultUnsupportedOperation())
|
||||||
|
}
|
||||||
|
|
||||||
virtual Result Flush() override {
|
virtual Result Flush() override {
|
||||||
R_RETURN(m_impl->Flush());
|
R_RETURN(m_impl->Flush());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Result SetSize(s64 size) override {
|
||||||
|
/* TODO: Better result code? */
|
||||||
|
AMS_UNUSED(size);
|
||||||
|
R_THROW(ams::fs::ResultUnsupportedOperation())
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result GetSize(s64 *out_size) override {
|
||||||
|
R_RETURN(m_impl->GetSize(out_size));
|
||||||
|
}
|
||||||
|
|
||||||
virtual Result OperateRange(void *dst, size_t dst_size, ams::fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
|
virtual Result OperateRange(void *dst, size_t dst_size, ams::fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
|
||||||
R_RETURN(m_impl->OperateRange(dst, dst_size, op_id, offset, size, src, src_size));
|
R_RETURN(m_impl->OperateRange(dst, dst_size, op_id, offset, size, src, src_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
virtual Result BatchRead(void *out0, void *out1, void *out2, void *out3, void *out4, void *out5, void *out6, const void *in) override {
|
||||||
/* TODO: Better result code? */
|
/* TODO */
|
||||||
AMS_UNUSED(offset, buffer, size);
|
AMS_UNUSED(out0, out1, out2, out3, out4, out5, out6, in);
|
||||||
R_THROW(ams::fs::ResultUnsupportedOperation())
|
R_THROW(ams::fs::ResultUnsupportedOperation());
|
||||||
}
|
|
||||||
|
|
||||||
virtual Result SetSize(s64 size) override {
|
|
||||||
/* TODO: Better result code? */
|
|
||||||
AMS_UNUSED(size);
|
|
||||||
R_THROW(ams::fs::ResultUnsupportedOperation())
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -261,6 +307,54 @@ namespace ams::mitm::fs {
|
|||||||
/* Return a new shared storage for the impl. */
|
/* Return a new shared storage for the impl. */
|
||||||
return std::make_shared<LayeredRomfsStorage>(impl);
|
return std::make_shared<LayeredRomfsStorage>(impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ams::fs::IStorageForBatchRead> GetLayeredRomfsStorageForBatchRead(ncm::ProgramId program_id, ::FsStorageForBatchRead &data_storage, bool is_process_romfs) {
|
||||||
|
/*Prepare to find or create a new storage. */
|
||||||
|
LayeredRomfsStorageImpl *impl = nullptr;
|
||||||
|
{
|
||||||
|
std::scoped_lock lk(g_storage_set_mutex);
|
||||||
|
|
||||||
|
/* Find an existing storage. */
|
||||||
|
if (auto it = g_storage_set.find_key(program_id.value); it != g_storage_set.end()) {
|
||||||
|
return std::make_shared<LayeredRomfsStorageForBatchRead>(it->GetImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We don't have an existing storage. If we're creating process romfs, free any unreferenced process romfs. */
|
||||||
|
/* This should help prevent too much memory in use at any time. */
|
||||||
|
if (is_process_romfs) {
|
||||||
|
auto it = g_storage_set.begin();
|
||||||
|
while (it != g_storage_set.end()) {
|
||||||
|
if (it->GetReferenceCount() > 0 || !it->IsProcessRomfs()) {
|
||||||
|
++it;
|
||||||
|
} else {
|
||||||
|
auto *holder = std::addressof(*it);
|
||||||
|
it = g_storage_set.erase(it);
|
||||||
|
delete holder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a new storage. */
|
||||||
|
{
|
||||||
|
::FsFile data_file;
|
||||||
|
if (R_SUCCEEDED(OpenAtmosphereSdFile(std::addressof(data_file), program_id, "romfs.bin", OpenMode_Read))) {
|
||||||
|
impl = new LayeredRomfsStorageImpl(std::make_unique<ReadOnlyStorageAdapterForBatchRead>(new RemoteStorageForBatchRead(data_storage)), std::make_unique<ReadOnlyStorageAdapterForBatchRead>(new FileStorage(new RemoteFile(data_file))), program_id);
|
||||||
|
} else {
|
||||||
|
impl = new LayeredRomfsStorageImpl(std::make_unique<ReadOnlyStorageAdapterForBatchRead>(new RemoteStorageForBatchRead(data_storage)), nullptr, program_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert holder. Reference count will now be one. */
|
||||||
|
g_storage_set.insert(*(new LayeredRomfsStorageHolder(impl, is_process_romfs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Begin initialization. When this finishes, a decref will occur. */
|
||||||
|
AMS_ABORT_UNLESS(impl != nullptr);
|
||||||
|
impl->BeginInitialize();
|
||||||
|
|
||||||
|
/* Return a new shared storage for the impl. */
|
||||||
|
return std::make_shared<LayeredRomfsStorageForBatchRead>(impl);
|
||||||
|
}
|
||||||
|
|
||||||
void FinalizeLayeredRomfsStorage(ncm::ProgramId program_id) {
|
void FinalizeLayeredRomfsStorage(ncm::ProgramId program_id) {
|
||||||
std::scoped_lock lk(g_initialization_mutex);
|
std::scoped_lock lk(g_initialization_mutex);
|
||||||
@@ -392,6 +486,10 @@ namespace ams::mitm::fs {
|
|||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result LayeredRomfsStorageImpl::Flush() {
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
Result LayeredRomfsStorageImpl::GetSize(s64 *out_size) {
|
Result LayeredRomfsStorageImpl::GetSize(s64 *out_size) {
|
||||||
/* Ensure we're initialized. */
|
/* Ensure we're initialized. */
|
||||||
@@ -403,10 +501,6 @@ namespace ams::mitm::fs {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LayeredRomfsStorageImpl::Flush() {
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result LayeredRomfsStorageImpl::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
|
Result LayeredRomfsStorageImpl::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
|
||||||
AMS_UNUSED(offset, src, src_size);
|
AMS_UNUSED(offset, src, src_size);
|
||||||
|
|
||||||
|
|||||||
@@ -44,13 +44,13 @@ namespace ams::mitm::fs {
|
|||||||
constexpr ncm::ProgramId GetProgramId() const { return m_program_id; }
|
constexpr ncm::ProgramId GetProgramId() const { return m_program_id; }
|
||||||
|
|
||||||
Result Read(s64 offset, void *buffer, size_t size);
|
Result Read(s64 offset, void *buffer, size_t size);
|
||||||
Result GetSize(s64 *out_size);
|
|
||||||
Result Flush();
|
Result Flush();
|
||||||
|
Result GetSize(s64 *out_size);
|
||||||
Result OperateRange(void *dst, size_t dst_size, ams::fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size);
|
Result OperateRange(void *dst, size_t dst_size, ams::fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<ams::fs::IStorage> GetLayeredRomfsStorage(ncm::ProgramId program_id, ::FsStorage &data_storage, bool is_process_romfs);
|
std::shared_ptr<ams::fs::IStorage> GetLayeredRomfsStorage(ncm::ProgramId program_id, ::FsStorage &data_storage, bool is_process_romfs);
|
||||||
|
std::shared_ptr<ams::fs::IStorageForBatchRead> GetLayeredRomfsStorageForBatchRead(ncm::ProgramId program_id, ::FsStorageForBatchRead &data_storage, bool is_process_romfs);
|
||||||
void FinalizeLayeredRomfsStorage(ncm::ProgramId program_id);
|
void FinalizeLayeredRomfsStorage(ncm::ProgramId program_id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,11 @@ namespace ams::mitm::fs {
|
|||||||
/* Unknown heap sensitivity. */
|
/* Unknown heap sensitivity. */
|
||||||
{ 0x01002C9022770000, 16_MB, 0_MB },
|
{ 0x01002C9022770000, 16_MB, 0_MB },
|
||||||
|
|
||||||
|
/* Trails in the Sky 2nd Chapter. */
|
||||||
|
/* Requirement ~16 MB.*/
|
||||||
|
/* No particular heap sensitivity. */
|
||||||
|
{ 0x01007A2027548000, 8_MB, 0_MB },
|
||||||
|
|
||||||
/* STAR WARS: Knights of the Old Republic II: The Sith Lords. */
|
/* STAR WARS: Knights of the Old Republic II: The Sith Lords. */
|
||||||
/* Requirement ? MB. 16 MB stolen heap fixes a crash, though. */
|
/* Requirement ? MB. 16 MB stolen heap fixes a crash, though. */
|
||||||
/* Unknown heap sensitivity. */
|
/* Unknown heap sensitivity. */
|
||||||
@@ -469,7 +474,7 @@ namespace ams::mitm::fs {
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Entry>
|
template<typename Entry>
|
||||||
class TableWriter : public DynamicTableCache {
|
class TableWriter : public DynamicTableCache {
|
||||||
NON_COPYABLE(TableWriter);
|
NON_COPYABLE(TableWriter);
|
||||||
@@ -722,12 +727,12 @@ namespace ams::mitm::fs {
|
|||||||
public:
|
public:
|
||||||
DirectoryTableReader(ams::fs::IStorage *s, size_t ofs, size_t sz) : TableReader(s, ofs, sz) { /* ... */ }
|
DirectoryTableReader(ams::fs::IStorage *s, size_t ofs, size_t sz) : TableReader(s, ofs, sz) { /* ... */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileTableReader : public TableReader<FileEntry> {
|
class FileTableReader : public TableReader<FileEntry> {
|
||||||
public:
|
public:
|
||||||
FileTableReader(ams::fs::IStorage *s, size_t ofs, size_t sz) : TableReader(s, ofs, sz) { /* ... */ }
|
FileTableReader(ams::fs::IStorage *s, size_t ofs, size_t sz) : TableReader(s, ofs, sz) { /* ... */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
void Builder::VisitDirectory(BuildDirectoryContext *parent, u32 parent_offset, DirectoryTableReader &dir_table, FileTableReader &file_table) {
|
void Builder::VisitDirectory(BuildDirectoryContext *parent, u32 parent_offset, DirectoryTableReader &dir_table, FileTableReader &file_table) {
|
||||||
const DirectoryEntry *parent_entry = dir_table.GetEntry(parent_offset);
|
const DirectoryEntry *parent_entry = dir_table.GetEntry(parent_offset);
|
||||||
if (AMS_UNLIKELY(parent_entry == nullptr)) {
|
if (AMS_UNLIKELY(parent_entry == nullptr)) {
|
||||||
@@ -768,8 +773,7 @@ namespace ams::mitm::fs {
|
|||||||
cur_child_offset = next_child_offset;
|
cur_child_offset = next_child_offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Builder::AddSdFiles() {
|
void Builder::AddSdFiles() {
|
||||||
/* Open Sd Card filesystem. */
|
/* Open Sd Card filesystem. */
|
||||||
FsFileSystem sd_filesystem;
|
FsFileSystem sd_filesystem;
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ namespace ams::mitm::fs::romfs {
|
|||||||
private:
|
private:
|
||||||
void VisitDirectory(FsFileSystem *fs, BuildDirectoryContext *parent);
|
void VisitDirectory(FsFileSystem *fs, BuildDirectoryContext *parent);
|
||||||
void VisitDirectory(BuildDirectoryContext *parent, u32 parent_offset, DirectoryTableReader &dir_table, FileTableReader &file_table);
|
void VisitDirectory(BuildDirectoryContext *parent, u32 parent_offset, DirectoryTableReader &dir_table, FileTableReader &file_table);
|
||||||
|
|
||||||
void AddDirectory(BuildDirectoryContext **out, BuildDirectoryContext *parent_ctx, std::unique_ptr<BuildDirectoryContext> file_ctx);
|
void AddDirectory(BuildDirectoryContext **out, BuildDirectoryContext *parent_ctx, std::unique_ptr<BuildDirectoryContext> file_ctx);
|
||||||
void AddFile(BuildDirectoryContext *parent_ctx, std::unique_ptr<BuildFileContext> file_ctx);
|
void AddFile(BuildDirectoryContext *parent_ctx, std::unique_ptr<BuildFileContext> file_ctx);
|
||||||
public:
|
public:
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -347,7 +347,7 @@ namespace dbk {
|
|||||||
|
|
||||||
/* Copy result text if there is a result. */
|
/* Copy result text if there is a result. */
|
||||||
if (R_FAILED(rc)) {
|
if (R_FAILED(rc)) {
|
||||||
snprintf(m_result_text, sizeof(m_result_text), "Result: 0x%08x", rc);
|
snprintf(m_result_text, sizeof(m_result_text), "Ergebnis: 0x%08x", rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,7 +375,7 @@ namespace dbk {
|
|||||||
const float button_width = WindowWidth - HorizontalInset * 2.0f;
|
const float button_width = WindowWidth - HorizontalInset * 2.0f;
|
||||||
|
|
||||||
/* Add buttons. */
|
/* Add buttons. */
|
||||||
this->AddButton(ExitButtonId, "Exit", x + HorizontalInset, button_y, button_width, ButtonHeight);
|
this->AddButton(ExitButtonId, "Beenden", x + HorizontalInset, button_y, button_width, ButtonHeight);
|
||||||
this->SetButtonSelected(ExitButtonId, true);
|
this->SetButtonSelected(ExitButtonId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,8 +412,8 @@ namespace dbk {
|
|||||||
|
|
||||||
const float button_y = y + TitleGap + SubTextHeight + VerticalGap * 2.0f + (R_FAILED(m_rc) ? SubTextHeight : 0.0f);
|
const float button_y = y + TitleGap + SubTextHeight + VerticalGap * 2.0f + (R_FAILED(m_rc) ? SubTextHeight : 0.0f);
|
||||||
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
|
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
|
||||||
this->AddButton(BackButtonId, "Back", x + HorizontalInset, button_y, button_width, ButtonHeight);
|
this->AddButton(BackButtonId, "Zurück", x + HorizontalInset, button_y, button_width, ButtonHeight);
|
||||||
this->AddButton(ContinueButtonId, "Continue", x + HorizontalInset + button_width + ButtonHorizontalGap, button_y, button_width, ButtonHeight);
|
this->AddButton(ContinueButtonId, "Weiter", x + HorizontalInset + button_width + ButtonHorizontalGap, button_y, button_width, ButtonHeight);
|
||||||
this->SetButtonSelected(ContinueButtonId, true);
|
this->SetButtonSelected(ContinueButtonId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,8 +450,8 @@ namespace dbk {
|
|||||||
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
||||||
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
||||||
|
|
||||||
this->AddButton(InstallButtonId, "Install", x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2, ButtonHeight);
|
this->AddButton(InstallButtonId, "Installieren", x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2, ButtonHeight);
|
||||||
this->AddButton(ExitButtonId, "Exit", x + HorizontalInset, y + TitleGap + ButtonHeight + VerticalGap, WindowWidth - HorizontalInset * 2, ButtonHeight);
|
this->AddButton(ExitButtonId, "Beenden", x + HorizontalInset, y + TitleGap + ButtonHeight + VerticalGap, WindowWidth - HorizontalInset * 2, ButtonHeight);
|
||||||
this->SetButtonSelected(InstallButtonId, true);
|
this->SetButtonSelected(InstallButtonId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,24 +475,24 @@ namespace dbk {
|
|||||||
u64 is_emummc;
|
u64 is_emummc;
|
||||||
|
|
||||||
if (R_FAILED(rc = splGetConfig(SplConfigItem_HardwareType, &hardware_type))) {
|
if (R_FAILED(rc = splGetConfig(SplConfigItem_HardwareType, &hardware_type))) {
|
||||||
ChangeMenu(std::make_shared<ErrorMenu>("An error has occurred", "Failed to get hardware type.", rc));
|
ChangeMenu(std::make_shared<ErrorMenu>("Ein Fehler ist aufgetreten", "Hardwaretyp konnte nicht ermittelt werden.", rc));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereHasRcmBugPatch), &has_rcm_bug_patch))) {
|
if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereHasRcmBugPatch), &has_rcm_bug_patch))) {
|
||||||
ChangeMenu(std::make_shared<ErrorMenu>("An error has occurred", "Failed to check RCM bug status.", rc));
|
ChangeMenu(std::make_shared<ErrorMenu>("Ein Fehler ist aufgetreten", "RCM-Bug-Status konnte nicht geprüft werden.", rc));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereEmummcType), &is_emummc))) {
|
if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereEmummcType), &is_emummc))) {
|
||||||
ChangeMenu(std::make_shared<ErrorMenu>("An error has occurred", "Failed to check emuMMC status.", rc));
|
ChangeMenu(std::make_shared<ErrorMenu>("Ein Fehler ist aufgetreten", "emuMMC-Status konnte nicht geprüft werden.", rc));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Warn if we're working with a patched unit. */
|
/* Warn if we're working with a patched unit. */
|
||||||
const bool is_erista = hardware_type == 0 || hardware_type == 1;
|
const bool is_erista = hardware_type == 0 || hardware_type == 1;
|
||||||
if (is_erista && has_rcm_bug_patch && !is_emummc) {
|
if (is_erista && has_rcm_bug_patch && !is_emummc) {
|
||||||
ChangeMenu(std::make_shared<WarningMenu>(g_current_menu, file_menu, "Warning: Patched unit detected", "You may burn fuses or render your switch inoperable."));
|
ChangeMenu(std::make_shared<WarningMenu>(g_current_menu, file_menu, "Warnung: Gepatchte Konsole erkannt", "Sicherungen können durchgebrannt werden oder die Konsole unbrauchbar gemacht werden."));
|
||||||
} else {
|
} else {
|
||||||
ChangeMenu(file_menu);
|
ChangeMenu(file_menu);
|
||||||
}
|
}
|
||||||
@@ -739,7 +739,7 @@ namespace dbk {
|
|||||||
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
||||||
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
||||||
|
|
||||||
DrawWindow(vg, "Select an update directory", x, y, WindowWidth, WindowHeight);
|
DrawWindow(vg, "Update-Ordner auswählen", x, y, WindowWidth, WindowHeight);
|
||||||
DrawTextBackground(vg, x + TextBackgroundOffset, y + TitleGap, WindowWidth - TextBackgroundOffset * 2.0f, (FileRowHeight + FileRowGap) * MaxFileRows + FileRowGap);
|
DrawTextBackground(vg, x + TextBackgroundOffset, y + TitleGap, WindowWidth - TextBackgroundOffset * 2.0f, (FileRowHeight + FileRowGap) * MaxFileRows + FileRowGap);
|
||||||
|
|
||||||
nvgSave(vg);
|
nvgSave(vg);
|
||||||
@@ -765,8 +765,8 @@ namespace dbk {
|
|||||||
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
|
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
|
||||||
|
|
||||||
/* Add buttons. */
|
/* Add buttons. */
|
||||||
this->AddButton(BackButtonId, "Back", x + HorizontalInset, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight);
|
this->AddButton(BackButtonId, "Zurück", x + HorizontalInset, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight);
|
||||||
this->AddButton(ContinueButtonId, "Continue", x + HorizontalInset + button_width + ButtonHorizontalGap, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight);
|
this->AddButton(ContinueButtonId, "Weiter", x + HorizontalInset + button_width + ButtonHorizontalGap, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight);
|
||||||
this->SetButtonEnabled(BackButtonId, false);
|
this->SetButtonEnabled(BackButtonId, false);
|
||||||
this->SetButtonEnabled(ContinueButtonId, false);
|
this->SetButtonEnabled(ContinueButtonId, false);
|
||||||
|
|
||||||
@@ -776,20 +776,20 @@ namespace dbk {
|
|||||||
this->SetButtonSelected(BackButtonId, true);
|
this->SetButtonSelected(BackButtonId, true);
|
||||||
} else {
|
} else {
|
||||||
/* Log this early so it is printed out before validation causes stalling. */
|
/* Log this early so it is printed out before validation causes stalling. */
|
||||||
this->LogText("Validating update, this may take a moment...\n");
|
this->LogText("Update wird geprüft, bitte warten...\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ValidateUpdateMenu::GetUpdateInformation() {
|
Result ValidateUpdateMenu::GetUpdateInformation() {
|
||||||
Result rc = 0;
|
Result rc = 0;
|
||||||
this->LogText("Directory %s\n", g_update_path);
|
this->LogText("Verzeichnis %s\n", g_update_path);
|
||||||
|
|
||||||
/* Attempt to get the update information. */
|
/* Attempt to get the update information. */
|
||||||
if (R_FAILED(rc = amssuGetUpdateInformation(&m_update_info, g_update_path))) {
|
if (R_FAILED(rc = amssuGetUpdateInformation(&m_update_info, g_update_path))) {
|
||||||
if (rc == 0x1a405) {
|
if (rc == 0x1a405) {
|
||||||
this->LogText("No update found in folder.\nEnsure your ncas are named correctly!\nResult: 0x%08x\n", rc);
|
this->LogText("Kein Update im Ordner gefunden.\nStelle sicher, dass die NCAs korrekt benannt sind!\nErgebnis: 0x%08x\n", rc);
|
||||||
} else {
|
} else {
|
||||||
this->LogText("Failed to get update information.\nResult: 0x%08x\n", rc);
|
this->LogText("Update-Informationen konnten nicht abgerufen werden.\nErgebnis: 0x%08x\n", rc);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -797,11 +797,11 @@ namespace dbk {
|
|||||||
/* Print update information. */
|
/* Print update information. */
|
||||||
this->LogText("- Version: %d.%d.%d\n", (m_update_info.version >> 26) & 0x1f, (m_update_info.version >> 20) & 0x1f, (m_update_info.version >> 16) & 0xf);
|
this->LogText("- Version: %d.%d.%d\n", (m_update_info.version >> 26) & 0x1f, (m_update_info.version >> 20) & 0x1f, (m_update_info.version >> 16) & 0xf);
|
||||||
if (m_update_info.exfat_supported) {
|
if (m_update_info.exfat_supported) {
|
||||||
this->LogText("- exFAT: Supported\n");
|
this->LogText("- exFAT: Unterstützt\n");
|
||||||
} else {
|
} else {
|
||||||
this->LogText("- exFAT: Unsupported\n");
|
this->LogText("- exFAT: Nicht unterstützt\n");
|
||||||
}
|
}
|
||||||
this->LogText("- Firmware variations: %d\n", m_update_info.num_firmware_variations);
|
this->LogText("- Firmware-Varianten: %d\n", m_update_info.num_firmware_variations);
|
||||||
|
|
||||||
/* Mark as having obtained update info. */
|
/* Mark as having obtained update info. */
|
||||||
m_has_info = true;
|
m_has_info = true;
|
||||||
@@ -813,21 +813,21 @@ namespace dbk {
|
|||||||
|
|
||||||
/* Validate the update. */
|
/* Validate the update. */
|
||||||
if (R_FAILED(rc = amssuValidateUpdate(&m_validation_info, g_update_path))) {
|
if (R_FAILED(rc = amssuValidateUpdate(&m_validation_info, g_update_path))) {
|
||||||
this->LogText("Failed to validate update.\nResult: 0x%08x\n", rc);
|
this->LogText("Update konnte nicht validiert werden.\nErgebnis: 0x%08x\n", rc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the result. */
|
/* Check the result. */
|
||||||
if (R_SUCCEEDED(m_validation_info.result)) {
|
if (R_SUCCEEDED(m_validation_info.result)) {
|
||||||
this->LogText("Update is valid!\n");
|
this->LogText("Update ist gültig!\n");
|
||||||
|
|
||||||
if (R_FAILED(m_validation_info.exfat_result)) {
|
if (R_FAILED(m_validation_info.exfat_result)) {
|
||||||
const u32 version = m_validation_info.invalid_key.version;
|
const u32 version = m_validation_info.invalid_key.version;
|
||||||
this->LogText("exFAT Validation failed with result: 0x%08x\n", m_validation_info.exfat_result);
|
this->LogText("exFAT-Validierung fehlgeschlagen, Ergebnis: 0x%08x\n", m_validation_info.exfat_result);
|
||||||
this->LogText("Missing content:\n- Program id: %016lx\n- Version: %d.%d.%d\n", m_validation_info.invalid_key.id, (version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf);
|
this->LogText("Fehlender Inhalt:\n- Programm-ID: %016lx\n- Version: %d.%d.%d\n", m_validation_info.invalid_key.id, (version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf);
|
||||||
|
|
||||||
/* Log the missing content id. */
|
/* Log the missing content id. */
|
||||||
this->LogText("- Content id: ");
|
this->LogText("- Inhalts-ID: ");
|
||||||
for (size_t i = 0; i < sizeof(NcmContentId); i++) {
|
for (size_t i = 0; i < sizeof(NcmContentId); i++) {
|
||||||
this->LogText("%02x", m_validation_info.invalid_content_id.c[i]);
|
this->LogText("%02x", m_validation_info.invalid_content_id.c[i]);
|
||||||
}
|
}
|
||||||
@@ -841,11 +841,11 @@ namespace dbk {
|
|||||||
} else {
|
} else {
|
||||||
/* Log the missing content info. */
|
/* Log the missing content info. */
|
||||||
const u32 version = m_validation_info.invalid_key.version;
|
const u32 version = m_validation_info.invalid_key.version;
|
||||||
this->LogText("Validation failed with result: 0x%08x\n", m_validation_info.result);
|
this->LogText("Validierung fehlgeschlagen, Ergebnis: 0x%08x\n", m_validation_info.result);
|
||||||
this->LogText("Missing content:\n- Program id: %016lx\n- Version: %d.%d.%d\n", m_validation_info.invalid_key.id, (version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf);
|
this->LogText("Fehlender Inhalt:\n- Programm-ID: %016lx\n- Version: %d.%d.%d\n", m_validation_info.invalid_key.id, (version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf);
|
||||||
|
|
||||||
/* Log the missing content id. */
|
/* Log the missing content id. */
|
||||||
this->LogText("- Content id: ");
|
this->LogText("- Inhalts-ID: ");
|
||||||
for (size_t i = 0; i < sizeof(NcmContentId); i++) {
|
for (size_t i = 0; i < sizeof(NcmContentId); i++) {
|
||||||
this->LogText("%02x", m_validation_info.invalid_content_id.c[i]);
|
this->LogText("%02x", m_validation_info.invalid_content_id.c[i]);
|
||||||
}
|
}
|
||||||
@@ -897,13 +897,13 @@ namespace dbk {
|
|||||||
|
|
||||||
/* Warn the user if they're updating with exFAT supposed to be supported but not present/corrupted. */
|
/* Warn the user if they're updating with exFAT supposed to be supported but not present/corrupted. */
|
||||||
if (m_update_info.exfat_supported && R_FAILED(m_validation_info.exfat_result)) {
|
if (m_update_info.exfat_supported && R_FAILED(m_validation_info.exfat_result)) {
|
||||||
next_menu = std::make_shared<WarningMenu>(g_current_menu, next_menu, "Warning: exFAT firmware is missing or corrupt", "Are you sure you want to proceed?");
|
next_menu = std::make_shared<WarningMenu>(g_current_menu, next_menu, "Warnung: exFAT-Firmware fehlt oder ist beschädigt", "Möchtest du wirklich fortfahren?");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Warn the user if they're updating to a version higher than supported. */
|
/* Warn the user if they're updating to a version higher than supported. */
|
||||||
const u32 version = m_validation_info.invalid_key.version;
|
const u32 version = m_validation_info.invalid_key.version;
|
||||||
if (EncodeVersion((version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf) > g_supported_version) {
|
if (EncodeVersion((version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf) > g_supported_version) {
|
||||||
next_menu = std::make_shared<WarningMenu>(g_current_menu, next_menu, "Warning: firmware is too new and not known to be supported", "Are you sure you want to proceed?");
|
next_menu = std::make_shared<WarningMenu>(g_current_menu, next_menu, "Warnung: Firmware ist zu neu und nicht als unterstützt bekannt", "Möchtest du wirklich fortfahren?");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Change to the next menu. */
|
/* Change to the next menu. */
|
||||||
@@ -919,7 +919,7 @@ namespace dbk {
|
|||||||
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
||||||
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
||||||
|
|
||||||
DrawWindow(vg, "Update information", x, y, WindowWidth, WindowHeight);
|
DrawWindow(vg, "Update-Informationen", x, y, WindowWidth, WindowHeight);
|
||||||
DrawTextBackground(vg, x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2.0f, TextAreaHeight);
|
DrawTextBackground(vg, x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2.0f, TextAreaHeight);
|
||||||
DrawTextBlock(vg, m_log_buffer, x + HorizontalInset + TextHorizontalInset, y + TitleGap + TextVerticalInset, WindowWidth - (HorizontalInset + TextHorizontalInset) * 2.0f, TextAreaHeight - TextVerticalInset * 2.0f);
|
DrawTextBlock(vg, m_log_buffer, x + HorizontalInset + TextHorizontalInset, y + TitleGap + TextVerticalInset, WindowWidth - (HorizontalInset + TextHorizontalInset) * 2.0f, TextAreaHeight - TextVerticalInset * 2.0f);
|
||||||
|
|
||||||
@@ -933,8 +933,8 @@ namespace dbk {
|
|||||||
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
|
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
|
||||||
|
|
||||||
/* Add buttons. */
|
/* Add buttons. */
|
||||||
this->AddButton(ResetToFactorySettingsButtonId, "Reset to factory settings", x + HorizontalInset, y + TitleGap, button_width, ButtonHeight);
|
this->AddButton(ResetToFactorySettingsButtonId, "Werkseinstellungen", x + HorizontalInset, y + TitleGap, button_width, ButtonHeight);
|
||||||
this->AddButton(PreserveSettingsButtonId, "Preserve settings", x + HorizontalInset + button_width + ButtonHorizontalGap, y + TitleGap, button_width, ButtonHeight);
|
this->AddButton(PreserveSettingsButtonId, "Einstellungen behalten", x + HorizontalInset + button_width + ButtonHorizontalGap, y + TitleGap, button_width, ButtonHeight);
|
||||||
this->SetButtonSelected(PreserveSettingsButtonId, true);
|
this->SetButtonSelected(PreserveSettingsButtonId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -963,11 +963,11 @@ namespace dbk {
|
|||||||
if (g_exfat_supported) {
|
if (g_exfat_supported) {
|
||||||
next_menu = std::make_shared<ChooseExfatMenu>(g_current_menu);
|
next_menu = std::make_shared<ChooseExfatMenu>(g_current_menu);
|
||||||
} else {
|
} else {
|
||||||
next_menu = std::make_shared<WarningMenu>(g_current_menu, std::make_shared<InstallUpdateMenu>(g_current_menu), "Ready to begin update installation", "Are you sure you want to proceed?");
|
next_menu = std::make_shared<WarningMenu>(g_current_menu, std::make_shared<InstallUpdateMenu>(g_current_menu), "Bereit zur Update-Installation", "Möchtest du wirklich fortfahren?");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_reset_to_factory) {
|
if (g_reset_to_factory) {
|
||||||
ChangeMenu(std::make_shared<WarningMenu>(g_current_menu, next_menu, "Warning: Factory reset selected", "Saves and installed games will be permanently deleted."));
|
ChangeMenu(std::make_shared<WarningMenu>(g_current_menu, next_menu, "Warnung: Werkseinstellungen ausgewählt", "Spielstände und installierte Spiele werden dauerhaft gelöscht."));
|
||||||
} else {
|
} else {
|
||||||
ChangeMenu(next_menu);
|
ChangeMenu(next_menu);
|
||||||
}
|
}
|
||||||
@@ -985,7 +985,7 @@ namespace dbk {
|
|||||||
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
||||||
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
||||||
|
|
||||||
DrawWindow(vg, "Select settings mode", x, y, WindowWidth, WindowHeight);
|
DrawWindow(vg, "Einstellungsmodus wählen", x, y, WindowWidth, WindowHeight);
|
||||||
this->DrawButtons(vg, ns);
|
this->DrawButtons(vg, ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -995,8 +995,8 @@ namespace dbk {
|
|||||||
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
|
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
|
||||||
|
|
||||||
/* Add buttons. */
|
/* Add buttons. */
|
||||||
this->AddButton(Fat32ButtonId, "Install (FAT32)", x + HorizontalInset, y + TitleGap, button_width, ButtonHeight);
|
this->AddButton(Fat32ButtonId, "Installieren (FAT32)", x + HorizontalInset, y + TitleGap, button_width, ButtonHeight);
|
||||||
this->AddButton(ExFatButtonId, "Install (FAT32 + exFAT)", x + HorizontalInset + button_width + ButtonHorizontalGap, y + TitleGap, button_width, ButtonHeight);
|
this->AddButton(ExFatButtonId, "Installieren (FAT32 + exFAT)", x + HorizontalInset + button_width + ButtonHorizontalGap, y + TitleGap, button_width, ButtonHeight);
|
||||||
|
|
||||||
/* Set the default selected button based on the user's current install. We aren't particularly concerned if fsIsExFatSupported fails. */
|
/* Set the default selected button based on the user's current install. We aren't particularly concerned if fsIsExFatSupported fails. */
|
||||||
bool exfat_supported = false;
|
bool exfat_supported = false;
|
||||||
@@ -1029,7 +1029,7 @@ namespace dbk {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChangeMenu(std::make_shared<WarningMenu>(g_current_menu, std::make_shared<InstallUpdateMenu>(g_current_menu), "Ready to begin update installation", "Are you sure you want to proceed?"));
|
ChangeMenu(std::make_shared<WarningMenu>(g_current_menu, std::make_shared<InstallUpdateMenu>(g_current_menu), "Bereit zur Update-Installation", "Möchtest du wirklich fortfahren?"));
|
||||||
}
|
}
|
||||||
|
|
||||||
this->UpdateButtons();
|
this->UpdateButtons();
|
||||||
@@ -1044,7 +1044,7 @@ namespace dbk {
|
|||||||
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
||||||
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
||||||
|
|
||||||
DrawWindow(vg, "Select driver variant", x, y, WindowWidth, WindowHeight);
|
DrawWindow(vg, "Treibervariante wählen", x, y, WindowWidth, WindowHeight);
|
||||||
this->DrawButtons(vg, ns);
|
this->DrawButtons(vg, ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1054,8 +1054,8 @@ namespace dbk {
|
|||||||
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
|
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
|
||||||
|
|
||||||
/* Add buttons. */
|
/* Add buttons. */
|
||||||
this->AddButton(ShutdownButtonId, "Shutdown", x + HorizontalInset, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight);
|
this->AddButton(ShutdownButtonId, "Ausschalten", x + HorizontalInset, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight);
|
||||||
this->AddButton(RebootButtonId, "Reboot", x + HorizontalInset + button_width + ButtonHorizontalGap, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight);
|
this->AddButton(RebootButtonId, "Neustart", x + HorizontalInset + button_width + ButtonHorizontalGap, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight);
|
||||||
this->SetButtonEnabled(ShutdownButtonId, false);
|
this->SetButtonEnabled(ShutdownButtonId, false);
|
||||||
this->SetButtonEnabled(RebootButtonId, false);
|
this->SetButtonEnabled(RebootButtonId, false);
|
||||||
|
|
||||||
@@ -1075,34 +1075,34 @@ namespace dbk {
|
|||||||
if (m_install_state == InstallState::NeedsSetup) {
|
if (m_install_state == InstallState::NeedsSetup) {
|
||||||
/* Setup the update. */
|
/* Setup the update. */
|
||||||
if (R_FAILED(rc = amssuSetupUpdate(nullptr, UpdateTaskBufferSize, g_update_path, g_use_exfat))) {
|
if (R_FAILED(rc = amssuSetupUpdate(nullptr, UpdateTaskBufferSize, g_update_path, g_use_exfat))) {
|
||||||
this->LogText("Failed to setup update.\nResult: 0x%08x\n", rc);
|
this->LogText("Update-Einrichtung fehlgeschlagen.\nErgebnis: 0x%08x\n", rc);
|
||||||
this->MarkForReboot();
|
this->MarkForReboot();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Log setup completion. */
|
/* Log setup completion. */
|
||||||
this->LogText("Update setup complete.\n");
|
this->LogText("Update-Einrichtung abgeschlossen.\n");
|
||||||
m_install_state = InstallState::NeedsPrepare;
|
m_install_state = InstallState::NeedsPrepare;
|
||||||
} else if (m_install_state == InstallState::NeedsPrepare) {
|
} else if (m_install_state == InstallState::NeedsPrepare) {
|
||||||
/* Request update preparation. */
|
/* Request update preparation. */
|
||||||
if (R_FAILED(rc = amssuRequestPrepareUpdate(&m_prepare_result))) {
|
if (R_FAILED(rc = amssuRequestPrepareUpdate(&m_prepare_result))) {
|
||||||
this->LogText("Failed to request update preparation.\nResult: 0x%08x\n", rc);
|
this->LogText("Update-Vorbereitung konnte nicht angefordert werden.\nErgebnis: 0x%08x\n", rc);
|
||||||
this->MarkForReboot();
|
this->MarkForReboot();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Log awaiting prepare. */
|
/* Log awaiting prepare. */
|
||||||
this->LogText("Preparing update...\n");
|
this->LogText("Update wird vorbereitet...\n");
|
||||||
m_install_state = InstallState::AwaitingPrepare;
|
m_install_state = InstallState::AwaitingPrepare;
|
||||||
} else if (m_install_state == InstallState::AwaitingPrepare) {
|
} else if (m_install_state == InstallState::AwaitingPrepare) {
|
||||||
/* Check if preparation has a result. */
|
/* Check if preparation has a result. */
|
||||||
if (R_FAILED(rc = asyncResultWait(&m_prepare_result, 0)) && rc != 0xea01) {
|
if (R_FAILED(rc = asyncResultWait(&m_prepare_result, 0)) && rc != 0xea01) {
|
||||||
this->LogText("Failed to check update preparation result.\nResult: 0x%08x\n", rc);
|
this->LogText("Ergebnis der Update-Vorbereitung konnte nicht geprüft werden.\nErgebnis: 0x%08x\n", rc);
|
||||||
this->MarkForReboot();
|
this->MarkForReboot();
|
||||||
return rc;
|
return rc;
|
||||||
} else if (R_SUCCEEDED(rc)) {
|
} else if (R_SUCCEEDED(rc)) {
|
||||||
if (R_FAILED(rc = asyncResultGet(&m_prepare_result))) {
|
if (R_FAILED(rc = asyncResultGet(&m_prepare_result))) {
|
||||||
this->LogText("Failed to prepare update.\nResult: 0x%08x\n", rc);
|
this->LogText("Update konnte nicht vorbereitet werden.\nErgebnis: 0x%08x\n", rc);
|
||||||
this->MarkForReboot();
|
this->MarkForReboot();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -1111,14 +1111,14 @@ namespace dbk {
|
|||||||
/* Check if the update has been prepared. */
|
/* Check if the update has been prepared. */
|
||||||
bool prepared;
|
bool prepared;
|
||||||
if (R_FAILED(rc = amssuHasPreparedUpdate(&prepared))) {
|
if (R_FAILED(rc = amssuHasPreparedUpdate(&prepared))) {
|
||||||
this->LogText("Failed to check if update has been prepared.\nResult: 0x%08x\n", rc);
|
this->LogText("Prüfung, ob das Update vorbereitet wurde, fehlgeschlagen.\nErgebnis: 0x%08x\n", rc);
|
||||||
this->MarkForReboot();
|
this->MarkForReboot();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark for application if preparation complete. */
|
/* Mark for application if preparation complete. */
|
||||||
if (prepared) {
|
if (prepared) {
|
||||||
this->LogText("Update preparation complete.\nApplying update...\n");
|
this->LogText("Update-Vorbereitung abgeschlossen.\nUpdate wird angewendet...\n");
|
||||||
m_install_state = InstallState::NeedsApply;
|
m_install_state = InstallState::NeedsApply;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -1126,7 +1126,7 @@ namespace dbk {
|
|||||||
/* Check update progress. */
|
/* Check update progress. */
|
||||||
NsSystemUpdateProgress update_progress = {};
|
NsSystemUpdateProgress update_progress = {};
|
||||||
if (R_FAILED(rc = amssuGetPrepareUpdateProgress(&update_progress))) {
|
if (R_FAILED(rc = amssuGetPrepareUpdateProgress(&update_progress))) {
|
||||||
this->LogText("Failed to check update progress.\nResult: 0x%08x\n", rc);
|
this->LogText("Update-Fortschritt konnte nicht geprüft werden.\nErgebnis: 0x%08x\n", rc);
|
||||||
this->MarkForReboot();
|
this->MarkForReboot();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -1140,28 +1140,28 @@ namespace dbk {
|
|||||||
} else if (m_install_state == InstallState::NeedsApply) {
|
} else if (m_install_state == InstallState::NeedsApply) {
|
||||||
/* Apply the prepared update. */
|
/* Apply the prepared update. */
|
||||||
if (R_FAILED(rc = amssuApplyPreparedUpdate())) {
|
if (R_FAILED(rc = amssuApplyPreparedUpdate())) {
|
||||||
this->LogText("Failed to apply update.\nResult: 0x%08x\n", rc);
|
this->LogText("Update konnte nicht angewendet werden.\nErgebnis: 0x%08x\n", rc);
|
||||||
} else {
|
} else {
|
||||||
/* Log success. */
|
/* Log success. */
|
||||||
this->LogText("Update applied successfully.\n");
|
this->LogText("Update erfolgreich angewendet.\n");
|
||||||
|
|
||||||
if (g_reset_to_factory) {
|
if (g_reset_to_factory) {
|
||||||
if (R_FAILED(rc = nsResetToFactorySettingsForRefurbishment())) {
|
if (R_FAILED(rc = nsResetToFactorySettingsForRefurbishment())) {
|
||||||
/* Fallback on ResetToFactorySettings. */
|
/* Fallback on ResetToFactorySettings. */
|
||||||
if (rc == MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer)) {
|
if (rc == MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer)) {
|
||||||
if (R_FAILED(rc = nsResetToFactorySettings())) {
|
if (R_FAILED(rc = nsResetToFactorySettings())) {
|
||||||
this->LogText("Failed to reset to factory settings.\nResult: 0x%08x\n", rc);
|
this->LogText("Zurücksetzen auf Werkseinstellungen fehlgeschlagen.\nErgebnis: 0x%08x\n", rc);
|
||||||
this->MarkForReboot();
|
this->MarkForReboot();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this->LogText("Failed to reset to factory settings for refurbishment.\nResult: 0x%08x\n", rc);
|
this->LogText("Zurücksetzen für Aufbereitung fehlgeschlagen.\nErgebnis: 0x%08x\n", rc);
|
||||||
this->MarkForReboot();
|
this->MarkForReboot();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->LogText("Successfully reset to factory settings.\n", rc);
|
this->LogText("Erfolgreich auf Werkseinstellungen zurückgesetzt.\n", rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1201,7 +1201,7 @@ namespace dbk {
|
|||||||
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
||||||
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
||||||
|
|
||||||
DrawWindow(vg, "Installing update", x, y, WindowWidth, WindowHeight);
|
DrawWindow(vg, "Update wird installiert", x, y, WindowWidth, WindowHeight);
|
||||||
DrawProgressText(vg, x + HorizontalInset, y + TitleGap, m_progress_percent);
|
DrawProgressText(vg, x + HorizontalInset, y + TitleGap, m_progress_percent);
|
||||||
DrawProgressBar(vg, x + HorizontalInset, y + TitleGap + ProgressTextHeight, WindowWidth - HorizontalInset * 2.0f, ProgressBarHeight, m_progress_percent);
|
DrawProgressBar(vg, x + HorizontalInset, y + TitleGap + ProgressTextHeight, WindowWidth - HorizontalInset * 2.0f, ProgressBarHeight, m_progress_percent);
|
||||||
DrawTextBackground(vg, x + HorizontalInset, y + TitleGap + ProgressTextHeight + ProgressBarHeight + VerticalGap, WindowWidth - HorizontalInset * 2.0f, TextAreaHeight);
|
DrawTextBackground(vg, x + HorizontalInset, y + TitleGap + ProgressTextHeight + ProgressBarHeight + VerticalGap, WindowWidth - HorizontalInset * 2.0f, TextAreaHeight);
|
||||||
@@ -1211,7 +1211,7 @@ namespace dbk {
|
|||||||
|
|
||||||
/* We have drawn now, allow setup to occur. */
|
/* We have drawn now, allow setup to occur. */
|
||||||
if (m_install_state == InstallState::NeedsDraw) {
|
if (m_install_state == InstallState::NeedsDraw) {
|
||||||
this->LogText("Beginning update setup...\n");
|
this->LogText("Update-Einrichtung wird gestartet...\n");
|
||||||
m_install_state = InstallState::NeedsSetup;
|
m_install_state = InstallState::NeedsSetup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1236,7 +1236,7 @@ namespace dbk {
|
|||||||
/* Attempt to get the exosphere version. */
|
/* Attempt to get the exosphere version. */
|
||||||
u64 version;
|
u64 version;
|
||||||
if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereApiVersionConfigItem), &version))) {
|
if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereApiVersionConfigItem), &version))) {
|
||||||
ChangeMenu(std::make_shared<ErrorMenu>("Atmosphere not found", "Daybreak requires Atmosphere to be installed.", rc));
|
ChangeMenu(std::make_shared<ErrorMenu>("Atmosphere nicht gefunden", "Daybreak benötigt eine installierte Atmosphere-Umgebung.", rc));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1247,13 +1247,13 @@ namespace dbk {
|
|||||||
/* Validate the exosphere version. */
|
/* Validate the exosphere version. */
|
||||||
const bool ams_supports_sysupdate_api = EncodeVersion(version_major, version_minor, version_micro) >= EncodeVersion(0, 14, 0);
|
const bool ams_supports_sysupdate_api = EncodeVersion(version_major, version_minor, version_micro) >= EncodeVersion(0, 14, 0);
|
||||||
if (!ams_supports_sysupdate_api) {
|
if (!ams_supports_sysupdate_api) {
|
||||||
ChangeMenu(std::make_shared<ErrorMenu>("Outdated Atmosphere version", "Daybreak requires Atmosphere 0.14.0 or later.", rc));
|
ChangeMenu(std::make_shared<ErrorMenu>("Veraltete Atmosphere-Version", "Daybreak benötigt Atmosphere 0.14.0 oder neuer.", rc));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure DayBreak is ran as a NRO. */
|
/* Ensure DayBreak is ran as a NRO. */
|
||||||
if (envIsNso()) {
|
if (envIsNso()) {
|
||||||
ChangeMenu(std::make_shared<ErrorMenu>("Unsupported Environment", "Please launch Daybreak via the Homebrew menu.", rc));
|
ChangeMenu(std::make_shared<ErrorMenu>("Nicht unterstützte Umgebung", "Bitte starte Daybreak über das Homebrew-Menü.", rc));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ namespace dbk {
|
|||||||
|
|
||||||
void DrawProgressText(NVGcontext *vg, float x, float y, float progress) {
|
void DrawProgressText(NVGcontext *vg, float x, float y, float progress) {
|
||||||
char progress_text[32] = {};
|
char progress_text[32] = {};
|
||||||
snprintf(progress_text, sizeof(progress_text)-1, "%d%% complete", static_cast<int>(progress * 100.0f));
|
snprintf(progress_text, sizeof(progress_text)-1, "%d%% abgeschlossen", static_cast<int>(progress * 100.0f));
|
||||||
|
|
||||||
nvgFontSize(vg, 24.0f);
|
nvgFontSize(vg, 24.0f);
|
||||||
nvgFontFace(vg, SwitchStandardFont);
|
nvgFontFace(vg, SwitchStandardFont);
|
||||||
|
|||||||
Reference in New Issue
Block a user