Remote: SFTP upload via system OpenSSH client

This commit is contained in:
Smile
2026-10-18 14:38:09 +00:00
parent f37e13af3d
commit 34313ce6e1
+72 -18
View File
@@ -1,24 +1,78 @@
#include "versiond/versiond.hpp" #include "versiond/versiond.hpp"
#include <array>
#include <cstdio>
#include <filesystem> #include <filesystem>
#include <sstream>
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace versiond { namespace versiond {
bool remote_upload_wolfssh(const std::string& host, const std::string& user, namespace {
const std::string& local, const std::string& remote, struct Target {
std::string& err) { std::string user, host, port = "22", path;
#ifdef HAVE_WOLFSSH };
(void)host; Target parse_target(const std::string& url, const std::string& user, const std::string& fallback_remote) {
(void)user; Target t;
(void)local; std::string s = url.empty() ? fallback_remote : url;
(void)remote; const std::string pre = "sftp://";
if (s.rfind(pre, 0) == 0) s = s.substr(pre.size());
auto at = s.find('@');
std::string hostpart = s;
if (at != std::string::npos) {
t.user = s.substr(0, at);
hostpart = s.substr(at + 1);
} else {
t.user = user;
}
auto slash = hostpart.find('/');
std::string hp = slash == std::string::npos ? hostpart : hostpart.substr(0, slash);
std::string p = slash == std::string::npos ? "" : hostpart.substr(slash);
auto colon = hp.rfind(':');
if (colon != std::string::npos && hp.find(']') == std::string::npos) {
t.host = hp.substr(0, colon);
t.port = hp.substr(colon + 1);
} else {
t.host = hp;
}
t.path = p.empty() ? fallback_remote : p;
return t;
}
std::string shellq(const std::string& s) {
std::string o = "'";
for (char c : s) {
if (c == '\'') o += "'\\''";
else o += c;
}
return o + "'";
}
} // namespace
bool remote_upload_wolfssh(const std::string& host, const std::string& user, const std::string& local,
const std::string& remote, std::string& err) {
if (!fs::exists(local)) {
err = "local file missing: " + local;
return false;
}
Target t = parse_target(host, user, remote);
if (t.host.empty()) {
err = "no remote host";
return false;
}
std::string dest = t.user.empty() ? t.host : t.user + "@" + t.host;
std::string cmd = "sftp -P " + shellq(t.port) + " -o BatchMode=yes -o StrictHostKeyChecking=accept-new " +
shellq(dest) + " <<'VERSIOND_SFTP_EOF'\nput " + shellq(local) + " " + shellq(t.path) +
"\nVERSIOND_SFTP_EOF 2>&1";
std::array<char, 512> buf{};
std::string out;
FILE* p = popen(cmd.c_str(), "r");
if (!p) {
err = "popen(sftp) failed";
return false;
}
while (fgets(buf.data(), (int)buf.size(), p)) out += buf.data();
int rc = pclose(p);
if (rc != 0) {
err = "sftp exit " + std::to_string(rc) + ": " + out;
return false;
}
err = ""; err = "";
return fs::exists(local); return true;
#else
(void)host;
(void)user;
(void)local;
(void)remote;
err = "wolfssh not vendored yet (deps/wolfssh empty)";
return false;
#endif
}
} }
} // namespace versiond