1
0
Fork 0
mirror of https://github.com/Atmosphere-NX/Atmosphere.git synced 2024-12-18 16:32:05 +00:00

htcfs: implement OpenDirectory/CloseDirectory

This commit is contained in:
Michael Scire 2021-02-13 01:57:24 -08:00 committed by SciresM
parent b371487525
commit e79417c37c
9 changed files with 209 additions and 13 deletions

View file

@ -819,6 +819,7 @@ namespace ams::sf::impl {
/* Useful defines. */
using ArgsTypeForInvoke = typename CommandMeta::ArgsTypeForInvoke;
using ArgsType = typename CommandMeta::ArgsType;
using BufferArrayType = std::array<cmif::PointerAndSize, CommandMeta::NumBuffers>;
using OutRawHolderType = OutRawHolder<CommandMeta::OutDataSize, CommandMeta::OutDataAlign>;
using OutHandleHolderType = OutHandleHolder<CommandMeta::NumOutMoveHandles, CommandMeta::NumOutCopyHandles>;
@ -1004,8 +1005,8 @@ namespace ams::sf::impl {
/* Argument deserialization. */
private:
template<size_t Index, typename T = typename std::tuple_element<Index, ArgsTypeForInvoke>::type>
NX_CONSTEXPR T DeserializeArgumentImpl(const cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const OutRawHolderType &out_raw_holder, const BufferArrayType &buffers, OutHandleHolderType &out_handles_holder, InOutObjectHolderType &in_out_objects_holder) {
template<size_t Index, typename T = typename std::tuple_element<Index, ArgsType>::type>
NX_CONSTEXPR typename std::tuple_element<Index, ArgsTypeForInvoke>::type DeserializeArgumentImpl(const cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const OutRawHolderType &out_raw_holder, const BufferArrayType &buffers, OutHandleHolderType &out_handles_holder, InOutObjectHolderType &in_out_objects_holder) {
constexpr auto Info = CommandMeta::ArgumentSerializationInfos[Index];
if constexpr (Info.arg_type == ArgumentType::InData) {
/* New in rawdata. */
@ -1051,8 +1052,8 @@ namespace ams::sf::impl {
constexpr auto Attributes = CommandMeta::BufferAttributes[Info.buffer_index];
if constexpr (Attributes & SfBufferAttr_In) {
/* TODO: AMS_ABORT_UNLESS()? N does not bother. */
static_assert(std::is_reference<T>::value);
static_assert(std::is_const<typename std::remove_reference<T>::type>::value);
using InvokeType = typename std::tuple_element<Index, ArgsTypeForInvoke>::type;
static_assert(std::same_as<InvokeType, const T &>);
return *reinterpret_cast<const T *>(buffers[Info.buffer_index].GetAddress());
} else if constexpr (Attributes & SfBufferAttr_Out) {
return T(buffers[Info.buffer_index]);

View file

@ -43,5 +43,4 @@ namespace ams::htcfs {
return GetReference(g_client_storage);
}
}

View file

@ -24,6 +24,9 @@ namespace ams::htcfs {
ClientImpl m_impl;
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); }
};
void InitializeClient(htclow::HtclowManager *manager);

View file

@ -29,6 +29,10 @@ namespace ams::htcfs {
constinit u8 g_cache[32_KB];
ALWAYS_INLINE Result ConvertNativeResult(s64 value) {
return result::impl::MakeResult(value);
}
}
ClientImpl::ClientImpl(htclow::HtclowManager *manager)
@ -188,6 +192,26 @@ namespace ams::htcfs {
return ResultSuccess();
}
Result ClientImpl::CheckResponseHeader(const Header &response, PacketType packet_type) {
/* Perform base checks. */
R_TRY(this->CheckResponseHeaderWithoutVersion(response, packet_type));
/* Check the version. */
R_UNLESS(response.version == m_header_factory.GetVersion(), htcfs::ResultUnexpectedResponseProtocolVersion());
return ResultSuccess();
}
Result ClientImpl::CheckResponseHeader(const Header &response, PacketType packet_type, s64 body_size) {
/* Perform base checks. */
R_TRY(this->CheckResponseHeader(response, packet_type));
/* Check the body size. */
R_UNLESS(response.body_size == body_size, htcfs::ResultUnexpectedResponseBodySize());
return ResultSuccess();
}
Result ClientImpl::GetMaxProtocolVersion(s16 *out) {
/* Create space for request and response. */
Header request, response;
@ -283,4 +307,110 @@ namespace ams::htcfs {
return ResultSuccess();
}
Result ClientImpl::InitializeRpcChannel() {
/* Check that we're not cancelled. */
R_UNLESS(!m_event.TryWait(), htcfs::ResultConnectionFailure());
/* Check that we're connected. */
R_UNLESS(m_connected, htcfs::ResultConnectionFailure());
return ResultSuccess();
}
Result ClientImpl::SendRequest(const Header &request, const void *arg1, size_t arg1_size, const void *arg2, size_t arg2_size) {
/* Try to perform an optimized send. */
if (sizeof(request) + arg1_size + arg2_size < sizeof(m_packet_buffer)) {
/* Setup our packet buffer. */
std::memcpy(m_packet_buffer, std::addressof(request), sizeof(request));
if (arg1_size > 0) {
std::memcpy(m_packet_buffer + sizeof(request), arg1, arg1_size);
}
if (arg2_size > 0) {
std::memcpy(m_packet_buffer + sizeof(request) + arg1_size, arg2, arg2_size);
}
/* Send the request. */
R_TRY(this->SendToRpcChannel(m_packet_buffer, sizeof(request) + arg1_size + arg2_size));
} else {
/* We can't perform a single optimized send, so perform three separate sends. */
R_TRY(this->SendToRpcChannel(std::addressof(request), sizeof(request)));
if (arg1_size > 0) {
R_TRY(this->SendToRpcChannel(arg1, arg1_size));
}
if (arg2_size > 0) {
R_TRY(this->SendToRpcChannel(arg2, arg2_size));
}
}
return ResultSuccess();
}
Result ClientImpl::OpenDirectory(s32 *out_handle, const char *path, fs::OpenDirectoryMode mode, bool case_sensitive) {
/* 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. */
const auto path_len = std::strlen(path);
m_header_factory.MakeOpenDirectoryHeader(std::addressof(request), path_len, mode, case_sensitive);
/* Send the request to the host. */
R_TRY(this->SendRequest(request, path, path_len));
/* 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 handle. */
*out_handle = static_cast<s32>(response.params[2]);
return ResultSuccess();
}
Result ClientImpl::CloseDirectory(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.MakeCloseDirectoryHeader(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]));
return ResultSuccess();
}
}

View file

@ -52,6 +52,9 @@ namespace ams::htcfs {
void Start();
void Cancel();
void Wait();
public:
Result OpenDirectory(s32 *out_handle, const char *path, fs::OpenDirectoryMode mode, bool case_sensitive);
Result CloseDirectory(s32 handle);
private:
int WaitAny(htclow::ChannelState state, os::EventType *event);
@ -59,15 +62,23 @@ namespace ams::htcfs {
void TearDownProtocol();
Result CheckResponseHeaderWithoutVersion(const Header &response, PacketType packet_type);
Result CheckResponseHeader(const Header &response, PacketType packet_type);
Result CheckResponseHeader(const Header &response, PacketType packet_type, s64 body_size);
Result GetMaxProtocolVersion(s16 *out);
Result SetProtocolVersion(s16 version);
Result InitializeRpcChannel();
Result SendToRpcChannel(const void *src, s64 size);
Result ReceiveFromRpcChannel(void *dst, s64 size);
Result SendToHtclow(const void *src, s64 size, htclow::Channel *channel);
Result ReceiveFromHtclow(void *dst, s64 size, htclow::Channel *channel);
Result SendRequest(const Header &request) { return this->SendRequest(request, nullptr, 0, nullptr, 0); }
Result SendRequest(const Header &request, const void *arg1, size_t arg1_size) { return this->SendRequest(request, arg1, arg1_size, nullptr, 0); }
Result SendRequest(const Header &request, const void *arg1, size_t arg1_size, const void *arg2, size_t arg2_size);
};
}

View file

@ -15,14 +15,14 @@
*/
#include <stratosphere.hpp>
#include "htcfs_directory_service_object.hpp"
#include "htcfs_client.hpp"
namespace ams::htcfs {
DirectoryServiceObject::DirectoryServiceObject(s32 handle) : m_handle(handle) { /* ... */ }
DirectoryServiceObject::~DirectoryServiceObject() {
/* TODO */
AMS_ABORT("htcfs::GetClient().CloseDirectory(m_handle);");
htcfs::GetClient().CloseDirectory(m_handle);
}
Result DirectoryServiceObject::GetEntryCount(ams::sf::Out<s64> out) {

View file

@ -15,9 +15,37 @@
*/
#include <stratosphere.hpp>
#include "htcfs_file_system_service_object.hpp"
#include "htcfs_file_service_object.hpp"
#include "htcfs_directory_service_object.hpp"
#include "htcfs_client.hpp"
namespace ams::htcfs {
namespace {
struct DirectoryServiceObjectAllocatorTag;
struct FileServiceObjectAllocatorTag;
using DirectoryServiceObjectAllocator = ams::sf::ExpHeapStaticAllocator<4_KB, DirectoryServiceObjectAllocatorTag>;
using FileServiceObjectAllocator = ams::sf::ExpHeapStaticAllocator<4_KB, FileServiceObjectAllocatorTag>;
using DirectoryServiceObjectFactory = ams::sf::ObjectFactory<typename DirectoryServiceObjectAllocator::Policy>;
using FileServiceObjectFactory = ams::sf::ObjectFactory<typename FileServiceObjectAllocator::Policy>;
class StaticAllocatorInitializer {
public:
StaticAllocatorInitializer() {
DirectoryServiceObjectAllocator::Initialize(lmem::CreateOption_ThreadSafe);
FileServiceObjectAllocator::Initialize(lmem::CreateOption_ThreadSafe);
}
} g_static_allocator_initializer;
constexpr bool IsValidPath(const tma::Path &path) {
const auto len = util::Strnlen(path.str, fs::EntryNameLengthMax + 1);
return 0 < len && len < static_cast<int>(fs::EntryNameLengthMax + 1);
}
}
Result FileSystemServiceObject::OpenFile(sf::Out<sf::SharedPointer<tma::IFileAccessor>> out, const tma::Path &path, u32 open_mode, bool case_sensitive) {
AMS_ABORT("FileSystemServiceObject::OpenFile");
}
@ -39,7 +67,16 @@ namespace ams::htcfs {
}
Result FileSystemServiceObject::OpenDirectory(sf::Out<sf::SharedPointer<tma::IDirectoryAccessor>> out, const tma::Path &path, s32 open_mode, bool case_sensitive) {
AMS_ABORT("FileSystemServiceObject::OpenDirectory");
/* Check that the path is valid. */
R_UNLESS(IsValidPath(path), htcfs::ResultInvalidArgument());
/* Open the directory. */
s32 handle;
R_TRY(htcfs::GetClient().OpenDirectory(std::addressof(handle), path.str, static_cast<fs::OpenDirectoryMode>(open_mode), case_sensitive));
/* Set the output directory. */
*out = DirectoryServiceObjectFactory::CreateSharedEmplaced<tma::IDirectoryAccessor, DirectoryServiceObject>(handle);
return ResultSuccess();
}
Result FileSystemServiceObject::DirectoryExists(sf::Out<bool> out, const tma::Path &path, bool case_sensitive) {

View file

@ -102,6 +102,9 @@ namespace ams::htcfs {
out->params[2] = param2;
out->params[3] = param3;
out->params[4] = param4;
/* Clear reserved. */
out->reserved = 0;
}
void MakeGetMaxProtocolVersionHeader(Header *out) {
@ -111,6 +114,14 @@ namespace ams::htcfs {
void MakeSetProtocolVersionHeader(Header *out, s16 version) {
return this->MakeRequestHeader(out, PacketType::SetProtocolVersion, 0, version);
}
void MakeOpenDirectoryHeader(Header *out, int path_len, fs::OpenDirectoryMode mode, bool case_sensitive) {
return this->MakeRequestHeader(out, PacketType::OpenDirectory, path_len, static_cast<s64>(mode), case_sensitive ? 1 : 0);
}
void MakeCloseDirectoryHeader(Header *out, s32 handle) {
return this->MakeRequestHeader(out, PacketType::CloseDirectory, 0, handle);
}
};
}

View file

@ -22,12 +22,16 @@ namespace ams::htcfs {
R_DEFINE_ERROR_RESULT(InvalidArgument, 3);
R_DEFINE_ERROR_RANGE(ConnectionFailure, 100, 199);
R_DEFINE_ERROR_RESULT(HtclowChannelClosed, 101);
R_DEFINE_ERROR_RANGE(UnexpectedResponse, 110, 119);
R_DEFINE_ERROR_RESULT(UnexpectedResponseProtocolId, 111);
R_DEFINE_ERROR_RESULT(UnexpectedResponseProtocolVersion, 112);
R_DEFINE_ERROR_RESULT(UnexpectedResponsePacketCategory, 113);
R_DEFINE_ERROR_RESULT(UnexpectedResponsePacketType, 114);
R_DEFINE_ERROR_RESULT(UnexpectedResponseBodySize, 115);
R_DEFINE_ERROR_RESULT(UnknownError, 211);
R_DEFINE_ERROR_RESULT(UnsupportedProtocolVersion, 212);