From 22b669fae0e4a7b7828b50fb0f66ea7f217e80ff Mon Sep 17 00:00:00 2001 From: Nikolai Fedorov Date: Sat, 25 Apr 2026 10:46:20 +0300 Subject: [PATCH] create backup only when receiver found --- include/TransferState.hpp | 10 ++++---- include/client.hpp | 7 +++--- source/TitlesLayout.cpp | 10 ++------ source/client.cpp | 49 ++++++++++++++++++++++----------------- source/io.cpp | 1 + source/title.cpp | 4 ---- 6 files changed, 40 insertions(+), 41 deletions(-) diff --git a/include/TransferState.hpp b/include/TransferState.hpp index e7753c4..d3adc61 100644 --- a/include/TransferState.hpp +++ b/include/TransferState.hpp @@ -11,14 +11,16 @@ struct TransferState { std::atomic bytes_total{0}; std::string status; + std::string fail_reason; mutable std::mutex status_mutex; void reset() { - done = false; - cancelled = false; + done = false; + cancelled = false; connection_failed = false; - bytes_done = 0; - bytes_total = 0; + bytes_done = 0; + bytes_total = 0; + fail_reason.clear(); std::lock_guard lock(status_mutex); status.clear(); } diff --git a/include/client.hpp b/include/client.hpp index f62c79b..a5b8cef 100644 --- a/include/client.hpp +++ b/include/client.hpp @@ -1,12 +1,11 @@ -#include #include -namespace fs = std::filesystem; -using path = fs::path; +#include -int transfer_files(path directory); +int transfer_files(size_t index, AccountUid uid); bool isClientTransferDone(); bool isClientTransferCancelled(); bool isClientConnectionFailed(); void cancelClientTransfer(); double getClientProgress(); std::string getClientStatusText(); +std::string getClientFailReason(); diff --git a/source/TitlesLayout.cpp b/source/TitlesLayout.cpp index 47cc672..557f9a4 100644 --- a/source/TitlesLayout.cpp +++ b/source/TitlesLayout.cpp @@ -46,18 +46,12 @@ namespace ui { switch (opt) { case 0: { // Transfer selected - auto backupResult = io::backup(index, g_currentUId); - if (!std::get<0>(backupResult)) { - mainApp->CreateShowDialog("Transfer", "Failed to create backup:\n" + std::get<2>(backupResult), {"OK"}, true); - break; - } - auto directory = std::filesystem::path(std::get<2>(backupResult)); { auto ovl = TransferOverlay::New("Transferring save data..."); this->titlesMenu->SetVisible(false); mainApp->StartOverlay(ovl); this->LockInput(); - if (transfer_files(directory) != 0) { + if (transfer_files(index, g_currentUId) != 0) { mainApp->EndOverlay(); this->titlesMenu->SetVisible(true); this->UnlockInput(); @@ -78,7 +72,7 @@ namespace ui { this->UnlockInput(); } if (isClientConnectionFailed()) { - mainApp->CreateShowDialog("Transfer", "No receiver found.\nMake sure the other Switch is in Receive mode.", {"OK"}, true); + mainApp->CreateShowDialog("Transfer", getClientFailReason(), {"OK"}, true); } else if (isClientTransferCancelled()) { mainApp->CreateShowDialog("Transfer", "Transfer cancelled.", {"OK"}, true); } else { diff --git a/source/client.cpp b/source/client.cpp index 3b5d872..4d52a27 100644 --- a/source/client.cpp +++ b/source/client.cpp @@ -14,6 +14,7 @@ #ifdef __SWITCH__ #include +#include #include #endif @@ -32,6 +33,7 @@ bool isClientConnectionFailed() { return g_client_state.connection_failed.loa void cancelClientTransfer() { g_client_state.cancelled.store(true); } double getClientProgress() { return g_client_state.progress(); } std::string getClientStatusText() { return g_client_state.getStatus(); } +std::string getClientFailReason() { return g_client_state.fail_reason; } static bool send_all(int sock, const void* buf, size_t len) { size_t sent = 0; @@ -78,35 +80,52 @@ static bool sendFile(int sock, const fs::path& filepath) { return true; } +struct ThreadArgs { size_t index; AccountUid uid; }; + static int find_server(char* server_ip); -static void fail_connect() { +static void fail_connect(const std::string& reason) { + g_client_state.fail_reason = reason; g_client_state.connection_failed.store(true); g_client_state.done.store(true); } static void* discovery_and_send_thread(void* arg) { - fs::path directory = *static_cast(arg); - delete static_cast(arg); + ThreadArgs* targs = static_cast(arg); + size_t index = targs->index; + AccountUid uid = targs->uid; + delete targs; char server_ip[INET_ADDRSTRLEN]; if (find_server(server_ip) != 0) { - if (!g_client_state.cancelled.load()) fail_connect(); - g_client_state.done.store(true); + if (!g_client_state.cancelled.load()) + fail_connect("No receiver found.\nMake sure the other Switch is in Receive mode."); + else + g_client_state.done.store(true); return nullptr; } if (g_client_state.cancelled.load()) { g_client_state.done.store(true); return nullptr; } + g_client_state.setStatus("Creating backup..."); + auto backupResult = io::backup(index, uid); + if (!std::get<0>(backupResult)) { + fail_connect("Failed to create backup:\n" + std::get<2>(backupResult)); + return nullptr; + } + fs::path directory = std::get<2>(backupResult); + + if (g_client_state.cancelled.load()) { g_client_state.done.store(true); return nullptr; } + g_client_state.setStatus("Connecting..."); Socket tcp(socket(AF_INET, SOCK_STREAM, 0)); - if (!tcp.valid()) { fail_connect(); return nullptr; } + if (!tcp.valid()) { fail_connect("Failed to open socket."); return nullptr; } sockaddr_in serv{}; serv.sin_family = AF_INET; serv.sin_port = htons(proto::TCP_PORT); if (inet_pton(AF_INET, server_ip, &serv.sin_addr) <= 0 || connect(tcp, (sockaddr*)&serv, sizeof(serv)) < 0) { - fail_connect(); + fail_connect("Failed to connect to receiver."); return nullptr; } @@ -179,11 +198,11 @@ static int find_server(char* server_ip) { return -1; } -int transfer_files(fs::path directory) { +int transfer_files(size_t index, AccountUid uid) { g_client_state.reset(); g_client_state.setStatus("Searching for receiver..."); - fs::path* arg = new fs::path(directory); + ThreadArgs* arg = new ThreadArgs{index, uid}; pthread_t thread; if (pthread_create(&thread, nullptr, discovery_and_send_thread, arg) != 0) { delete arg; @@ -192,15 +211,3 @@ int transfer_files(fs::path directory) { pthread_detach(thread); return 0; } - -#ifndef __SWITCH__ -int main(int argc, char* argv[]) { - if (argc < 2) { - std::cerr << "Usage: " << argv[0] << " " << std::endl; - return 1; - } - if (transfer_files(fs::path(argv[1])) != 0) return 1; - while (!isClientTransferDone()) usleep(16000); - return 0; -} -#endif diff --git a/source/io.cpp b/source/io.cpp index f4ca4ef..9316f07 100644 --- a/source/io.cpp +++ b/source/io.cpp @@ -176,6 +176,7 @@ std::tuple io::backup(size_t index, AccountUid uid) std::string suggestion = StringUtils::removeNotAscii(StringUtils::removeAccents(Account::username(title.userId()))); + io::createDirectory(title.path()); std::string dstPath = title.path() + "/" + suggestion; // Write to a temp dir first; rename on success so the existing backup diff --git a/source/title.cpp b/source/title.cpp index 5745f9f..dee7ebf 100644 --- a/source/title.cpp +++ b/source/title.cpp @@ -65,10 +65,6 @@ void Title::init(u8 saveDataType, u64 id, AccountUid userID, const std::string& } } - if (!io::directoryExists(mPath)) { - io::createDirectory(mPath); - } - refreshDirectories(); }