Remote: SFTP upload via system OpenSSH client
This commit is contained in:
+72
-18
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user