From 68658a8385b74454c8523efe95ceb81b34bb8812 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 28 Apr 2019 18:49:46 -0400 Subject: module: Create BCAT backend based upon Settings value on construction --- src/core/hle/service/bcat/module.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/core/hle/service/bcat/module.cpp') diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index b7bd738fc..32d3d5cfc 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -38,10 +38,22 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface(); +namespace { +std::unique_ptr CreateBackendFromSettings(DirectoryGetter getter) { + const auto backend = Settings::values.bcat_backend; + +#ifdef YUZU_ENABLE_BOXCAT + if (backend == "boxcat") + return std::make_unique(std::move(getter)); +#endif + + return std::make_unique(std::move(getter)); } +} // Anonymous namespace Module::Interface::Interface(std::shared_ptr module, const char* name) - : ServiceFramework(name), module(std::move(module)) {} + : ServiceFramework(name), module(std::move(module)), + backend(CreateBackendFromSettings(&Service::FileSystem::GetBCATDirectory)) {} Module::Interface::~Interface() = default; -- cgit v1.2.3 From 78d146f907cbab60026f972e1be7cc8eb83e05bb Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 28 Apr 2019 18:51:18 -0400 Subject: bcat: Add commands to create IDeliveryCacheStorageService Used to access contents of download. --- src/core/hle/service/bcat/module.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'src/core/hle/service/bcat/module.cpp') diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 32d3d5cfc..fd742fde2 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -11,7 +11,8 @@ namespace Service::BCAT { class IBcatService final : public ServiceFramework { public: - IBcatService() : ServiceFramework("IBcatService") { + IBcatService(Backend& backend) : ServiceFramework("IBcatService"), backend(backend) { + // clang-format off static const FunctionInfo functions[] = { {10100, nullptr, "RequestSyncDeliveryCache"}, {10101, nullptr, "RequestSyncDeliveryCacheWithDirectoryName"}, @@ -28,6 +29,7 @@ public: {90201, nullptr, "ClearDeliveryCacheStorage"}, {90300, nullptr, "GetPushNotificationLog"}, }; + // clang-format on RegisterHandlers(functions); } }; @@ -37,7 +39,29 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(); + rb.PushIpcInterface(*backend); +void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface( + Service::FileSystem::GetBCATDirectory(Core::CurrentProcess()->GetTitleID())); +} + +void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId( + Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto title_id = rp.PopRaw(); + + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface( + Service::FileSystem::GetBCATDirectory(title_id)); +} + namespace { std::unique_ptr CreateBackendFromSettings(DirectoryGetter getter) { const auto backend = Settings::values.bcat_backend; -- cgit v1.2.3 From 862131ead9cf8e10e4ff220d01cb1be16533d208 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 28 Apr 2019 18:53:03 -0400 Subject: bcat: Implement IDeliveryCacheStorageService commands Used to create subclasses to manage files and directories and to list directories. --- src/core/hle/service/bcat/module.cpp | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) (limited to 'src/core/hle/service/bcat/module.cpp') diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index fd742fde2..2d8341359 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -40,6 +40,64 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface(*backend); +class IDeliveryCacheStorageService final : public ServiceFramework { +public: + IDeliveryCacheStorageService(FileSys::VirtualDir root_) + : ServiceFramework{"IDeliveryCacheStorageService"}, root(std::move(root_)) { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IDeliveryCacheStorageService::CreateFileService, "CreateFileService"}, + {1, &IDeliveryCacheStorageService::CreateDirectoryService, "CreateDirectoryService"}, + {10, &IDeliveryCacheStorageService::EnumerateDeliveryCacheDirectory, "EnumerateDeliveryCacheDirectory"}, + }; + // clang-format on + + RegisterHandlers(functions); + + for (const auto& subdir : root->GetSubdirectories()) { + DirectoryName name{}; + std::memcpy(name.data(), subdir->GetName().data(), + std::min(sizeof(DirectoryName) - 1, subdir->GetName().size())); + entries.push_back(name); + } + } + +private: + void CreateFileService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(root); + } + + void CreateDirectoryService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(root); + } + + void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) { + auto size = ctx.GetWriteBufferSize() / sizeof(DirectoryName); + + LOG_DEBUG(Service_BCAT, "called, size={:016X}", size); + + size = std::min(size, entries.size() - next_read_index); + ctx.WriteBuffer(entries.data() + next_read_index, size * sizeof(DirectoryName)); + next_read_index += size; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(size); + } + + FileSys::VirtualDir root; + std::vector entries; + u64 next_read_index = 0; +}; + void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_BCAT, "called"); -- cgit v1.2.3 From 8812018c1defbd76b9a44aaf8e050bf97c73aeae Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 28 Apr 2019 18:53:39 -0400 Subject: bcat: Implement IDeliveryCacheDirectoryService commands Used to list and get directories at the root level. --- src/core/hle/service/bcat/module.cpp | 99 ++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'src/core/hle/service/bcat/module.cpp') diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 2d8341359..6645599f2 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -40,6 +40,105 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface(*backend); +class IDeliveryCacheDirectoryService final + : public ServiceFramework { +public: + IDeliveryCacheDirectoryService(FileSys::VirtualDir root_) + : ServiceFramework{"IDeliveryCacheDirectoryService"}, root(std::move(root_)) { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IDeliveryCacheDirectoryService::Open, "Open"}, + {1, &IDeliveryCacheDirectoryService::Read, "Read"}, + {2, &IDeliveryCacheDirectoryService::GetCount, "GetCount"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void Open(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto name_raw = rp.PopRaw(); + const auto name = + Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size()); + + LOG_DEBUG(Service_BCAT, "called, name={}", name); + + if (!VerifyNameValidDir(ctx, name_raw)) + return; + + if (current_dir != nullptr) { + LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_ENTITY_ALREADY_OPEN); + return; + } + + current_dir = root->GetSubdirectory(name); + + if (current_dir == nullptr) { + LOG_ERROR(Service_BCAT, "Failed to open the directory name={}!", name); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_FAILED_OPEN_ENTITY); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void Read(Kernel::HLERequestContext& ctx) { + auto write_size = ctx.GetWriteBufferSize() / sizeof(DeliveryCacheDirectoryEntry); + + LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", write_size); + + if (current_dir == nullptr) { + LOG_ERROR(Service_BCAT, "There is no open directory!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + return; + } + + const auto files = current_dir->GetFiles(); + write_size = std::min(write_size, files.size()); + std::vector entries(write_size); + std::transform( + files.begin(), files.begin() + write_size, entries.begin(), [](const auto& file) { + FileName name{}; + std::memcpy(name.data(), file->GetName().data(), + std::min(file->GetName().size(), name.size())); + return DeliveryCacheDirectoryEntry{name, file->GetSize(), DigestFile(file)}; + }); + + ctx.WriteBuffer(entries); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(write_size * sizeof(DeliveryCacheDirectoryEntry)); + } + + void GetCount(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + if (current_dir == nullptr) { + LOG_ERROR(Service_BCAT, "There is no open directory!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + return; + } + + const auto files = current_dir->GetFiles(); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(files.size()); + } + + FileSys::VirtualDir root; + FileSys::VirtualDir current_dir; +}; + class IDeliveryCacheStorageService final : public ServiceFramework { public: IDeliveryCacheStorageService(FileSys::VirtualDir root_) -- cgit v1.2.3 From f352ad5c93aa0266cba8b4c15ee3f0c5f0b0aed2 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 28 Apr 2019 18:54:26 -0400 Subject: bcat: Implement IDeliveryCacheFileService commands Used to read the contents of files and access their metadata. --- src/core/hle/service/bcat/module.cpp | 117 +++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) (limited to 'src/core/hle/service/bcat/module.cpp') diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 6645599f2..25f68ed63 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -40,6 +40,123 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface(*backend); + +class IDeliveryCacheFileService final : public ServiceFramework { +public: + IDeliveryCacheFileService(FileSys::VirtualDir root_) + : ServiceFramework{"IDeliveryCacheFileService"}, root(std::move(root_)) { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IDeliveryCacheFileService::Open, "Open"}, + {1, &IDeliveryCacheFileService::Read, "Read"}, + {2, &IDeliveryCacheFileService::GetSize, "GetSize"}, + {3, &IDeliveryCacheFileService::GetDigest, "GetDigest"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void Open(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto dir_name_raw = rp.PopRaw(); + const auto file_name_raw = rp.PopRaw(); + + const auto dir_name = + Common::StringFromFixedZeroTerminatedBuffer(dir_name_raw.data(), dir_name_raw.size()); + const auto file_name = + Common::StringFromFixedZeroTerminatedBuffer(file_name_raw.data(), file_name_raw.size()); + + LOG_DEBUG(Service_BCAT, "called, dir_name={}, file_name={}", dir_name, file_name); + + if (!VerifyNameValidDir(ctx, dir_name_raw) || !VerifyNameValidFile(ctx, file_name_raw)) + return; + + if (current_file != nullptr) { + LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_ENTITY_ALREADY_OPEN); + return; + } + + const auto dir = root->GetSubdirectory(dir_name); + + if (dir == nullptr) { + LOG_ERROR(Service_BCAT, "The directory of name={} couldn't be opened!", dir_name); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_FAILED_OPEN_ENTITY); + return; + } + + current_file = dir->GetFile(file_name); + + if (current_file == nullptr) { + LOG_ERROR(Service_BCAT, "The file of name={} couldn't be opened!", file_name); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_FAILED_OPEN_ENTITY); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void Read(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto offset{rp.PopRaw()}; + + auto size = ctx.GetWriteBufferSize(); + + LOG_DEBUG(Service_BCAT, "called, offset={:016X}, size={:016X}", offset, size); + + if (current_file == nullptr) { + LOG_ERROR(Service_BCAT, "There is no file currently open!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + } + + size = std::min(current_file->GetSize() - offset, size); + const auto buffer = current_file->ReadBytes(size, offset); + ctx.WriteBuffer(buffer); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(buffer.size()); + } + + void GetSize(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + if (current_file == nullptr) { + LOG_ERROR(Service_BCAT, "There is no file currently open!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + } + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(current_file->GetSize()); + } + + void GetDigest(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + if (current_file == nullptr) { + LOG_ERROR(Service_BCAT, "There is no file currently open!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + } + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw(DigestFile(current_file)); + } + + FileSys::VirtualDir root; + FileSys::VirtualFile current_file; +}; + class IDeliveryCacheDirectoryService final : public ServiceFramework { public: -- cgit v1.2.3 From cb7c96b96a0ad781d5bb4387072d5d0becd74dd7 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 28 Apr 2019 18:55:56 -0400 Subject: bcat: Implement IDeliveryCacheProgressService commands Used to query completion status and events for the current delivery task. --- src/core/hle/service/bcat/module.cpp | 131 +++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) (limited to 'src/core/hle/service/bcat/module.cpp') diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 25f68ed63..1459fab11 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -2,13 +2,144 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include +#include +#include "backend/boxcat.h" +#include "common/hex_util.h" #include "common/logging/log.h" +#include "common/string_util.h" +#include "core/file_sys/vfs.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" +#include "core/hle/service/bcat/backend/backend.h" #include "core/hle/service/bcat/bcat.h" #include "core/hle/service/bcat/module.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/settings.h" namespace Service::BCAT { +constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::BCAT, 1}; +constexpr ResultCode ERROR_FAILED_OPEN_ENTITY{ErrorModule::BCAT, 2}; +constexpr ResultCode ERROR_ENTITY_ALREADY_OPEN{ErrorModule::BCAT, 6}; +constexpr ResultCode ERROR_NO_OPEN_ENTITY{ErrorModule::BCAT, 7}; + +// The command to clear the delivery cache just calls fs IFileSystem DeleteFile on all of the files +// and if any of them have a non-zero result it just forwards that result. This is the FS error code +// for permission denied, which is the closest approximation of this scenario. +constexpr ResultCode ERROR_FAILED_CLEAR_CACHE{ErrorModule::FS, 6400}; + +using BCATDigest = std::array; + +struct DeliveryCacheProgressImpl { + enum class Status : u8 { + Incomplete = 0x1, + Complete = 0x9, + }; + + Status status = Status::Incomplete; + INSERT_PADDING_BYTES( + 0x1FF); ///< TODO(DarkLordZach): RE this structure. It just seems to convey info about the + ///< progress of the BCAT sync, but for us just setting completion works. +}; +static_assert(sizeof(DeliveryCacheProgressImpl) == 0x200, + "DeliveryCacheProgressImpl has incorrect size."); + +namespace { + +u64 GetCurrentBuildID() { + const auto& id = Core::System::GetInstance().GetCurrentProcessBuildID(); + u64 out{}; + std::memcpy(&out, id.data(), sizeof(u64)); + return out; +} + +// The digest is only used to determine if a file is unique compared to others of the same name. +// Since the algorithm isn't ever checked in game, MD5 is safe. +BCATDigest DigestFile(const FileSys::VirtualFile& file) { + BCATDigest out{}; + const auto bytes = file->ReadAllBytes(); + mbedtls_md5(bytes.data(), bytes.size(), out.data()); + return out; +} + +// For a name to be valid it must be non-empty, must have a null terminating character as the final +// char, can only contain numbers, letters, underscores and a hyphen if directory and a period if +// file. +bool VerifyNameValidInternal(Kernel::HLERequestContext& ctx, std::array name, + char match_char) { + const auto null_chars = std::count(name.begin(), name.end(), 0); + const auto bad_chars = std::count_if(name.begin(), name.end(), [match_char](char c) { + return !std::isalnum(static_cast(c)) && c != '_' && c != match_char && c != '\0'; + }); + if (null_chars == 0x20 || null_chars == 0 || bad_chars != 0 || name[0x1F] != '\0') { + LOG_ERROR(Service_BCAT, "Name passed was invalid!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + return false; + } + + return true; +} + +bool VerifyNameValidDir(Kernel::HLERequestContext& ctx, std::array name) { + return VerifyNameValidInternal(ctx, name, '-'); +} + +bool VerifyNameValidFile(Kernel::HLERequestContext& ctx, std::array name) { + return VerifyNameValidInternal(ctx, name, '.'); +} + +} // Anonymous namespace + +using DirectoryName = std::array; +using FileName = std::array; + +struct DeliveryCacheDirectoryEntry { + FileName name; + u64 size; + BCATDigest digest; +}; + +class IDeliveryCacheProgressService final : public ServiceFramework { +public: + IDeliveryCacheProgressService(Kernel::SharedPtr event, + const DeliveryCacheProgressImpl& impl) + : ServiceFramework{"IDeliveryCacheProgressService"}, event(std::move(event)), impl(impl) { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"}, + {1, &IDeliveryCacheProgressService::GetImpl, "GetImpl"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void GetEvent(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(event); + } + + void GetImpl(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + ctx.WriteBuffer(&impl, sizeof(DeliveryCacheProgressImpl)); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + Kernel::SharedPtr event; + const DeliveryCacheProgressImpl& impl; +}; + class IBcatService final : public ServiceFramework { public: IBcatService(Backend& backend) : ServiceFramework("IBcatService"), backend(backend) { -- cgit v1.2.3 From 86773a7f081a8a6c71643ecdc6573b65dbf0ccd3 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 28 Apr 2019 18:57:37 -0400 Subject: bcat: Implement cmd RequestSyncDeliveryCache and variant Variant also supports only updating a single directory. These just both invoke backend commands. --- src/core/hle/service/bcat/module.cpp | 72 +++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) (limited to 'src/core/hle/service/bcat/module.cpp') diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 1459fab11..605aa6e00 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -145,8 +145,8 @@ public: IBcatService(Backend& backend) : ServiceFramework("IBcatService"), backend(backend) { // clang-format off static const FunctionInfo functions[] = { - {10100, nullptr, "RequestSyncDeliveryCache"}, - {10101, nullptr, "RequestSyncDeliveryCacheWithDirectoryName"}, + {10100, &IBcatService::RequestSyncDeliveryCache, "RequestSyncDeliveryCache"}, + {10101, &IBcatService::RequestSyncDeliveryCacheWithDirectoryName, "RequestSyncDeliveryCacheWithDirectoryName"}, {10200, nullptr, "CancelSyncDeliveryCacheRequest"}, {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"}, {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"}, @@ -162,7 +162,74 @@ public: }; // clang-format on RegisterHandlers(functions); + + auto& kernel{Core::System::GetInstance().Kernel()}; + progress.at(static_cast(SyncType::Normal)).event = + Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, + "BCAT::IDeliveryCacheProgressEvent"); + progress.at(static_cast(SyncType::Directory)).event = + Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::OneShot, + "BCAT::IDeliveryCacheProgressEvent::DirectoryName"); + } + +private: + enum class SyncType { + Normal, + Directory, + Count, + }; + + std::function CreateCallback(SyncType type) { + return [this, type](bool success) { + auto& pair{progress.at(static_cast(type))}; + pair.impl.status = DeliveryCacheProgressImpl::Status::Complete; + pair.event.writable->Signal(); + }; + } + + std::shared_ptr CreateProgressService(SyncType type) { + const auto& pair{progress.at(static_cast(type))}; + return std::make_shared(pair.event.readable, pair.impl); } + + void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + backend.Synchronize({Core::CurrentProcess()->GetTitleID(), GetCurrentBuildID()}, + CreateCallback(SyncType::Normal)); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(CreateProgressService(SyncType::Normal)); + } + + void RequestSyncDeliveryCacheWithDirectoryName(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto name_raw = rp.PopRaw(); + const auto name = + Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size()); + + LOG_DEBUG(Service_BCAT, "called, name={}", name); + + backend.SynchronizeDirectory({Core::CurrentProcess()->GetTitleID(), GetCurrentBuildID()}, + name, CreateCallback(SyncType::Directory)); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(CreateProgressService(SyncType::Directory)); + } + + } + + Backend& backend; + + struct ProgressPair { + Kernel::EventPair event; + DeliveryCacheProgressImpl impl; + }; + + std::array(SyncType::Count)> progress{}; }; void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { @@ -171,6 +238,7 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface(*backend); +} class IDeliveryCacheFileService final : public ServiceFramework { public: -- cgit v1.2.3 From 1bde5a3c6a205de445b2086f2fda2a830d70b8f6 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 28 Apr 2019 18:59:35 -0400 Subject: bcat: Implement cmd 30100 SetPassphrase Takes a title ID and passphrase (0x40 byte string) and passes it to the backend. --- src/core/hle/service/bcat/module.cpp | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'src/core/hle/service/bcat/module.cpp') diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 605aa6e00..cbda8e0d3 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -150,7 +150,7 @@ public: {10200, nullptr, "CancelSyncDeliveryCacheRequest"}, {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"}, {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"}, - {30100, nullptr, "SetPassphrase"}, + {30100, &IBcatService::SetPassphrase, "SetPassphrase"}, {30200, nullptr, "RegisterBackgroundDeliveryTask"}, {30201, nullptr, "UnregisterBackgroundDeliveryTask"}, {30202, nullptr, "BlockDeliveryTask"}, @@ -220,6 +220,38 @@ private: rb.PushIpcInterface(CreateProgressService(SyncType::Directory)); } + void SetPassphrase(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto title_id = rp.PopRaw(); + + const auto passphrase_raw = ctx.ReadBuffer(); + + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id, + Common::HexVectorToString(passphrase_raw)); + + if (title_id == 0) { + LOG_ERROR(Service_BCAT, "Invalid title ID!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + } + + if (passphrase_raw.size() > 0x40) { + LOG_ERROR(Service_BCAT, "Passphrase too large!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + return; + } + + Passphrase passphrase{}; + std::memcpy(passphrase.data(), passphrase_raw.data(), + std::min(passphrase.size(), passphrase_raw.size())); + + backend.SetPassphrase(title_id, passphrase); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + } Backend& backend; -- cgit v1.2.3 From 102db206e0cf8c0332e6ec0c2c6f4fa8c7d4f05c Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 28 Apr 2019 19:00:36 -0400 Subject: bcat: Implement cmd 90201 ClearDeliveryCacheStorage Takes a title ID and simply deletes all the data for that title ID's bcat. Invokes the respective backend command. --- src/core/hle/service/bcat/module.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'src/core/hle/service/bcat/module.cpp') diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index cbda8e0d3..9244c265a 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -157,7 +157,7 @@ public: {30203, nullptr, "UnblockDeliveryTask"}, {90100, nullptr, "EnumerateBackgroundDeliveryTask"}, {90200, nullptr, "GetDeliveryList"}, - {90201, nullptr, "ClearDeliveryCacheStorage"}, + {90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"}, {90300, nullptr, "GetPushNotificationLog"}, }; // clang-format on @@ -252,6 +252,28 @@ private: rb.Push(RESULT_SUCCESS); } + void ClearDeliveryCacheStorage(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto title_id = rp.PopRaw(); + + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); + + if (title_id == 0) { + LOG_ERROR(Service_BCAT, "Invalid title ID!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + return; + } + + if (!backend.Clear(title_id)) { + LOG_ERROR(Service_BCAT, "Could not clear the directory successfully!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_FAILED_CLEAR_CACHE); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); } Backend& backend; -- cgit v1.2.3 From ea17b294ea04a00d94025cda97b2cd4d5f730b17 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 1 May 2019 22:41:32 -0400 Subject: bcat: Expose CreateBackendFromSettings helper function --- src/core/hle/service/bcat/module.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/core/hle/service/bcat/module.cpp') diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 9244c265a..a8d545992 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -589,7 +589,6 @@ void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId( Service::FileSystem::GetBCATDirectory(title_id)); } -namespace { std::unique_ptr CreateBackendFromSettings(DirectoryGetter getter) { const auto backend = Settings::values.bcat_backend; @@ -600,7 +599,6 @@ std::unique_ptr CreateBackendFromSettings(DirectoryGetter getter) { return std::make_unique(std::move(getter)); } -} // Anonymous namespace Module::Interface::Interface(std::shared_ptr module, const char* name) : ServiceFramework(name), module(std::move(module)), -- cgit v1.2.3 From 2d410ddf4d9c0109d64fdf3319efeb9e6cc0bce1 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 13 May 2019 18:51:02 -0400 Subject: bcat: Implement DeliveryCacheProgressImpl structure Huge thanks to lioncash for re-ing this for me. --- src/core/hle/service/bcat/module.cpp | 56 +++++++----------------------------- 1 file changed, 11 insertions(+), 45 deletions(-) (limited to 'src/core/hle/service/bcat/module.cpp') diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index a8d545992..d5f9e9d3b 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -33,20 +33,6 @@ constexpr ResultCode ERROR_FAILED_CLEAR_CACHE{ErrorModule::FS, 6400}; using BCATDigest = std::array; -struct DeliveryCacheProgressImpl { - enum class Status : u8 { - Incomplete = 0x1, - Complete = 0x9, - }; - - Status status = Status::Incomplete; - INSERT_PADDING_BYTES( - 0x1FF); ///< TODO(DarkLordZach): RE this structure. It just seems to convey info about the - ///< progress of the BCAT sync, but for us just setting completion works. -}; -static_assert(sizeof(DeliveryCacheProgressImpl) == 0x200, - "DeliveryCacheProgressImpl has incorrect size."); - namespace { u64 GetCurrentBuildID() { @@ -84,19 +70,16 @@ bool VerifyNameValidInternal(Kernel::HLERequestContext& ctx, std::array name) { +bool VerifyNameValidDir(Kernel::HLERequestContext& ctx, DirectoryName name) { return VerifyNameValidInternal(ctx, name, '-'); } -bool VerifyNameValidFile(Kernel::HLERequestContext& ctx, std::array name) { +bool VerifyNameValidFile(Kernel::HLERequestContext& ctx, FileName name) { return VerifyNameValidInternal(ctx, name, '.'); } } // Anonymous namespace -using DirectoryName = std::array; -using FileName = std::array; - struct DeliveryCacheDirectoryEntry { FileName name; u64 size; @@ -162,15 +145,6 @@ public: }; // clang-format on RegisterHandlers(functions); - - auto& kernel{Core::System::GetInstance().Kernel()}; - progress.at(static_cast(SyncType::Normal)).event = - Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, - "BCAT::IDeliveryCacheProgressEvent"); - progress.at(static_cast(SyncType::Directory)).event = - Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, - "BCAT::IDeliveryCacheProgressEvent::DirectoryName"); } private: @@ -180,24 +154,17 @@ private: Count, }; - std::function CreateCallback(SyncType type) { - return [this, type](bool success) { - auto& pair{progress.at(static_cast(type))}; - pair.impl.status = DeliveryCacheProgressImpl::Status::Complete; - pair.event.writable->Signal(); - }; - } - std::shared_ptr CreateProgressService(SyncType type) { - const auto& pair{progress.at(static_cast(type))}; - return std::make_shared(pair.event.readable, pair.impl); + auto& backend{progress.at(static_cast(type))}; + return std::make_shared(backend.GetEvent(), + backend.GetImpl()); } void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_BCAT, "called"); backend.Synchronize({Core::CurrentProcess()->GetTitleID(), GetCurrentBuildID()}, - CreateCallback(SyncType::Normal)); + progress.at(static_cast(SyncType::Normal))); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -213,7 +180,8 @@ private: LOG_DEBUG(Service_BCAT, "called, name={}", name); backend.SynchronizeDirectory({Core::CurrentProcess()->GetTitleID(), GetCurrentBuildID()}, - name, CreateCallback(SyncType::Directory)); + name, + progress.at(static_cast(SyncType::Directory))); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -278,12 +246,10 @@ private: Backend& backend; - struct ProgressPair { - Kernel::EventPair event; - DeliveryCacheProgressImpl impl; + std::array(SyncType::Count)> progress{ + ProgressServiceBackend{"Normal"}, + ProgressServiceBackend{"Directory"}, }; - - std::array(SyncType::Count)> progress{}; }; void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { -- cgit v1.2.3 From bcf1eafb8bd1a810fd33a7e7e06a86173b4bfb9f Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 20 Jun 2019 20:31:17 -0400 Subject: boxcat: Implement events global field --- src/core/hle/service/bcat/module.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core/hle/service/bcat/module.cpp') diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index d5f9e9d3b..1b9a75a1c 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -195,7 +195,7 @@ private: const auto passphrase_raw = ctx.ReadBuffer(); LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id, - Common::HexVectorToString(passphrase_raw)); + Common::HexToString(passphrase_raw)); if (title_id == 0) { LOG_ERROR(Service_BCAT, "Invalid title ID!"); @@ -335,7 +335,7 @@ private: rb.Push(ERROR_NO_OPEN_ENTITY); } - size = std::min(current_file->GetSize() - offset, size); + size = std::min(current_file->GetSize() - offset, size); const auto buffer = current_file->ReadBytes(size, offset); ctx.WriteBuffer(buffer); @@ -437,7 +437,7 @@ private: } const auto files = current_dir->GetFiles(); - write_size = std::min(write_size, files.size()); + write_size = std::min(write_size, files.size()); std::vector entries(write_size); std::transform( files.begin(), files.begin() + write_size, entries.begin(), [](const auto& file) { @@ -519,7 +519,7 @@ private: LOG_DEBUG(Service_BCAT, "called, size={:016X}", size); - size = std::min(size, entries.size() - next_read_index); + size = std::min(size, entries.size() - next_read_index); ctx.WriteBuffer(entries.data() + next_read_index, size * sizeof(DirectoryName)); next_read_index += size; -- cgit v1.2.3 From 19c466dfb1f997eaa16fc9d9b832aaf3321adc40 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Tue, 1 Oct 2019 09:13:09 -0400 Subject: bcat: Add FSC accessors for BCAT data Ports BCAT to use FSC interface --- src/core/hle/service/bcat/module.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'src/core/hle/service/bcat/module.cpp') diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 1b9a75a1c..b3fed56c7 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -539,7 +539,7 @@ void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestCont IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface( - Service::FileSystem::GetBCATDirectory(Core::CurrentProcess()->GetTitleID())); + fsc.GetBCATDirectory(Core::CurrentProcess()->GetTitleID())); } void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId( @@ -551,8 +551,7 @@ void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId( IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface( - Service::FileSystem::GetBCATDirectory(title_id)); + rb.PushIpcInterface(fsc.GetBCATDirectory(title_id)); } std::unique_ptr CreateBackendFromSettings(DirectoryGetter getter) { @@ -566,18 +565,23 @@ std::unique_ptr CreateBackendFromSettings(DirectoryGetter getter) { return std::make_unique(std::move(getter)); } -Module::Interface::Interface(std::shared_ptr module, const char* name) - : ServiceFramework(name), module(std::move(module)), - backend(CreateBackendFromSettings(&Service::FileSystem::GetBCATDirectory)) {} +Module::Interface::Interface(std::shared_ptr module, FileSystem::FileSystemController& fsc, + const char* name) + : ServiceFramework(name), module(std::move(module)), fsc(fsc), + backend(CreateBackendFromSettings([&fsc](u64 tid) { return fsc.GetBCATDirectory(tid); })) {} Module::Interface::~Interface() = default; -void InstallInterfaces(SM::ServiceManager& service_manager) { +void InstallInterfaces(Core::System& system) { auto module = std::make_shared(); - std::make_shared(module, "bcat:a")->InstallAsService(service_manager); - std::make_shared(module, "bcat:m")->InstallAsService(service_manager); - std::make_shared(module, "bcat:u")->InstallAsService(service_manager); - std::make_shared(module, "bcat:s")->InstallAsService(service_manager); + std::make_shared(module, system.GetFileSystemController(), "bcat:a") + ->InstallAsService(system.ServiceManager()); + std::make_shared(module, system.GetFileSystemController(), "bcat:m") + ->InstallAsService(system.ServiceManager()); + std::make_shared(module, system.GetFileSystemController(), "bcat:u") + ->InstallAsService(system.ServiceManager()); + std::make_shared(module, system.GetFileSystemController(), "bcat:s") + ->InstallAsService(system.ServiceManager()); } } // namespace Service::BCAT -- cgit v1.2.3