From 786f8a42fa1983b1e92e87d7b0a12e77e2f4fc0f Mon Sep 17 00:00:00 2001 From: ITotalJustice <47043333+ITotalJustice@users.noreply.github.com> Date: Mon, 21 Apr 2025 01:41:20 +0100 Subject: [PATCH] send file name and size via usb, add requirements.txt for usb.py --- sphaira/include/yati/container/base.hpp | 8 ++- sphaira/include/yati/source/stdio.hpp | 2 +- sphaira/include/yati/source/usb.hpp | 1 + sphaira/include/yati/yati.hpp | 11 ++-- sphaira/source/ui/menus/usb_menu.cpp | 10 +++- sphaira/source/yati/container/xci.cpp | 4 +- sphaira/source/yati/source/stdio.cpp | 2 +- sphaira/source/yati/source/usb.cpp | 24 ++++++++- sphaira/source/yati/yati.cpp | 67 +++++++++++-------------- tools/requirements.txt | 1 + tools/usb_total.py | 13 ++++- 11 files changed, 89 insertions(+), 54 deletions(-) create mode 100644 tools/requirements.txt diff --git a/sphaira/include/yati/container/base.hpp b/sphaira/include/yati/container/base.hpp index 5fdfb47..75c4e5a 100644 --- a/sphaira/include/yati/container/base.hpp +++ b/sphaira/include/yati/container/base.hpp @@ -3,6 +3,7 @@ #include "yati/source/base.hpp" #include #include +#include #include namespace sphaira::yati::container { @@ -28,12 +29,15 @@ using Collections = std::vector; struct Base { using Source = source::Base; - Base(Source* source) : m_source{source} { } + Base(std::shared_ptr source) : m_source{source} { } virtual ~Base() = default; virtual Result GetCollections(Collections& out) = 0; + auto GetSource() const { + return m_source; + } protected: - Source* m_source; + std::shared_ptr m_source; }; } // namespace sphaira::yati::container diff --git a/sphaira/include/yati/source/stdio.hpp b/sphaira/include/yati/source/stdio.hpp index db18a6e..a6c73c1 100644 --- a/sphaira/include/yati/source/stdio.hpp +++ b/sphaira/include/yati/source/stdio.hpp @@ -8,7 +8,7 @@ namespace sphaira::yati::source { struct Stdio final : Base { - Stdio(const char* path); + Stdio(const fs::FsPath& path); ~Stdio(); Result Read(void* buf, s64 off, s64 size, u64* bytes_read) override; diff --git a/sphaira/include/yati/source/usb.hpp b/sphaira/include/yati/source/usb.hpp index 1ac51af..7970e33 100644 --- a/sphaira/include/yati/source/usb.hpp +++ b/sphaira/include/yati/source/usb.hpp @@ -25,6 +25,7 @@ struct Usb final : Base { Result Init(); Result WaitForConnection(u64 timeout, u32& speed, u32& count); + Result GetFileInfo(std::string& name_out, u64& size_out); private: enum UsbSessionEndpoint { diff --git a/sphaira/include/yati/yati.hpp b/sphaira/include/yati/yati.hpp index 5be9fb3..05c94c9 100644 --- a/sphaira/include/yati/yati.hpp +++ b/sphaira/include/yati/yati.hpp @@ -9,6 +9,7 @@ #include "fs.hpp" #include "source/base.hpp" +#include "container/base.hpp" #include "ui/progress_box.hpp" #include @@ -116,12 +117,10 @@ struct Config { bool lower_system_version{}; }; -Result InstallFromFile(FsFileSystem* fs, const fs::FsPath& path); -Result InstallFromStdioFile(const char* path); -Result InstallFromSource(std::shared_ptr source); - Result InstallFromFile(ui::ProgressBox* pbox, FsFileSystem* fs, const fs::FsPath& path); -Result InstallFromStdioFile(ui::ProgressBox* pbox, const char* path); -Result InstallFromSource(ui::ProgressBox* pbox, std::shared_ptr source); +Result InstallFromStdioFile(ui::ProgressBox* pbox, const fs::FsPath& path); +Result InstallFromSource(ui::ProgressBox* pbox, std::shared_ptr source, const fs::FsPath& path); +Result InstallFromContainer(ui::ProgressBox* pbox, std::shared_ptr container); +Result InstallFromCollections(ui::ProgressBox* pbox, std::shared_ptr source, const container::Collections& collections); } // namespace sphaira::yati diff --git a/sphaira/source/ui/menus/usb_menu.cpp b/sphaira/source/ui/menus/usb_menu.cpp index 472e278..2c2ac75 100644 --- a/sphaira/source/ui/menus/usb_menu.cpp +++ b/sphaira/source/ui/menus/usb_menu.cpp @@ -102,7 +102,15 @@ void Menu::Update(Controller* controller, TouchInfo* touch) { App::Push(std::make_shared("Installing App"_i18n, [this](auto pbox) mutable -> bool { log_write("inside progress box\n"); for (u32 i = 0; i < m_usb_count; i++) { - const auto rc = yati::InstallFromSource(pbox, m_usb_source); + std::string file_name; + u64 file_size; + if (R_FAILED(m_usb_source->GetFileInfo(file_name, file_size))) { + return false; + } + + log_write("got file name: %s size: %lX\n", file_name.c_str(), file_size); + + const auto rc = yati::InstallFromSource(pbox, m_usb_source, file_name); if (R_FAILED(rc)) { return false; } diff --git a/sphaira/source/yati/container/xci.cpp b/sphaira/source/yati/container/xci.cpp index ab0213f..d55ae41 100644 --- a/sphaira/source/yati/container/xci.cpp +++ b/sphaira/source/yati/container/xci.cpp @@ -70,12 +70,12 @@ Result Xci::Validate(source::Base* source) { Result Xci::GetCollections(Collections& out) { Hfs0 root{}; - R_TRY(Hfs0GetPartition(m_source, HFS0_HEADER_OFFSET, root)); + R_TRY(Hfs0GetPartition(m_source.get(), HFS0_HEADER_OFFSET, root)); for (u32 i = 0; i < root.header.total_files; i++) { if (root.string_table[i] == "secure") { Hfs0 secure{}; - R_TRY(Hfs0GetPartition(m_source, root.data_offset + root.file_table[i].data_offset, secure)); + R_TRY(Hfs0GetPartition(m_source.get(), root.data_offset + root.file_table[i].data_offset, secure)); for (u32 i = 0; i < secure.header.total_files; i++) { CollectionEntry entry; diff --git a/sphaira/source/yati/source/stdio.cpp b/sphaira/source/yati/source/stdio.cpp index 1a70590..6a4880e 100644 --- a/sphaira/source/yati/source/stdio.cpp +++ b/sphaira/source/yati/source/stdio.cpp @@ -2,7 +2,7 @@ namespace sphaira::yati::source { -Stdio::Stdio(const char* path) { +Stdio::Stdio(const fs::FsPath& path) { m_file = std::fopen(path, "rb"); if (!m_file) { m_open_result = fsdevGetLastResult(); diff --git a/sphaira/source/yati/source/usb.cpp b/sphaira/source/yati/source/usb.cpp index e99ba50..21b7bf1 100644 --- a/sphaira/source/yati/source/usb.cpp +++ b/sphaira/source/yati/source/usb.cpp @@ -22,7 +22,7 @@ namespace sphaira::yati::source { namespace { constexpr u32 MAGIC = 0x53504841; -constexpr u32 VERSION = 1; +constexpr u32 VERSION = 2; struct SendHeader { u32 magic; @@ -224,6 +224,28 @@ Result Usb::WaitForConnection(u64 timeout, u32& speed, u32& count) { R_SUCCEED(); } +Result Usb::GetFileInfo(std::string& name_out, u64& size_out) { + struct { + u64 size; + u64 name_length; + } file_info_meta; + + alignas(0x1000) u8 aligned[0x1000]{}; + + // receive meta. + u32 transferredSize; + R_TRY(TransferPacketImpl(true, aligned, sizeof(file_info_meta), &transferredSize, m_transfer_timeout)); + std::memcpy(&file_info_meta, aligned, sizeof(file_info_meta)); + R_UNLESS(file_info_meta.name_length < sizeof(aligned), 0x1); + + R_TRY(TransferPacketImpl(true, aligned, file_info_meta.name_length, &transferredSize, m_transfer_timeout)); + name_out.resize(file_info_meta.name_length); + std::memcpy(name_out.data(), aligned, name_out.size()); + + size_out = file_info_meta.size; + R_SUCCEED(); +} + bool Usb::GetConfigured() const { UsbState usb_state; usbDsGetState(std::addressof(usb_state)); diff --git a/sphaira/source/yati/yati.cpp b/sphaira/source/yati/yati.cpp index 40f0a79..060e93d 100644 --- a/sphaira/source/yati/yati.cpp +++ b/sphaira/source/yati/yati.cpp @@ -284,7 +284,7 @@ struct Yati { Yati(ui::ProgressBox*, std::shared_ptr); ~Yati(); - Result Setup(container::Collections& out); + Result Setup(); Result InstallNca(std::span tickets, NcaCollection& nca); Result InstallCnmtNca(std::span tickets, CnmtCollection& cnmt, const container::Collections& collections); Result InstallControlNca(std::span tickets, const CnmtCollection& cnmt, NcaCollection& nca); @@ -778,7 +778,7 @@ Yati::~Yati() { appletSetMediaPlaybackState(false); } -Result Yati::Setup(container::Collections& out) { +Result Yati::Setup() { config.sd_card_install = App::GetApp()->m_install_sd.Get(); config.allow_downgrade = App::GetApp()->m_allow_downgrade.Get(); config.skip_if_already_installed = App::GetApp()->m_skip_if_already_installed.Get(); @@ -812,19 +812,6 @@ Result Yati::Setup(container::Collections& out) { cs = ncm_cs[config.sd_card_install]; db = ncm_db[config.sd_card_install]; - if (R_SUCCEEDED(container::Nsp::Validate(source.get()))) { - log_write("found nsp\n"); - container = std::make_unique(source.get()); - } else if (R_SUCCEEDED(container::Xci::Validate(source.get()))) { - log_write("found xci\n"); - container = std::make_unique(source.get()); - } else { - log_write("found unknown container\n"); - } - - R_UNLESS(container, Result_ContainerNotFound); - R_TRY(container->GetCollections(out)); - R_TRY(parse_keys(keys, true)); R_SUCCEED(); } @@ -1040,11 +1027,9 @@ Result Yati::InstallControlNca(std::span tickets, const CnmtColle R_SUCCEED(); } -Result InstallInternal(ui::ProgressBox* pbox, std::shared_ptr source) { +Result InstallInternal(ui::ProgressBox* pbox, std::shared_ptr source, const container::Collections& collections) { auto yati = std::make_unique(pbox, source); - - container::Collections collections{}; - R_TRY(yati->Setup(collections)); + R_TRY(yati->Setup()); std::vector tickets{}; for (const auto& collection : collections) { @@ -1287,31 +1272,35 @@ Result InstallInternal(ui::ProgressBox* pbox, std::shared_ptr sour } // namespace -Result InstallFromFile(FsFileSystem* fs, const fs::FsPath& path) { - return InstallFromSource(std::make_shared(fs, path)); -} - -Result InstallFromStdioFile(const char* path) { - return InstallFromSource(std::make_shared(path)); -} - -Result InstallFromSource(std::shared_ptr source) { - App::Push(std::make_shared("Installing App"_i18n, [source](auto pbox) mutable -> bool { - return R_SUCCEEDED(InstallFromSource(pbox, source)); - })); - R_SUCCEED(); -} - Result InstallFromFile(ui::ProgressBox* pbox, FsFileSystem* fs, const fs::FsPath& path) { - return InstallFromSource(pbox, std::make_shared(fs, path)); + return InstallFromSource(pbox, std::make_shared(fs, path), path); } -Result InstallFromStdioFile(ui::ProgressBox* pbox, const char* path) { - return InstallFromSource(pbox, std::make_shared(path)); +Result InstallFromStdioFile(ui::ProgressBox* pbox, const fs::FsPath& path) { + return InstallFromSource(pbox, std::make_shared(path), path); } -Result InstallFromSource(ui::ProgressBox* pbox, std::shared_ptr source) { - return InstallInternal(pbox, source); +Result InstallFromSource(ui::ProgressBox* pbox, std::shared_ptr source, const fs::FsPath& path) { + if (R_SUCCEEDED(container::Nsp::Validate(source.get()))) { + log_write("found nsp\n"); + return InstallFromContainer(pbox, std::make_unique(source)); + } else if (R_SUCCEEDED(container::Xci::Validate(source.get()))) { + log_write("found xci\n"); + return InstallFromContainer(pbox, std::make_unique(source)); + } else { + log_write("found unknown container\n"); + R_THROW(Result_ContainerNotFound); + } +} + +Result InstallFromContainer(ui::ProgressBox* pbox, std::shared_ptr container) { + container::Collections collections; + R_TRY(container->GetCollections(collections)); + return InstallFromCollections(pbox, container->GetSource(), collections); +} + +Result InstallFromCollections(ui::ProgressBox* pbox, std::shared_ptr source, const container::Collections& collections) { + return InstallInternal(pbox, source, collections); } } // namespace sphaira::yati diff --git a/tools/requirements.txt b/tools/requirements.txt new file mode 100644 index 0000000..6513d5e --- /dev/null +++ b/tools/requirements.txt @@ -0,0 +1 @@ +pyusb diff --git a/tools/usb_total.py b/tools/usb_total.py index d41ec3e..178f976 100644 --- a/tools/usb_total.py +++ b/tools/usb_total.py @@ -6,11 +6,12 @@ import usb.core import usb.util import time import glob +from pathlib import Path # magic number (SPHA) for the script and switch. MAGIC = 0x53504841 # version of the usb script. -VERSION = 1 +VERSION = 2 # list of supported extensions. EXTS = (".nsp", ".xci", ".nsz", ".xcz") @@ -28,6 +29,15 @@ def verify_switch(bcdUSB, count, in_ep, out_ep): send_data = struct.pack('