htc: Implement (almost) all host-directory commands

This commit is contained in:
Michael Scire 2021-02-13 05:39:02 -08:00 committed by SciresM
parent e79417c37c
commit 9daec3a66a
7 changed files with 235 additions and 13 deletions

View file

@ -16,6 +16,7 @@
#pragma once
#include <stratosphere.hpp>
#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);

View file

@ -16,7 +16,6 @@
#include <stratosphere.hpp>
#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<size_t>(response.body_size) == max_out_entries * sizeof(*out_entries), htcfs::ResultUnexpectedResponseBody());
/* Check that the number of entries read is allowable. */
R_UNLESS(static_cast<size_t>(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<s32>(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();
}
}

View file

@ -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);

View file

@ -16,6 +16,7 @@
#include <stratosphere.hpp>
#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<s64> out) {
AMS_ABORT("DirectoryServiceObject::GetEntryCount");
return htcfs::GetClient().GetEntryCount(out.GetPointer(), m_handle);
}
Result DirectoryServiceObject::Read(ams::sf::Out<s64> out, const ams::sf::OutMapAliasArray<fs::DirectoryEntry> &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<s32> out) {
AMS_ABORT("DirectoryServiceObject::GetPriorityForDirectory");
return htcfs::GetClient().GetPriorityForDirectory(out.GetPointer(), m_handle);
}

View file

@ -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);
}
};
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
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;
}
}

View file

@ -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);
}