mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-18 08:22:04 +00:00
htcfs: implement OpenDirectory/CloseDirectory
This commit is contained in:
parent
b371487525
commit
e79417c37c
9 changed files with 209 additions and 13 deletions
|
@ -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]);
|
||||
|
|
|
@ -43,5 +43,4 @@ namespace ams::htcfs {
|
|||
return GetReference(g_client_storage);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -22,12 +22,16 @@ namespace ams::htcfs {
|
|||
|
||||
R_DEFINE_ERROR_RESULT(InvalidArgument, 3);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(HtclowChannelClosed, 101);
|
||||
|
||||
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_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);
|
||||
|
|
Loading…
Reference in a new issue