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:
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;
|
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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue