From 27de9ea37b6defc39cb6515f058f262d68625651 Mon Sep 17 00:00:00 2001 From: Adubbz Date: Wed, 25 Mar 2020 12:52:14 +1100 Subject: [PATCH] ncm client: implement PackageInstallTaskBase --- .../include/stratosphere/ncm.hpp | 3 +- ...all_task.hpp => ncm_install_task_base.hpp} | 0 .../ncm/ncm_package_install_task_base.hpp | 45 ++++++++++ .../source/ncm/ncm_content_id_utils.cpp | 20 ++++- ...all_task.cpp => ncm_install_task_base.cpp} | 0 .../ncm/ncm_package_install_task_base.cpp | 90 +++++++++++++++++++ 6 files changed, 156 insertions(+), 2 deletions(-) rename libraries/libstratosphere/include/stratosphere/ncm/{ncm_install_task.hpp => ncm_install_task_base.hpp} (100%) create mode 100644 libraries/libstratosphere/include/stratosphere/ncm/ncm_package_install_task_base.hpp rename libraries/libstratosphere/source/ncm/{ncm_install_task.cpp => ncm_install_task_base.cpp} (100%) create mode 100644 libraries/libstratosphere/source/ncm/ncm_package_install_task_base.cpp diff --git a/libraries/libstratosphere/include/stratosphere/ncm.hpp b/libraries/libstratosphere/include/stratosphere/ncm.hpp index e5d85dd68..78b5a4d6e 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm.hpp @@ -28,7 +28,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task_base.hpp similarity index 100% rename from libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task.hpp rename to libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task_base.hpp diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_package_install_task_base.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_package_install_task_base.hpp new file mode 100644 index 000000000..e923ccf45 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_package_install_task_base.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019-2020 Adubbz, Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include + +namespace ams::ncm { + + class PackageInstallTaskBase : public InstallTaskBase { + private: + using PackagePath = kvdb::BoundedString<256>; + private: + PackagePath package_root; + void *buffer; + size_t buffer_size; + public: + Result Initialize(const char *package_path, void *buffer, size_t buffer_size, StorageId storage_id, InstallTaskDataBase *data, u32 config); + protected: + const char *GetPackageRootPath() { + return this->package_root.Get(); + } + private: + void CreateContentMetaPath(PackagePath *out_path, ContentId content_id); + void CreateContentPath(PackagePath *out_path, ContentId content_id); + Result InstallTicket(const fs::RightsId &rights_id, ContentMetaType meta_type); + void CreateTicketPath(PackagePath *out_path, fs::RightsId id); + void CreateCertificatePath(PackagePath *out_path, fs::RightsId id); + private: + virtual Result OnWritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info) override; + }; + +} diff --git a/libraries/libstratosphere/source/ncm/ncm_content_id_utils.cpp b/libraries/libstratosphere/source/ncm/ncm_content_id_utils.cpp index 4450693c3..a0a27b9d1 100644 --- a/libraries/libstratosphere/source/ncm/ncm_content_id_utils.cpp +++ b/libraries/libstratosphere/source/ncm/ncm_content_id_utils.cpp @@ -48,7 +48,6 @@ namespace ams::ncm { } - ContentIdString GetContentIdString(ContentId id) { ContentIdString str; GetStringFromContentId(str.data, sizeof(str), id); @@ -60,6 +59,25 @@ namespace ams::ncm { GetStringFromBytes(dst, std::addressof(id), sizeof(id)); } + void GetStringFromRightsId(char *dst, size_t dst_size, fs::RightsId id) { + AMS_ABORT_UNLESS(dst_size > RightsIdStringLength); + GetStringFromBytes(dst, std::addressof(id), sizeof(id)); + } + + void GetTicketFileStringFromRightsId(char *dst, size_t dst_size, fs::RightsId id) { + AMS_ABORT_UNLESS(dst_size > TicketFileStringLength); + ContentIdString str; + GetStringFromRightsId(str.data, sizeof(str), id); + std::snprintf(dst, dst_size, "%s.tik", str.data); + } + + void GetCertificateFileStringFromRightsId(char *dst, size_t dst_size, fs::RightsId id) { + AMS_ABORT_UNLESS(dst_size > CertFileStringLength); + ContentIdString str; + GetStringFromRightsId(str.data, sizeof(str), id); + std::snprintf(dst, dst_size, "%s.cert", str.data); + } + std::optional GetContentIdFromString(const char *str, size_t len) { if (len < ContentIdStringLength) { return std::nullopt; diff --git a/libraries/libstratosphere/source/ncm/ncm_install_task.cpp b/libraries/libstratosphere/source/ncm/ncm_install_task_base.cpp similarity index 100% rename from libraries/libstratosphere/source/ncm/ncm_install_task.cpp rename to libraries/libstratosphere/source/ncm/ncm_install_task_base.cpp diff --git a/libraries/libstratosphere/source/ncm/ncm_package_install_task_base.cpp b/libraries/libstratosphere/source/ncm/ncm_package_install_task_base.cpp new file mode 100644 index 000000000..da8916e22 --- /dev/null +++ b/libraries/libstratosphere/source/ncm/ncm_package_install_task_base.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019-2020 Adubbz, Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::ncm { + + Result PackageInstallTaskBase::Initialize(const char *package_path, void *buffer, size_t buffer_size, StorageId storage_id, InstallTaskDataBase *data, u32 config) { + R_TRY(InstallTaskBase::Initialize(storage_id, data, config)); + this->package_root.Set(package_path); + this->buffer = buffer; + this->buffer_size = buffer_size; + return ResultSuccess(); + } + + Result PackageInstallTaskBase::OnWritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info) { + PackagePath path; + if (content_info->GetType() == ContentType::Meta) { + this->CreateContentMetaPath(std::addressof(path), content_info->GetId()); + } else { + this->CreateContentPath(std::addressof(path), content_info->GetId()); + } + /* Open the file. */ + fs::FileHandle file; + R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + /* Continuously write the file to the placeholder until there is nothing left to write. */ + while (true) { + /* Read as much of the remainder of the file as possible. */ + size_t size_read; + R_TRY(fs::ReadFile(std::addressof(size_read), file, content_info->written, this->buffer, this->buffer_size)); + + /* There is nothing left to read. */ + if (size_read == 0) { + break; + } + + /* Write the placeholder. */ + R_TRY(this->WritePlaceHolderBuffer(content_info, this->buffer, size_read)); + } + + return ResultSuccess(); + } + + void PackageInstallTaskBase::CreateContentMetaPath(PackagePath *out_path, ContentId content_id) { + char str[ContentIdStringLength + 1] = {}; + GetStringFromContentId(str, sizeof(str), content_id); + out_path->SetFormat("%s%s%s", this->package_root.Get(), str, ".cnmt.nca"); + } + + void PackageInstallTaskBase::CreateContentPath(PackagePath *out_path, ContentId content_id) { + char str[ContentIdStringLength + 1] = {}; + GetStringFromContentId(str, sizeof(str), content_id); + out_path->SetFormat("%s%s%s", this->package_root.Get(), str, ".nca"); + } + + Result PackageInstallTaskBase::InstallTicket(const fs::RightsId &rights_id, ContentMetaType meta_type) { + /* TODO: Read ticket from file. */ + /* TODO: Read certificate from file. */ + /* TODO: es::ImportTicket() */ + /* TODO: How should es be handled without undesired effects? */ + return ResultSuccess(); + } + + void PackageInstallTaskBase::CreateTicketPath(PackagePath *out_path, fs::RightsId id) { + char str[RightsIdStringLength + 1] = {}; + GetStringFromRightsId(str, sizeof(str), id); + out_path->SetFormat("%s%s%s", this->package_root.Get(), str, ".tik"); + } + + void PackageInstallTaskBase::CreateCertificatePath(PackagePath *out_path, fs::RightsId id) { + char str[RightsIdStringLength + 1] = {}; + GetStringFromRightsId(str, sizeof(str), id); + out_path->SetFormat("%s%s%s", this->package_root.Get(), str, ".cert"); + } + +}