mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-18 08:22:04 +00:00
htc: implement the remaining commands for htcfs
This commit is contained in:
parent
1961cb1034
commit
d20bceff75
9 changed files with 1169 additions and 27 deletions
|
@ -51,6 +51,16 @@ namespace ams::htcfs {
|
|||
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) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
|
|
@ -26,14 +26,40 @@ namespace ams::htcfs {
|
|||
public:
|
||||
Client(htclow::HtclowManager *manager) : m_impl(manager) { /* ... */ }
|
||||
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 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 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 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)); }
|
||||
|
||||
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);
|
||||
|
|
|
@ -27,7 +27,8 @@ namespace ams::htcfs {
|
|||
|
||||
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) {
|
||||
return result::impl::MakeResult(value);
|
||||
|
@ -401,6 +402,191 @@ namespace ams::htcfs {
|
|||
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) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
@ -436,6 +622,297 @@ namespace ams::htcfs {
|
|||
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) {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
@ -570,10 +1047,18 @@ namespace ams::htcfs {
|
|||
R_TRY(this->CheckResponseHeader(response, request.packet_type, 0));
|
||||
|
||||
/* 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. */
|
||||
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. */
|
||||
R_UNLESS(static_cast<size_t>(response.params[2]) <= max_out_entries, htcfs::ResultUnexpectedResponseBody());
|
||||
|
@ -648,4 +1133,408 @@ namespace ams::htcfs {
|
|||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -56,7 +56,21 @@ namespace ams::htcfs {
|
|||
void Cancel();
|
||||
void Wait();
|
||||
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 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 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 GetPriorityForDirectory(s32 *out, 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:
|
||||
int WaitAny(htclow::ChannelState state, os::EventType *event);
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <stratosphere.hpp>
|
||||
#include "htcfs_directory_service_object.hpp"
|
||||
#include "htcfs_client.hpp"
|
||||
#include "../htclow/htclow_default_channel_config.hpp"
|
||||
|
||||
namespace ams::htcfs {
|
||||
|
||||
|
|
|
@ -15,42 +15,59 @@
|
|||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "htcfs_file_service_object.hpp"
|
||||
#include "htcfs_client.hpp"
|
||||
|
||||
namespace ams::htcfs {
|
||||
|
||||
FileServiceObject::FileServiceObject(s32 handle) : m_handle(handle) { /* ... */ }
|
||||
|
||||
FileServiceObject::~FileServiceObject() {
|
||||
/* TODO */
|
||||
AMS_ABORT("htcfs::GetClient().CloseFile(m_handle);");
|
||||
htcfs::GetClient().CloseFile(m_handle);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
AMS_ABORT("FileServiceObject::GetFileSize");
|
||||
return htcfs::GetClient().GetFileSize(out.GetPointer(), m_handle);
|
||||
}
|
||||
|
||||
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() {
|
||||
AMS_ABORT("FileServiceObject::FlushFile");
|
||||
return htcfs::GetClient().FlushFile(m_handle);
|
||||
}
|
||||
|
||||
Result FileServiceObject::SetPriorityForFile(s32 priority) {
|
||||
AMS_ABORT("FileServiceObject::SetPriorityForFile");
|
||||
return htcfs::GetClient().SetPriorityForFile(priority, m_handle);
|
||||
}
|
||||
|
||||
Result FileServiceObject::GetPriorityForFile(ams::sf::Out<s32> out) {
|
||||
AMS_ABORT("FileServiceObject::GetPriorityForFile");
|
||||
return htcfs::GetClient().GetPriorityForFile(out.GetPointer(), m_handle);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,26 +44,75 @@ namespace ams::htcfs {
|
|||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
|
@ -80,35 +129,68 @@ namespace ams::htcfs {
|
|||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -115,10 +115,62 @@ namespace ams::htcfs {
|
|||
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) {
|
||||
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) {
|
||||
return this->MakeRequestHeader(out, PacketType::CloseDirectory, 0, handle);
|
||||
}
|
||||
|
@ -142,6 +194,46 @@ namespace ams::htcfs {
|
|||
void MakeSetPriorityForDirectoryHeader(Header *out, s32 handle, s32 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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace ams::htcfs {
|
|||
InvalidRequest = 3,
|
||||
InvalidHandle = 4,
|
||||
OutOfHandle = 5,
|
||||
Ready = 6,
|
||||
};
|
||||
|
||||
inline Result ConvertHtcfsResult(HtcfsResult result) {
|
||||
|
|
Loading…
Reference in a new issue