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

htc: implement the remaining commands for htcfs

This commit is contained in:
Michael Scire 2021-02-15 18:56:22 -08:00 committed by SciresM
parent 1961cb1034
commit d20bceff75
9 changed files with 1169 additions and 27 deletions

View file

@ -51,6 +51,16 @@ namespace ams::htcfs {
m_has_cached_handle = false; m_has_cached_handle = false;
} }
void Invalidate(s32 handle) {
/* Lock ourselves. */
std::scoped_lock lk(m_mutex);
if (m_has_cached_handle && m_cached_handle == handle) {
/* Note that we have no handle. */
m_has_cached_handle = false;
}
}
void Record(s64 file_size, const void *data, s32 handle, size_t data_size) { void Record(s64 file_size, const void *data, s32 handle, size_t data_size) {
/* Lock ourselves. */ /* Lock ourselves. */
std::scoped_lock lk(m_mutex); std::scoped_lock lk(m_mutex);

View file

@ -26,14 +26,40 @@ namespace ams::htcfs {
public: public:
Client(htclow::HtclowManager *manager) : m_impl(manager) { /* ... */ } Client(htclow::HtclowManager *manager) : m_impl(manager) { /* ... */ }
public: public:
Result OpenFile(s32 *out_handle, const char *path, fs::OpenMode mode, bool case_sensitive) { return ConvertToFsResult(m_impl.OpenFile(out_handle, path, mode, case_sensitive)); }
Result FileExists(bool *out, const char *path, bool case_sensitive) { return ConvertToFsResult(m_impl.FileExists(out, path, case_sensitive)); }
Result DeleteFile(const char *path, bool case_sensitive) { return ConvertToFsResult(m_impl.DeleteFile(path, case_sensitive)); }
Result RenameFile(const char *old_path, const char *new_path, bool case_sensitive) { return ConvertToFsResult(m_impl.RenameFile(old_path, new_path, case_sensitive)); }
Result GetEntryType(fs::DirectoryEntryType *out, const char *path, bool case_sensitive) { return ConvertToFsResult(m_impl.GetEntryType(out, path, case_sensitive)); }
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 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 DirectoryExists(bool *out, const char *path, bool case_sensitive) { return ConvertToFsResult(m_impl.DirectoryExists(out, path, case_sensitive)); }
Result CreateDirectory(const char *path, bool case_sensitive) { return ConvertToFsResult(m_impl.CreateDirectory(path, case_sensitive)); }
Result DeleteDirectory(const char *path, bool recursively, bool case_sensitive) { return ConvertToFsResult(m_impl.DeleteDirectory(path, recursively, case_sensitive)); }
Result RenameDirectory(const char *old_path, const char *new_path, bool case_sensitive) { return ConvertToFsResult(m_impl.RenameDirectory(old_path, new_path, case_sensitive)); }
Result CreateFile(const char *path, s64 size, bool case_sensitive) { return ConvertToFsResult(m_impl.CreateFile(path, size, case_sensitive)); }
Result GetFileTimeStamp(u64 *out_create, u64 *out_access, u64 *out_modify, const char *path, bool case_sensitive) { return ConvertToFsResult(m_impl.GetFileTimeStamp(out_create, out_access, out_modify, path, case_sensitive)); }
Result GetCaseSensitivePath(char *dst, size_t dst_size, const char *path) { return ConvertToFsResult(m_impl.GetCaseSensitivePath(dst, dst_size, path)); }
Result GetDiskFreeSpace(s64 *out_free, s64 *out_total, s64 *out_total_free, const char *path) { return ConvertToFsResult(m_impl.GetDiskFreeSpace(out_free, out_total, out_total_free, path)); }
Result CloseDirectory(s32 handle) { return ConvertToFsResult(m_impl.CloseDirectory(handle)); } Result CloseDirectory(s32 handle) { return ConvertToFsResult(m_impl.CloseDirectory(handle)); }
Result GetEntryCount(s64 *out, s32 handle) { return ConvertToFsResult(m_impl.GetEntryCount(out, 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 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 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 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)); } Result SetPriorityForDirectory(s32 priority, s32 handle) { return ConvertToFsResult(m_impl.SetPriorityForDirectory(priority, handle)); }
Result CloseFile(s32 handle) { return ConvertToFsResult(m_impl.CloseFile(handle)); }
Result ReadFile(s64 *out, void *buffer, s32 handle, s64 offset, s64 buffer_size, fs::ReadOption option) { return ConvertToFsResult(m_impl.ReadFile(out, buffer, handle, offset, buffer_size, option)); }
Result ReadFileLarge(s64 *out, void *buffer, s32 handle, s64 offset, s64 buffer_size, fs::ReadOption option) { return ConvertToFsResult(m_impl.ReadFileLarge(out, buffer, handle, offset, buffer_size, option)); }
Result WriteFile(const void *buffer, s32 handle, s64 offset, s64 buffer_size, fs::WriteOption option) { return ConvertToFsResult(m_impl.WriteFile(buffer, handle, offset, buffer_size, option)); }
Result WriteFileLarge(const void *buffer, s32 handle, s64 offset, s64 buffer_size, fs::WriteOption option) { return ConvertToFsResult(m_impl.WriteFileLarge(buffer, handle, offset, buffer_size, option)); }
Result GetFileSize(s64 *out, s32 handle) { return ConvertToFsResult(m_impl.GetFileSize(out, handle)); }
Result SetFileSize(s64 size, s32 handle) { return ConvertToFsResult(m_impl.SetFileSize(size, handle)); }
Result FlushFile(s32 handle) { return ConvertToFsResult(m_impl.FlushFile(handle)); }
Result GetPriorityForFile(s32 *out, s32 handle) { return ConvertToFsResult(m_impl.GetPriorityForFile(out, handle)); }
Result SetPriorityForFile(s32 priority, s32 handle) { return ConvertToFsResult(m_impl.SetPriorityForFile(priority, handle)); }
}; };
void InitializeClient(htclow::HtclowManager *manager); void InitializeClient(htclow::HtclowManager *manager);

View file

@ -27,7 +27,8 @@ namespace ams::htcfs {
alignas(os::ThreadStackAlignment) constinit u8 g_monitor_thread_stack[os::MemoryPageSize]; alignas(os::ThreadStackAlignment) constinit u8 g_monitor_thread_stack[os::MemoryPageSize];
constinit u8 g_cache[32_KB]; constexpr size_t FileDataCacheSize = 32_KB;
constinit u8 g_cache[FileDataCacheSize];
ALWAYS_INLINE Result ConvertNativeResult(s64 value) { ALWAYS_INLINE Result ConvertNativeResult(s64 value) {
return result::impl::MakeResult(value); return result::impl::MakeResult(value);
@ -401,6 +402,191 @@ namespace ams::htcfs {
return ResultSuccess(); return ResultSuccess();
} }
Result ClientImpl::OpenFile(s32 *out_handle, const char *path, fs::OpenMode mode, bool case_sensitive) {
/* Invalidate the cache manager. */
m_cache_manager.Invalidate();
/* 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.MakeOpenFileHeader(std::addressof(request), path_len, mode, case_sensitive, FileDataCacheSize);
/* 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));
/* Check the response body size. */
R_UNLESS(response.body_size > 0, htcfs::ResultUnexpectedResponseBodySize());
R_UNLESS(static_cast<size_t>(response.body_size) <= MaxPacketBodySize, htcfs::ResultUnexpectedResponseBodySize());
/* Receive the response body. */
R_TRY(this->ReceiveFromRpcChannel(m_packet_buffer, response.body_size));
/* Check that we succeeded. */
R_TRY(ConvertHtcfsResult(response.params[0]));
/* Check our operation's result. */
R_TRY(ConvertNativeResult(response.params[1]));
/* Set our output handle. */
*out_handle = response.params[2];
/* If we have data to cache, cache it. */
if (response.params[3]) {
m_cache_manager.Record(response.params[4], m_packet_buffer, response.params[2], response.body_size);
}
return ResultSuccess();
}
Result ClientImpl::FileExists(bool *out, const char *path, 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.MakeFileExistsHeader(std::addressof(request), path_len, 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. */
*out = response.params[2] != 0;
return ResultSuccess();
}
Result ClientImpl::DeleteFile(const char *path, 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.MakeDeleteFileHeader(std::addressof(request), path_len, 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]));
return ResultSuccess();
}
Result ClientImpl::RenameFile(const char *old_path, const char *new_path, 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 old_path_len = std::strlen(new_path);
const auto new_path_len = std::strlen(old_path);
m_header_factory.MakeRenameFileHeader(std::addressof(request), old_path_len, new_path_len, case_sensitive);
/* Send the request to the host. */
R_TRY(this->SendRequest(request, old_path, old_path_len, new_path, new_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]));
return ResultSuccess();
}
Result ClientImpl::GetEntryType(fs::DirectoryEntryType *out, const char *path, 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.MakeGetEntryTypeHeader(std::addressof(request), path_len, 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. */
*out = static_cast<fs::DirectoryEntryType>(response.params[2]);
return ResultSuccess();
}
Result ClientImpl::OpenDirectory(s32 *out_handle, const char *path, fs::OpenDirectoryMode mode, bool case_sensitive) { Result ClientImpl::OpenDirectory(s32 *out_handle, const char *path, fs::OpenDirectoryMode mode, bool case_sensitive) {
/* Lock ourselves. */ /* Lock ourselves. */
std::scoped_lock lk(m_mutex); std::scoped_lock lk(m_mutex);
@ -436,6 +622,297 @@ namespace ams::htcfs {
return ResultSuccess(); return ResultSuccess();
} }
Result ClientImpl::DirectoryExists(bool *out, const char *path, 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.MakeDirectoryExistsHeader(std::addressof(request), path_len, 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. */
*out = response.params[2] != 0;
return ResultSuccess();
}
Result ClientImpl::CreateDirectory(const char *path, 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.MakeCreateDirectoryHeader(std::addressof(request), path_len, 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]));
return ResultSuccess();
}
Result ClientImpl::DeleteDirectory(const char *path, bool recursively, 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.MakeDeleteDirectoryHeader(std::addressof(request), path_len, recursively, 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]));
return ResultSuccess();
}
Result ClientImpl::RenameDirectory(const char *old_path, const char *new_path, 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 old_path_len = std::strlen(new_path);
const auto new_path_len = std::strlen(old_path);
m_header_factory.MakeRenameDirectoryHeader(std::addressof(request), old_path_len, new_path_len, case_sensitive);
/* Send the request to the host. */
R_TRY(this->SendRequest(request, old_path, old_path_len, new_path, new_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]));
return ResultSuccess();
}
Result ClientImpl::CreateFile(const char *path, s64 size, 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.MakeCreateFileHeader(std::addressof(request), path_len, size, 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]));
return ResultSuccess();
}
Result ClientImpl::GetFileTimeStamp(u64 *out_create, u64 *out_access, u64 *out_modify, const char *path, 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.MakeGetFileTimeStampHeader(std::addressof(request), path_len, 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 output. */
*out_create = static_cast<u64>(response.params[2]);
*out_access = static_cast<u64>(response.params[3]);
*out_modify = static_cast<u64>(response.params[4]);
return ResultSuccess();
}
Result ClientImpl::GetCaseSensitivePath(char *dst, size_t dst_size, const char *path) {
/* Sanity check the output buffer. */
R_UNLESS(util::IsIntValueRepresentable<s64>(dst_size), htcfs::ResultInvalidArgument());
R_UNLESS(dst_size > 0, htcfs::ResultInvalidArgument());
/* 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.MakeGetCaseSensitivePathHeader(std::addressof(request), path_len);
/* 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));
/* Check that we succeeded. */
const auto htcfs_result = ConvertHtcfsResult(response.params[0]);
if (R_FAILED(htcfs_result)) {
R_UNLESS(response.body_size == 0, htcfs::ResultUnexpectedResponseBodySize());
return htcfs_result;
}
/* Check our operation's result. */
const auto native_result = ConvertNativeResult(response.params[1]);
if (R_FAILED(native_result)) {
R_UNLESS(response.body_size == 0, htcfs::ResultUnexpectedResponseBodySize());
return native_result;
}
/* Check the body size. */
R_UNLESS(response.body_size < static_cast<s64>(dst_size), htcfs::ResultUnexpectedResponseBodySize());
/* Receive the response body. */
R_TRY(this->ReceiveFromRpcChannel(dst, response.body_size));
/* Null-terminate the output path. */
dst[response.body_size] = '\x00';
return ResultSuccess();
}
Result ClientImpl::GetDiskFreeSpace(s64 *out_free, s64 *out_total, s64 *out_total_free, const char *path) {
/* 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.MakeGetDiskFreeSpaceHeader(std::addressof(request), path_len);
/* 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 output. */
*out_free = response.params[2];
*out_total = response.params[3];
*out_total_free = response.params[4];
return ResultSuccess();
}
Result ClientImpl::CloseDirectory(s32 handle) { Result ClientImpl::CloseDirectory(s32 handle) {
/* Lock ourselves. */ /* Lock ourselves. */
std::scoped_lock lk(m_mutex); std::scoped_lock lk(m_mutex);
@ -570,10 +1047,18 @@ namespace ams::htcfs {
R_TRY(this->CheckResponseHeader(response, request.packet_type, 0)); R_TRY(this->CheckResponseHeader(response, request.packet_type, 0));
/* Check that we succeeded. */ /* Check that we succeeded. */
R_TRY(ConvertHtcfsResult(response.params[0])); const auto htcfs_result = ConvertHtcfsResult(response.params[0]);
if (R_FAILED(htcfs_result)) {
R_UNLESS(response.body_size == 0, htcfs::ResultUnexpectedResponseBodySize());
return htcfs_result;
}
/* Check our operation's result. */ /* Check our operation's result. */
R_TRY(ConvertNativeResult(response.params[1])); const auto native_result = ConvertNativeResult(response.params[1]);
if (R_FAILED(native_result)) {
R_UNLESS(response.body_size == 0, htcfs::ResultUnexpectedResponseBodySize());
return native_result;
}
/* Check that the number of entries read is allowable. */ /* Check that the number of entries read is allowable. */
R_UNLESS(static_cast<size_t>(response.params[2]) <= max_out_entries, htcfs::ResultUnexpectedResponseBody()); R_UNLESS(static_cast<size_t>(response.params[2]) <= max_out_entries, htcfs::ResultUnexpectedResponseBody());
@ -648,4 +1133,408 @@ namespace ams::htcfs {
return ResultSuccess(); return ResultSuccess();
} }
Result ClientImpl::CloseFile(s32 handle) {
/* Invalidate the cache. */
m_cache_manager.Invalidate(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.MakeCloseFileHeader(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();
}
Result ClientImpl::ReadFile(s64 *out, void *buffer, s32 handle, s64 offset, s64 buffer_size, fs::ReadOption option) {
/* Lock ourselves. */
std::scoped_lock lk(m_mutex);
/* Initialize our rpc channel. */
R_TRY(this->InitializeRpcChannel());
/* Try to read from our cache. */
if (util::IsIntValueRepresentable<size_t>(offset) && util::IsIntValueRepresentable<size_t>(buffer_size)) {
size_t read_size;
if (m_cache_manager.ReadFile(std::addressof(read_size), buffer, handle, static_cast<size_t>(offset), static_cast<size_t>(buffer_size))) {
AMS_ASSERT(util::IsIntValueRepresentable<s64>(read_size));
*out = static_cast<s64>(read_size);
return ResultSuccess();
}
}
/* Create space for request and response. */
Header request, response;
/* Create header for the request. */
m_header_factory.MakeReadFileHeader(std::addressof(request), handle, offset, buffer_size);
/* 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. */
const auto htcfs_result = ConvertHtcfsResult(response.params[0]);
if (R_FAILED(htcfs_result)) {
R_UNLESS(response.body_size == 0, htcfs::ResultUnexpectedResponseBodySize());
return htcfs_result;
}
/* Check our operation's result. */
const auto native_result = ConvertNativeResult(response.params[1]);
if (R_FAILED(native_result)) {
R_UNLESS(response.body_size == 0, htcfs::ResultUnexpectedResponseBodySize());
return native_result;
}
/* Check the body size. */
R_UNLESS(response.body_size <= buffer_size, htcfs::ResultUnexpectedResponseBodySize());
/* Receive the file data. */
R_TRY(this->ReceiveFromRpcChannel(buffer, response.body_size));
/* Set the output size. */
*out = response.body_size;
return ResultSuccess();
}
Result ClientImpl::ReadFileLarge(s64 *out, void *buffer, s32 handle, s64 offset, s64 buffer_size, fs::ReadOption option) {
/* Check our buffer size. */
R_UNLESS(util::IsIntValueRepresentable<size_t>(buffer_size), htcfs::ResultInvalidArgument());
/* Lock ourselves. */
std::scoped_lock lk(m_mutex);
/* Initialize our rpc channel. */
R_TRY(this->InitializeRpcChannel());
/* Setup data channel. */
this->InitializeDataChannelForReceive(buffer, buffer_size);
ON_SCOPE_EXIT { this->FinalizeDataChannel(); };
/* Create space for request and response. */
Header request, response;
/* Create header for the request. */
m_header_factory.MakeReadFileLargeHeader(std::addressof(request), handle, offset, buffer_size, DataChannelId);
/* 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. */
const auto htcfs_result = ConvertHtcfsResult(response.params[0]);
if (R_FAILED(htcfs_result)) {
R_UNLESS(response.body_size == 0, htcfs::ResultUnexpectedResponseBodySize());
return htcfs_result;
}
/* Check our operation's result. */
const auto native_result = ConvertNativeResult(response.params[1]);
if (R_FAILED(native_result)) {
R_UNLESS(response.body_size == 0, htcfs::ResultUnexpectedResponseBodySize());
return native_result;
}
/* Check that the size read is allowable. */
R_UNLESS(response.params[2] <= buffer_size, htcfs::ResultUnexpectedResponseBodySize());
/* Read the entries, if there are any. */
R_TRY(this->ReceiveFromDataChannel(response.params[2]));
/* Set the number of output entries. */
*out = response.params[2];
return ResultSuccess();
}
Result ClientImpl::WriteFile(const void *buffer, s32 handle, s64 offset, s64 buffer_size, fs::WriteOption option) {
/* Invalidate the cache. */
m_cache_manager.Invalidate(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.MakeWriteFileHeader(std::addressof(request), buffer_size, handle, option.value, offset);
/* Send the request to the host. */
R_TRY(this->SendRequest(request, buffer, buffer_size));
/* 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();
}
Result ClientImpl::WriteFileLarge(const void *buffer, s32 handle, s64 offset, s64 buffer_size, fs::WriteOption option) {
/* Invalidate the cache. */
m_cache_manager.Invalidate(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.MakeWriteFileLargeHeader(std::addressof(request), handle, option.value, offset, buffer_size, DataChannelId);
/* Send the request to the host. */
R_TRY(this->SendRequest(request, buffer, buffer_size));
/* 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));
/* Verify that the host reports ready to receive our data. */
if (static_cast<HtcfsResult>(response.params[0]) != HtcfsResult::Ready) {
return ConvertHtcfsResult(response.params[0]);
}
/* Verify that our send will be valid. */
AMS_ASSERT(util::IsIntValueRepresentable<size_t>(buffer_size));
/* Perform the send. */
{
/* Initialize data channel for our write. */
this->InitializeDataChannelForSend(buffer, buffer_size);
/* Ensure that we clean up our data channel. */
ON_SCOPE_EXIT { this->FinalizeDataChannel(); };
/* Send to our data channel. */
R_TRY(this->SendToDataChannel());
}
/* Receive the large-write response. */
Header write_resp;
R_TRY(this->ReceiveFromRpcChannel(std::addressof(write_resp), sizeof(write_resp)));
/* Check the write-response header. */
R_TRY(this->CheckResponseHeader(write_resp, request.packet_type, 0));
/* Check that we succeeded. */
R_TRY(ConvertHtcfsResult(write_resp.params[0]));
/* Check our operation's result. */
R_TRY(ConvertNativeResult(write_resp.params[1]));
return ResultSuccess();
}
Result ClientImpl::GetFileSize(s64 *out, s32 handle) {
/* Lock ourselves. */
std::scoped_lock lk(m_mutex);
/* Initialize our rpc channel. */
R_TRY(this->InitializeRpcChannel());
/* Check if we have the file size cached. */
R_SUCCEED_IF(m_cache_manager.GetFileSize(out, handle));
/* Create space for request and response. */
Header request, response;
/* Create header for the request. */
m_header_factory.MakeGetFileSizeHeader(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. */
*out = response.params[2];
return ResultSuccess();
}
Result ClientImpl::SetFileSize(s64 size, s32 handle) {
/* Invalidate the cache. */
m_cache_manager.Invalidate(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.MakeSetFileSizeHeader(std::addressof(request), handle, size);
/* 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();
}
Result ClientImpl::FlushFile(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.MakeFlushFileHeader(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();
}
Result ClientImpl::GetPriorityForFile(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.MakeGetPriorityForFileHeader(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::SetPriorityForFile(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.MakeSetPriorityForFileHeader(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

@ -56,7 +56,21 @@ namespace ams::htcfs {
void Cancel(); void Cancel();
void Wait(); void Wait();
public: public:
Result OpenFile(s32 *out_handle, const char *path, fs::OpenMode mode, bool case_sensitive);
Result FileExists(bool *out, const char *path, bool case_sensitive);
Result DeleteFile(const char *path, bool case_sensitive);
Result RenameFile(const char *old_path, const char *new_path, bool case_sensitive);
Result GetEntryType(fs::DirectoryEntryType *out, const char *path, bool case_sensitive);
Result OpenDirectory(s32 *out_handle, const char *path, fs::OpenDirectoryMode mode, bool case_sensitive); Result OpenDirectory(s32 *out_handle, const char *path, fs::OpenDirectoryMode mode, bool case_sensitive);
Result DirectoryExists(bool *out, const char *path, bool case_sensitive);
Result CreateDirectory(const char *path, bool case_sensitive);
Result DeleteDirectory(const char *path, bool recursively, bool case_sensitive);
Result RenameDirectory(const char *old_path, const char *new_path, bool case_sensitive);
Result CreateFile(const char *path, s64 size, bool case_sensitive);
Result GetFileTimeStamp(u64 *out_create, u64 *out_access, u64 *out_modify, const char *path, bool case_sensitive);
Result GetCaseSensitivePath(char *dst, size_t dst_size, const char *path);
Result GetDiskFreeSpace(s64 *out_free, s64 *out_total, s64 *out_total_free, const char *path);
Result CloseDirectory(s32 handle); Result CloseDirectory(s32 handle);
Result GetEntryCount(s64 *out, s32 handle); Result GetEntryCount(s64 *out, s32 handle);
@ -64,6 +78,18 @@ namespace ams::htcfs {
Result ReadDirectoryLarge(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 GetPriorityForDirectory(s32 *out, s32 handle);
Result SetPriorityForDirectory(s32 priority, s32 handle); Result SetPriorityForDirectory(s32 priority, s32 handle);
Result CloseFile(s32 handle);
Result ReadFile(s64 *out, void *buffer, s32 handle, s64 offset, s64 buffer_size, fs::ReadOption option);
Result ReadFileLarge(s64 *out, void *buffer, s32 handle, s64 offset, s64 buffer_size, fs::ReadOption option);
Result WriteFile(const void *buffer, s32 handle, s64 offset, s64 buffer_size, fs::WriteOption option);
Result WriteFileLarge(const void *buffer, s32 handle, s64 offset, s64 buffer_size, fs::WriteOption option);
Result GetFileSize(s64 *out, s32 handle);
Result SetFileSize(s64 size, s32 handle);
Result FlushFile(s32 handle);
Result GetPriorityForFile(s32 *out, s32 handle);
Result SetPriorityForFile(s32 priority, s32 handle);
private: private:
int WaitAny(htclow::ChannelState state, os::EventType *event); int WaitAny(htclow::ChannelState state, os::EventType *event);

View file

@ -16,7 +16,6 @@
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "htcfs_directory_service_object.hpp" #include "htcfs_directory_service_object.hpp"
#include "htcfs_client.hpp" #include "htcfs_client.hpp"
#include "../htclow/htclow_default_channel_config.hpp"
namespace ams::htcfs { namespace ams::htcfs {

View file

@ -15,42 +15,59 @@
*/ */
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "htcfs_file_service_object.hpp" #include "htcfs_file_service_object.hpp"
#include "htcfs_client.hpp"
namespace ams::htcfs { namespace ams::htcfs {
FileServiceObject::FileServiceObject(s32 handle) : m_handle(handle) { /* ... */ } FileServiceObject::FileServiceObject(s32 handle) : m_handle(handle) { /* ... */ }
FileServiceObject::~FileServiceObject() { FileServiceObject::~FileServiceObject() {
/* TODO */ htcfs::GetClient().CloseFile(m_handle);
AMS_ABORT("htcfs::GetClient().CloseFile(m_handle);");
} }
Result FileServiceObject::ReadFile(ams::sf::Out<s64> out, s64 offset, const ams::sf::OutNonSecureBuffer &buffer, ams::fs::ReadOption option) { Result FileServiceObject::ReadFile(ams::sf::Out<s64> out, s64 offset, const ams::sf::OutNonSecureBuffer &buffer, ams::fs::ReadOption option) {
AMS_ABORT("FileServiceObject::ReadFile"); /* Validate offset. */
R_UNLESS(offset >= 0, htcfs::ResultInvalidArgument());
if (buffer.GetSize() >= ClientImpl::MaxPacketBodySize) {
return htcfs::GetClient().ReadFileLarge(out.GetPointer(), buffer.GetPointer(), m_handle, offset, buffer.GetSize(), option);
} else {
return htcfs::GetClient().ReadFile(out.GetPointer(), buffer.GetPointer(), m_handle, offset, buffer.GetSize(), option);
}
} }
Result FileServiceObject::WriteFile(s64 offset, const ams::sf::InNonSecureBuffer &buffer, ams::fs::WriteOption option) { Result FileServiceObject::WriteFile(s64 offset, const ams::sf::InNonSecureBuffer &buffer, ams::fs::WriteOption option) {
AMS_ABORT("FileServiceObject::WriteFile"); /* Validate offset. */
R_UNLESS(offset >= 0, htcfs::ResultInvalidArgument());
if (buffer.GetSize() >= ClientImpl::MaxPacketBodySize) {
return htcfs::GetClient().WriteFileLarge(buffer.GetPointer(), m_handle, offset, buffer.GetSize(), option);
} else {
return htcfs::GetClient().WriteFile(buffer.GetPointer(), m_handle, offset, buffer.GetSize(), option);
}
} }
Result FileServiceObject::GetFileSize(ams::sf::Out<s64> out) { Result FileServiceObject::GetFileSize(ams::sf::Out<s64> out) {
AMS_ABORT("FileServiceObject::GetFileSize"); return htcfs::GetClient().GetFileSize(out.GetPointer(), m_handle);
} }
Result FileServiceObject::SetFileSize(s64 size) { Result FileServiceObject::SetFileSize(s64 size) {
AMS_ABORT("FileServiceObject::SetFileSize"); /* Validate size. */
R_UNLESS(size >= 0, htcfs::ResultInvalidArgument());
return htcfs::GetClient().SetFileSize(size, m_handle);
} }
Result FileServiceObject::FlushFile() { Result FileServiceObject::FlushFile() {
AMS_ABORT("FileServiceObject::FlushFile"); return htcfs::GetClient().FlushFile(m_handle);
} }
Result FileServiceObject::SetPriorityForFile(s32 priority) { Result FileServiceObject::SetPriorityForFile(s32 priority) {
AMS_ABORT("FileServiceObject::SetPriorityForFile"); return htcfs::GetClient().SetPriorityForFile(priority, m_handle);
} }
Result FileServiceObject::GetPriorityForFile(ams::sf::Out<s32> out) { Result FileServiceObject::GetPriorityForFile(ams::sf::Out<s32> out) {
AMS_ABORT("FileServiceObject::GetPriorityForFile"); return htcfs::GetClient().GetPriorityForFile(out.GetPointer(), m_handle);
} }
} }

View file

@ -44,26 +44,75 @@ namespace ams::htcfs {
return 0 < len && len < static_cast<int>(fs::EntryNameLengthMax + 1); return 0 < len && len < static_cast<int>(fs::EntryNameLengthMax + 1);
} }
Result ConvertOpenMode(fs::OpenMode *out, u32 open_mode) {
switch (open_mode) {
case 1:
*out = fs::OpenMode_Read;
break;
case 2:
*out = static_cast<fs::OpenMode>(fs::OpenMode_Write | fs::OpenMode_AllowAppend);
break;
case 3:
*out = static_cast<fs::OpenMode>(fs::OpenMode_ReadWrite | fs::OpenMode_AllowAppend);
break;
default:
return htcfs::ResultInvalidArgument();
}
return ResultSuccess();
}
} }
Result FileSystemServiceObject::OpenFile(sf::Out<sf::SharedPointer<tma::IFileAccessor>> out, const tma::Path &path, u32 open_mode, bool case_sensitive) { Result FileSystemServiceObject::OpenFile(sf::Out<sf::SharedPointer<tma::IFileAccessor>> out, const tma::Path &path, u32 open_mode, bool case_sensitive) {
AMS_ABORT("FileSystemServiceObject::OpenFile"); /* Check that the path is valid. */
R_UNLESS(IsValidPath(path), htcfs::ResultInvalidArgument());
/* Convert the open mode. */
fs::OpenMode fs_open_mode;
R_TRY(ConvertOpenMode(std::addressof(fs_open_mode), open_mode));
/* Open the file. */
s32 handle;
R_TRY(htcfs::GetClient().OpenFile(std::addressof(handle), path.str, fs_open_mode, case_sensitive));
/* Set the output file. */
*out = FileServiceObjectFactory::CreateSharedEmplaced<tma::IFileAccessor, FileServiceObject>(handle);
return ResultSuccess();
} }
Result FileSystemServiceObject::FileExists(sf::Out<bool> out, const tma::Path &path, bool case_sensitive) { Result FileSystemServiceObject::FileExists(sf::Out<bool> out, const tma::Path &path, bool case_sensitive) {
AMS_ABORT("FileSystemServiceObject::FileExists"); /* Check that the path is valid. */
R_UNLESS(IsValidPath(path), htcfs::ResultInvalidArgument());
/* Get whether the file exists. */
return htcfs::GetClient().FileExists(out.GetPointer(), path.str, case_sensitive);
} }
Result FileSystemServiceObject::DeleteFile(const tma::Path &path, bool case_sensitive) { Result FileSystemServiceObject::DeleteFile(const tma::Path &path, bool case_sensitive) {
AMS_ABORT("FileSystemServiceObject::DeleteFile"); /* Check that the path is valid. */
R_UNLESS(IsValidPath(path), htcfs::ResultInvalidArgument());
/* Delete the file. */
return htcfs::GetClient().DeleteFile(path.str, case_sensitive);
} }
Result FileSystemServiceObject::RenameFile(const tma::Path &old_path, const tma::Path &new_path, bool case_sensitive) { Result FileSystemServiceObject::RenameFile(const tma::Path &old_path, const tma::Path &new_path, bool case_sensitive) {
AMS_ABORT("FileSystemServiceObject::RenameFile"); /* Check that the paths are valid. */
R_UNLESS(IsValidPath(old_path), htcfs::ResultInvalidArgument());
R_UNLESS(IsValidPath(new_path), htcfs::ResultInvalidArgument());
/* Rename the file. */
return htcfs::GetClient().RenameFile(old_path.str, new_path.str, case_sensitive);
} }
Result FileSystemServiceObject::GetIOType(sf::Out<s32> out, const tma::Path &path, bool case_sensitive) { Result FileSystemServiceObject::GetIOType(sf::Out<s32> out, const tma::Path &path, bool case_sensitive) {
AMS_ABORT("FileSystemServiceObject::GetIOType"); /* Check that the path is valid. */
R_UNLESS(IsValidPath(path), htcfs::ResultInvalidArgument());
/* Get the entry type. */
static_assert(sizeof(s32) == sizeof(fs::DirectoryEntryType));
return htcfs::GetClient().GetEntryType(reinterpret_cast<fs::DirectoryEntryType *>(out.GetPointer()), path.str, case_sensitive);
} }
Result FileSystemServiceObject::OpenDirectory(sf::Out<sf::SharedPointer<tma::IDirectoryAccessor>> out, const tma::Path &path, s32 open_mode, bool case_sensitive) { Result FileSystemServiceObject::OpenDirectory(sf::Out<sf::SharedPointer<tma::IDirectoryAccessor>> out, const tma::Path &path, s32 open_mode, bool case_sensitive) {
@ -80,35 +129,68 @@ namespace ams::htcfs {
} }
Result FileSystemServiceObject::DirectoryExists(sf::Out<bool> out, const tma::Path &path, bool case_sensitive) { Result FileSystemServiceObject::DirectoryExists(sf::Out<bool> out, const tma::Path &path, bool case_sensitive) {
AMS_ABORT("FileSystemServiceObject::DirectoryExists"); /* Check that the path is valid. */
R_UNLESS(IsValidPath(path), htcfs::ResultInvalidArgument());
/* Get whether the file exists. */
return htcfs::GetClient().DirectoryExists(out.GetPointer(), path.str, case_sensitive);
} }
Result FileSystemServiceObject::CreateDirectory(const tma::Path &path, bool case_sensitive) { Result FileSystemServiceObject::CreateDirectory(const tma::Path &path, bool case_sensitive) {
AMS_ABORT("FileSystemServiceObject::CreateDirectory"); /* Check that the path is valid. */
R_UNLESS(IsValidPath(path), htcfs::ResultInvalidArgument());
/* Create the directory. */
return htcfs::GetClient().CreateDirectory(path.str, case_sensitive);
} }
Result FileSystemServiceObject::DeleteDirectory(const tma::Path &path, bool recursively, bool case_sensitive) { Result FileSystemServiceObject::DeleteDirectory(const tma::Path &path, bool recursively, bool case_sensitive) {
AMS_ABORT("FileSystemServiceObject::DeleteDirectory"); /* Check that the path is valid. */
R_UNLESS(IsValidPath(path), htcfs::ResultInvalidArgument());
/* Delete the directory. */
return htcfs::GetClient().DeleteDirectory(path.str, recursively, case_sensitive);
} }
Result FileSystemServiceObject::RenameDirectory(const tma::Path &old_path, const tma::Path &new_path, bool case_sensitive) { Result FileSystemServiceObject::RenameDirectory(const tma::Path &old_path, const tma::Path &new_path, bool case_sensitive) {
AMS_ABORT("FileSystemServiceObject::RenameDirectory"); /* Check that the paths are valid. */
R_UNLESS(IsValidPath(old_path), htcfs::ResultInvalidArgument());
R_UNLESS(IsValidPath(new_path), htcfs::ResultInvalidArgument());
/* Rename the file. */
return htcfs::GetClient().RenameDirectory(old_path.str, new_path.str, case_sensitive);
} }
Result FileSystemServiceObject::CreateFile(const tma::Path &path, s64 size, bool case_sensitive) { Result FileSystemServiceObject::CreateFile(const tma::Path &path, s64 size, bool case_sensitive) {
AMS_ABORT("FileSystemServiceObject::CreateFile"); /* Check that the path is valid. */
R_UNLESS(IsValidPath(path), htcfs::ResultInvalidArgument());
/* Create the file. */
return htcfs::GetClient().CreateFile(path.str, size, case_sensitive);
} }
Result FileSystemServiceObject::GetFileTimeStamp(sf::Out<u64> out_create, sf::Out<u64> out_access, sf::Out<u64> out_modify, const tma::Path &path, bool case_sensitive) { Result FileSystemServiceObject::GetFileTimeStamp(sf::Out<u64> out_create, sf::Out<u64> out_access, sf::Out<u64> out_modify, const tma::Path &path, bool case_sensitive) {
AMS_ABORT("FileSystemServiceObject::GetFileTimeStamp"); /* Check that the path is valid. */
R_UNLESS(IsValidPath(path), htcfs::ResultInvalidArgument());
/* Get the timestamp. */
return htcfs::GetClient().GetFileTimeStamp(out_create.GetPointer(), out_access.GetPointer(), out_modify.GetPointer(), path.str, case_sensitive);
} }
Result FileSystemServiceObject::GetCaseSensitivePath(const tma::Path &path, const sf::OutBuffer &out) { Result FileSystemServiceObject::GetCaseSensitivePath(const tma::Path &path, const sf::OutBuffer &out) {
AMS_ABORT("FileSystemServiceObject::GetCaseSensitivePath"); /* Check that the path is valid. */
R_UNLESS(IsValidPath(path), htcfs::ResultInvalidArgument());
/* Get the case sensitive path. */
return htcfs::GetClient().GetCaseSensitivePath(reinterpret_cast<char *>(out.GetPointer()), out.GetSize(), path.str);
} }
Result FileSystemServiceObject::GetDiskFreeSpaceExW(sf::Out<s64> out_free, sf::Out<s64> out_total, sf::Out<s64> out_total_free, const tma::Path &path) { Result FileSystemServiceObject::GetDiskFreeSpaceExW(sf::Out<s64> out_free, sf::Out<s64> out_total, sf::Out<s64> out_total_free, const tma::Path &path) {
AMS_ABORT("FileSystemServiceObject::GetDiskFreeSpaceExW"); /* Check that the path is valid. */
R_UNLESS(IsValidPath(path), htcfs::ResultInvalidArgument());
/* Get the timestamp. */
return htcfs::GetClient().GetDiskFreeSpace(out_free.GetPointer(), out_total.GetPointer(), out_total_free.GetPointer(), path.str);
} }
} }

View file

@ -115,10 +115,62 @@ namespace ams::htcfs {
return this->MakeRequestHeader(out, PacketType::SetProtocolVersion, 0, version); return this->MakeRequestHeader(out, PacketType::SetProtocolVersion, 0, version);
} }
void MakeOpenFileHeader(Header *out, int path_len, fs::OpenMode mode, bool case_sensitive, s64 cache_size) {
return this->MakeRequestHeader(out, PacketType::OpenFile, path_len, static_cast<s64>(mode), case_sensitive ? 1 : 0, cache_size);
}
void MakeFileExistsHeader(Header *out, int path_len, bool case_sensitive) {
return this->MakeRequestHeader(out, PacketType::FileExists, path_len, case_sensitive ? 1 : 0);
}
void MakeDeleteFileHeader(Header *out, int path_len, bool case_sensitive) {
return this->MakeRequestHeader(out, PacketType::DeleteFile, path_len, case_sensitive ? 1 : 0);
}
void MakeRenameFileHeader(Header *out, int old_path_len, int new_path_len, bool case_sensitive) {
return this->MakeRequestHeader(out, PacketType::RenameFile, old_path_len + new_path_len, old_path_len, new_path_len, case_sensitive ? 1 : 0);
}
void MakeGetEntryTypeHeader(Header *out, int path_len, bool case_sensitive) {
return this->MakeRequestHeader(out, PacketType::GetEntryType, path_len, case_sensitive ? 1 : 0);
}
void MakeOpenDirectoryHeader(Header *out, int path_len, fs::OpenDirectoryMode mode, bool case_sensitive) { 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); return this->MakeRequestHeader(out, PacketType::OpenDirectory, path_len, static_cast<s64>(mode), case_sensitive ? 1 : 0);
} }
void MakeDirectoryExistsHeader(Header *out, int path_len, bool case_sensitive) {
return this->MakeRequestHeader(out, PacketType::DirectoryExists, path_len, case_sensitive ? 1 : 0);
}
void MakeCreateDirectoryHeader(Header *out, int path_len, bool case_sensitive) {
return this->MakeRequestHeader(out, PacketType::CreateDirectory, path_len, case_sensitive ? 1 : 0);
}
void MakeDeleteDirectoryHeader(Header *out, int path_len, bool recursively, bool case_sensitive) {
return this->MakeRequestHeader(out, PacketType::DeleteDirectory, path_len, recursively ? 1 : 0, case_sensitive ? 1 : 0);
}
void MakeRenameDirectoryHeader(Header *out, int old_path_len, int new_path_len, bool case_sensitive) {
return this->MakeRequestHeader(out, PacketType::RenameDirectory, old_path_len + new_path_len, old_path_len, new_path_len, case_sensitive ? 1 : 0);
}
void MakeCreateFileHeader(Header *out, int path_len, s64 size, bool case_sensitive) {
return this->MakeRequestHeader(out, PacketType::CreateDirectory, path_len, size, case_sensitive ? 1 : 0);
}
void MakeGetFileTimeStampHeader(Header *out, int path_len, bool case_sensitive) {
return this->MakeRequestHeader(out, PacketType::GetFileTimeStamp, path_len, case_sensitive ? 1 : 0);
}
void MakeGetCaseSensitivePathHeader(Header *out, int path_len) {
return this->MakeRequestHeader(out, PacketType::GetCaseSensitivePath, path_len);
}
void MakeGetDiskFreeSpaceHeader(Header *out, int path_len) {
return this->MakeRequestHeader(out, PacketType::GetDiskFreeSpace, path_len);
}
void MakeCloseDirectoryHeader(Header *out, s32 handle) { void MakeCloseDirectoryHeader(Header *out, s32 handle) {
return this->MakeRequestHeader(out, PacketType::CloseDirectory, 0, handle); return this->MakeRequestHeader(out, PacketType::CloseDirectory, 0, handle);
} }
@ -142,6 +194,46 @@ namespace ams::htcfs {
void MakeSetPriorityForDirectoryHeader(Header *out, s32 handle, s32 priority) { void MakeSetPriorityForDirectoryHeader(Header *out, s32 handle, s32 priority) {
return this->MakeRequestHeader(out, PacketType::SetPriorityForDirectory, 0, handle, priority); return this->MakeRequestHeader(out, PacketType::SetPriorityForDirectory, 0, handle, priority);
} }
void MakeCloseFileHeader(Header *out, s32 handle) {
return this->MakeRequestHeader(out, PacketType::CloseFile, 0, handle);
}
void MakeReadFileHeader(Header *out, s32 handle, s64 offset, s64 buffer_size) {
return this->MakeRequestHeader(out, PacketType::ReadFile, 0, handle, offset, buffer_size);
}
void MakeReadFileLargeHeader(Header *out, s32 handle, s64 offset, s64 buffer_size, u16 data_channel_id) {
return this->MakeRequestHeader(out, PacketType::ReadFileLarge, 0, handle, offset, buffer_size, data_channel_id);
}
void MakeWriteFileHeader(Header *out, s64 buffer_size, s32 handle, u32 option, s64 offset) {
return this->MakeRequestHeader(out, PacketType::WriteFile, buffer_size, handle, option, offset);
}
void MakeWriteFileLargeHeader(Header *out, s32 handle, u32 option, s64 offset, s64 buffer_size, u16 data_channel_id) {
return this->MakeRequestHeader(out, PacketType::WriteFileLarge, 0, handle, option, offset, buffer_size, data_channel_id);
}
void MakeGetFileSizeHeader(Header *out, s32 handle) {
return this->MakeRequestHeader(out, PacketType::GetFileSize, 0, handle);
}
void MakeSetFileSizeHeader(Header *out, s32 handle, s64 size) {
return this->MakeRequestHeader(out, PacketType::SetFileSize, 0, handle, size);
}
void MakeFlushFileHeader(Header *out, s32 handle) {
return this->MakeRequestHeader(out, PacketType::FlushFile, 0, handle);
}
void MakeGetPriorityForFileHeader(Header *out, s32 handle) {
return this->MakeRequestHeader(out, PacketType::GetPriorityForFile, 0, handle);
}
void MakeSetPriorityForFileHeader(Header *out, s32 handle, s32 priority) {
return this->MakeRequestHeader(out, PacketType::SetPriorityForFile, 0, handle, priority);
}
}; };
} }

View file

@ -26,6 +26,7 @@ namespace ams::htcfs {
InvalidRequest = 3, InvalidRequest = 3,
InvalidHandle = 4, InvalidHandle = 4,
OutOfHandle = 5, OutOfHandle = 5,
Ready = 6,
}; };
inline Result ConvertHtcfsResult(HtcfsResult result) { inline Result ConvertHtcfsResult(HtcfsResult result) {