diff --git a/libraries/libstratosphere/source/htcfs/htcfs_client.hpp b/libraries/libstratosphere/source/htcfs/htcfs_client.hpp index 977917da4..6c2396fc5 100644 --- a/libraries/libstratosphere/source/htcfs/htcfs_client.hpp +++ b/libraries/libstratosphere/source/htcfs/htcfs_client.hpp @@ -16,6 +16,7 @@ #pragma once #include #include "htcfs_client_impl.hpp" +#include "htcfs_result_utils.hpp" namespace ams::htcfs { @@ -25,8 +26,14 @@ namespace ams::htcfs { public: Client(htclow::HtclowManager *manager) : m_impl(manager) { /* ... */ } public: - Result OpenDirectory(s32 *out_handle, const char *path, fs::OpenDirectoryMode mode, bool case_sensitive) { return m_impl.OpenDirectory(out_handle, path, mode, case_sensitive); } - Result CloseDirectory(s32 handle) { return m_impl.CloseDirectory(handle); } + Result OpenDirectory(s32 *out_handle, const char *path, fs::OpenDirectoryMode mode, bool case_sensitive) { return ConvertToFsResult(m_impl.OpenDirectory(out_handle, path, mode, case_sensitive)); } + Result CloseDirectory(s32 handle) { return ConvertToFsResult(m_impl.CloseDirectory(handle)); } + + Result GetEntryCount(s64 *out, s32 handle) { return ConvertToFsResult(m_impl.GetEntryCount(out, handle)); } + Result ReadDirectory(s64 *out, fs::DirectoryEntry *out_entries, size_t max_out_entries, s32 handle) { return ConvertToFsResult(m_impl.ReadDirectory(out, out_entries, max_out_entries, handle)); } + Result ReadDirectoryLarge(s64 *out, fs::DirectoryEntry *out_entries, size_t max_out_entries, s32 handle) { return ConvertToFsResult( m_impl.ReadDirectoryLarge(out, out_entries, max_out_entries, handle)); } + Result GetPriorityForDirectory(s32 *out, s32 handle) { return ConvertToFsResult(m_impl.GetPriorityForDirectory(out, handle)); } + Result SetPriorityForDirectory(s32 priority, s32 handle) { return ConvertToFsResult(m_impl.SetPriorityForDirectory(priority, handle)); } }; void InitializeClient(htclow::HtclowManager *manager); diff --git a/libraries/libstratosphere/source/htcfs/htcfs_client_impl.cpp b/libraries/libstratosphere/source/htcfs/htcfs_client_impl.cpp index d1baf3e24..320ac254b 100644 --- a/libraries/libstratosphere/source/htcfs/htcfs_client_impl.cpp +++ b/libraries/libstratosphere/source/htcfs/htcfs_client_impl.cpp @@ -16,7 +16,6 @@ #include #include "htcfs_client_impl.hpp" #include "htcfs_result.hpp" -#include "../htclow/htclow_default_channel_config.hpp" namespace ams::htcfs { @@ -413,4 +412,152 @@ namespace ams::htcfs { return ResultSuccess(); } + Result ClientImpl::GetEntryCount(s64 *out, s32 handle) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Initialize our rpc channel. */ + R_TRY(this->InitializeRpcChannel()); + + /* Create space for request and response. */ + Header request, response; + + /* Create header for the request. */ + m_header_factory.MakeGetEntryCountHeader(std::addressof(request), handle); + + /* Send the request to the host. */ + R_TRY(this->SendRequest(request)); + + /* Receive response from the host. */ + R_TRY(this->ReceiveFromRpcChannel(std::addressof(response), sizeof(response))); + + /* Check the response header. */ + R_TRY(this->CheckResponseHeader(response, request.packet_type, 0)); + + /* Check that we succeeded. */ + R_TRY(ConvertHtcfsResult(response.params[0])); + + /* Check our operation's result. */ + R_TRY(ConvertNativeResult(response.params[1])); + + /* Set the output count. */ + *out = response.params[2]; + + return ResultSuccess(); + } + + Result ClientImpl::ReadDirectory(s64 *out, fs::DirectoryEntry *out_entries, size_t max_out_entries, s32 handle) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Initialize our rpc channel. */ + R_TRY(this->InitializeRpcChannel()); + + /* Create space for request and response. */ + Header request, response; + + /* Create header for the request. */ + m_header_factory.MakeReadDirectoryHeader(std::addressof(request), handle, max_out_entries); + + /* Send the request to the host. */ + R_TRY(this->SendRequest(request)); + + /* Receive response from the host. */ + R_TRY(this->ReceiveFromRpcChannel(std::addressof(response), sizeof(response))); + + /* Check the response header. */ + R_TRY(this->CheckResponseHeader(response, request.packet_type)); + + /* Check that we succeeded. */ + R_TRY(ConvertHtcfsResult(response.params[0])); + + /* Check our operation's result. */ + R_TRY(ConvertNativeResult(response.params[1])); + + /* Check that the response body size is expected. */ + R_UNLESS(static_cast(response.body_size) == max_out_entries * sizeof(*out_entries), htcfs::ResultUnexpectedResponseBody()); + + /* Check that the number of entries read is allowable. */ + R_UNLESS(static_cast(response.params[2]) <= max_out_entries, htcfs::ResultUnexpectedResponseBody()); + + /* Receive the entries. */ + *out = response.params[2]; + return this->ReceiveFromRpcChannel(out_entries, response.body_size); + } + + Result ClientImpl::ReadDirectoryLarge(s64 *out, fs::DirectoryEntry *out_entries, size_t max_out_entries, s32 handle) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Initialize our rpc channel. */ + R_TRY(this->InitializeRpcChannel()); + + /* Create space for request and response. */ + Header request, response; + + /* Create header for the request. */ + m_header_factory.MakeReadDirectoryLargeHeader(std::addressof(request), handle, max_out_entries); + + AMS_ABORT("TODO: Data channel setup/teardown"); + } + + Result ClientImpl::GetPriorityForDirectory(s32 *out, s32 handle) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Initialize our rpc channel. */ + R_TRY(this->InitializeRpcChannel()); + + /* Create space for request and response. */ + Header request, response; + + /* Create header for the request. */ + m_header_factory.MakeGetPriorityForDirectoryHeader(std::addressof(request), handle); + + /* Send the request to the host. */ + R_TRY(this->SendRequest(request)); + + /* Receive response from the host. */ + R_TRY(this->ReceiveFromRpcChannel(std::addressof(response), sizeof(response))); + + /* Check the response header. */ + R_TRY(this->CheckResponseHeader(response, request.packet_type, 0)); + + /* Check that we succeeded. */ + R_TRY(ConvertHtcfsResult(response.params[0])); + + /* Set the output. */ + *out = static_cast(response.params[1]); + + return ResultSuccess(); + } + + Result ClientImpl::SetPriorityForDirectory(s32 priority, s32 handle) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Initialize our rpc channel. */ + R_TRY(this->InitializeRpcChannel()); + + /* Create space for request and response. */ + Header request, response; + + /* Create header for the request. */ + m_header_factory.MakeSetPriorityForDirectoryHeader(std::addressof(request), handle, priority); + + /* Send the request to the host. */ + R_TRY(this->SendRequest(request)); + + /* Receive response from the host. */ + R_TRY(this->ReceiveFromRpcChannel(std::addressof(response), sizeof(response))); + + /* Check the response header. */ + R_TRY(this->CheckResponseHeader(response, request.packet_type, 0)); + + /* Check that we succeeded. */ + R_TRY(ConvertHtcfsResult(response.params[0])); + + return ResultSuccess(); + } + } diff --git a/libraries/libstratosphere/source/htcfs/htcfs_client_impl.hpp b/libraries/libstratosphere/source/htcfs/htcfs_client_impl.hpp index b6166d336..b241a461d 100644 --- a/libraries/libstratosphere/source/htcfs/htcfs_client_impl.hpp +++ b/libraries/libstratosphere/source/htcfs/htcfs_client_impl.hpp @@ -19,14 +19,17 @@ #include "../htclow/htclow_channel.hpp" #include "htcfs_cache_manager.hpp" #include "htcfs_header_factory.hpp" +#include "../htclow/htclow_default_channel_config.hpp" namespace ams::htcfs { class ClientImpl { + public: + static constexpr size_t MaxPacketBodySize = htclow::DefaultChannelConfig.max_packet_size - sizeof(htclow::PacketHeader); private: u8 m_receive_buffer[0x1C040]; u8 m_send_buffer[0x1C040]; - u8 m_packet_buffer[0xE020]; + u8 m_packet_buffer[MaxPacketBodySize + sizeof(htclow::PacketHeader)]; htclow::HtclowManager *m_htclow_manager; CacheManager m_cache_manager; HeaderFactory m_header_factory; @@ -55,6 +58,12 @@ namespace ams::htcfs { public: Result OpenDirectory(s32 *out_handle, const char *path, fs::OpenDirectoryMode mode, bool case_sensitive); Result CloseDirectory(s32 handle); + + Result GetEntryCount(s64 *out, s32 handle); + Result ReadDirectory(s64 *out, fs::DirectoryEntry *out_entries, size_t max_out_entries, s32 handle); + Result ReadDirectoryLarge(s64 *out, fs::DirectoryEntry *out_entries, size_t max_out_entries, s32 handle); + Result GetPriorityForDirectory(s32 *out, s32 handle); + Result SetPriorityForDirectory(s32 priority, s32 handle); private: int WaitAny(htclow::ChannelState state, os::EventType *event); diff --git a/libraries/libstratosphere/source/htcfs/htcfs_directory_service_object.cpp b/libraries/libstratosphere/source/htcfs/htcfs_directory_service_object.cpp index 9bd9397ff..f0db33f07 100644 --- a/libraries/libstratosphere/source/htcfs/htcfs_directory_service_object.cpp +++ b/libraries/libstratosphere/source/htcfs/htcfs_directory_service_object.cpp @@ -16,6 +16,7 @@ #include #include "htcfs_directory_service_object.hpp" #include "htcfs_client.hpp" +#include "../htclow/htclow_default_channel_config.hpp" namespace ams::htcfs { @@ -26,19 +27,23 @@ namespace ams::htcfs { } Result DirectoryServiceObject::GetEntryCount(ams::sf::Out out) { - AMS_ABORT("DirectoryServiceObject::GetEntryCount"); + return htcfs::GetClient().GetEntryCount(out.GetPointer(), m_handle); } Result DirectoryServiceObject::Read(ams::sf::Out out, const ams::sf::OutMapAliasArray &out_entries) { - AMS_ABORT("DirectoryServiceObject::Read"); + if (out_entries.GetSize() * sizeof(fs::DirectoryEntry) >= ClientImpl::MaxPacketBodySize) { + return htcfs::GetClient().ReadDirectoryLarge(out.GetPointer(), out_entries.GetPointer(), out_entries.GetSize(), m_handle); + } else { + return htcfs::GetClient().ReadDirectory(out.GetPointer(), out_entries.GetPointer(), out_entries.GetSize(), m_handle); + } } Result DirectoryServiceObject::SetPriorityForDirectory(s32 priority) { - AMS_ABORT("DirectoryServiceObject::SetPriorityForDirectory"); + return htcfs::GetClient().SetPriorityForDirectory(priority, m_handle); } Result DirectoryServiceObject::GetPriorityForDirectory(ams::sf::Out out) { - AMS_ABORT("DirectoryServiceObject::GetPriorityForDirectory"); + return htcfs::GetClient().GetPriorityForDirectory(out.GetPointer(), m_handle); } diff --git a/libraries/libstratosphere/source/htcfs/htcfs_header_factory.hpp b/libraries/libstratosphere/source/htcfs/htcfs_header_factory.hpp index e19349f73..d7511e81f 100644 --- a/libraries/libstratosphere/source/htcfs/htcfs_header_factory.hpp +++ b/libraries/libstratosphere/source/htcfs/htcfs_header_factory.hpp @@ -122,6 +122,26 @@ namespace ams::htcfs { void MakeCloseDirectoryHeader(Header *out, s32 handle) { return this->MakeRequestHeader(out, PacketType::CloseDirectory, 0, handle); } + + void MakeGetEntryCountHeader(Header *out, s32 handle) { + return this->MakeRequestHeader(out, PacketType::GetEntryCount, 0, handle); + } + + void MakeReadDirectoryHeader(Header *out, s32 handle, size_t max_out_entries) { + return this->MakeRequestHeader(out, PacketType::ReadDirectory, 0, handle, max_out_entries); + } + + void MakeReadDirectoryLargeHeader(Header *out, s32 handle, size_t max_out_entries) { + return this->MakeRequestHeader(out, PacketType::ReadDirectoryLarge, 0, handle, max_out_entries); + } + + void MakeGetPriorityForDirectoryHeader(Header *out, s32 handle) { + return this->MakeRequestHeader(out, PacketType::GetPriorityForDirectory, 0, handle); + } + + void MakeSetPriorityForDirectoryHeader(Header *out, s32 handle, s32 priority) { + return this->MakeRequestHeader(out, PacketType::SetPriorityForDirectory, 0, handle, priority); + } }; } diff --git a/libraries/libstratosphere/source/htcfs/htcfs_result_utils.hpp b/libraries/libstratosphere/source/htcfs/htcfs_result_utils.hpp new file mode 100644 index 000000000..48c2dbb99 --- /dev/null +++ b/libraries/libstratosphere/source/htcfs/htcfs_result_utils.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::htcfs { + + inline Result ConvertToFsResult(Result result) { + R_TRY_CATCH(result) { + R_CONVERT(htcfs::ResultInvalidArgument, fs::ResultInvalidArgument()) + R_CONVERT(htcfs::ResultConnectionFailure, fs::ResultTargetNotFound()) + R_CONVERT(htcfs::ResultOutOfHandle, fs::ResultOpenCountLimit()) + R_CONVERT(htcfs::ResultInternalError, fs::ResultInternal()) + } R_END_TRY_CATCH; + + return result; + } + +} diff --git a/libraries/libvapours/include/vapours/results/htcfs_results.hpp b/libraries/libvapours/include/vapours/results/htcfs_results.hpp index 7fd689338..fc35e68f9 100644 --- a/libraries/libvapours/include/vapours/results/htcfs_results.hpp +++ b/libraries/libvapours/include/vapours/results/htcfs_results.hpp @@ -32,11 +32,13 @@ namespace ams::htcfs { R_DEFINE_ERROR_RESULT(UnexpectedResponsePacketCategory, 113); R_DEFINE_ERROR_RESULT(UnexpectedResponsePacketType, 114); R_DEFINE_ERROR_RESULT(UnexpectedResponseBodySize, 115); + R_DEFINE_ERROR_RESULT(UnexpectedResponseBody, 116); - R_DEFINE_ERROR_RESULT(UnknownError, 211); - R_DEFINE_ERROR_RESULT(UnsupportedProtocolVersion, 212); - R_DEFINE_ERROR_RESULT(InvalidRequest, 213); - R_DEFINE_ERROR_RESULT(InvalidHandle, 214); - R_DEFINE_ERROR_RESULT(OutOfHandle, 215); + R_DEFINE_ERROR_RANGE(InternalError, 200, 299); + R_DEFINE_ERROR_RESULT(UnknownError, 211); + R_DEFINE_ERROR_RESULT(UnsupportedProtocolVersion, 212); + R_DEFINE_ERROR_RESULT(InvalidRequest, 213); + R_DEFINE_ERROR_RESULT(InvalidHandle, 214); + R_DEFINE_ERROR_RESULT(OutOfHandle, 215); }