mirror of
https://github.com/nestriness/cdc-file-transfer.git
synced 2026-01-30 16:45:35 +02:00
Adds support for local syncs of files and folders on the same Windows machine, e.g. cdc_rsync C:\source C:\dest. The two main changes are - Skip the check whether the port is available remotely with PortManager. - Do not deploy cdc_rsync_server. - Run cdc_rsync_server directly, not through an SSH tunnel. The current implementation is not optimal as it starts cdc_rsync_server as a separate process and communicates to it via a TCP port.
171 lines
5.4 KiB
C++
171 lines
5.4 KiB
C++
// Copyright 2022 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "cdc_rsync/server_arch.h"
|
|
|
|
#include <filesystem>
|
|
|
|
#include "absl/strings/match.h"
|
|
#include "absl/strings/str_format.h"
|
|
#include "absl/strings/str_split.h"
|
|
#include "common/path.h"
|
|
#include "common/platform.h"
|
|
#include "common/remote_util.h"
|
|
#include "common/util.h"
|
|
|
|
namespace cdc_ft {
|
|
|
|
constexpr char kErrorFailedToGetKnownFolderPath[] =
|
|
"error_failed_to_get_known_folder_path";
|
|
constexpr char kErrorArchTypeUnhandled[] = "arch_type_unhandled";
|
|
|
|
// static
|
|
ServerArch::Type ServerArch::Detect(const std::string& destination) {
|
|
// Path starting with ~ or / -> Linux.
|
|
if (absl::StartsWith(destination, "~") ||
|
|
absl::StartsWith(destination, "/")) {
|
|
return Type::kLinux;
|
|
}
|
|
|
|
// Path starting with C: etc. -> Windows.
|
|
if (!path::GetDrivePrefix(destination).empty()) {
|
|
return Type::kWindows;
|
|
}
|
|
|
|
// Path with only / -> Linux.
|
|
if (absl::StrContains(destination, "/") &&
|
|
!absl::StrContains(destination, "\\")) {
|
|
return Type::kLinux;
|
|
}
|
|
|
|
// Path with only \\ -> Windows.
|
|
if (absl::StrContains(destination, "\\") &&
|
|
!absl::StrContains(destination, "/")) {
|
|
return Type::kWindows;
|
|
}
|
|
|
|
// Default to Linux.
|
|
return Type::kLinux;
|
|
}
|
|
|
|
// static
|
|
ServerArch::Type ServerArch::LocalType() {
|
|
#if PLATFORM_WINDOWS
|
|
return ServerArch::Type::kWindows;
|
|
#elif PLATFORM_LINUX
|
|
return ServerArch::Type::kLinux;
|
|
#endif
|
|
}
|
|
|
|
// static
|
|
std::string ServerArch::CdcRsyncFilename() {
|
|
switch (LocalType()) {
|
|
case Type::kWindows:
|
|
return "cdc_rsync.exe";
|
|
case Type::kLinux:
|
|
return "cdc_rsync";
|
|
default:
|
|
assert(!kErrorArchTypeUnhandled);
|
|
return std::string();
|
|
}
|
|
}
|
|
|
|
ServerArch::ServerArch(Type type) : type_(type) {}
|
|
|
|
ServerArch::~ServerArch() {}
|
|
|
|
std::string ServerArch::CdcServerFilename() const {
|
|
switch (type_) {
|
|
case Type::kWindows:
|
|
return "cdc_rsync_server.exe";
|
|
case Type::kLinux:
|
|
return "cdc_rsync_server";
|
|
default:
|
|
assert(!kErrorArchTypeUnhandled);
|
|
return std::string();
|
|
}
|
|
}
|
|
|
|
std::string ServerArch::RemoteToolsBinDir() const {
|
|
switch (type_) {
|
|
case Type::kWindows: {
|
|
return "AppData\\Roaming\\cdc-file-transfer\\bin\\";
|
|
}
|
|
case Type::kLinux:
|
|
return ".cache/cdc-file-transfer/bin/";
|
|
default:
|
|
assert(!kErrorArchTypeUnhandled);
|
|
return std::string();
|
|
}
|
|
}
|
|
|
|
std::string ServerArch::GetStartServerCommand(int exit_code_not_found,
|
|
const std::string& args) const {
|
|
std::string server_path = RemoteToolsBinDir() + CdcServerFilename();
|
|
|
|
switch (type_) {
|
|
case Type::kWindows:
|
|
// TODO(ljusten): On Windows, ssh does not seem to forward the Powershell
|
|
// exit code (exit_code_not_found) to the process. However, that's really
|
|
// a minor issue and means we display "Deploying server..." instead of
|
|
// "Server not deployed. Deploying...";
|
|
return RemoteUtil::QuoteForWindows(
|
|
absl::StrFormat("powershell -Command \" "
|
|
"Set-StrictMode -Version 2; "
|
|
"$ErrorActionPreference = 'Stop'; "
|
|
"if (-not (Test-Path -Path '%s')) { "
|
|
" exit %i; "
|
|
"} "
|
|
"%s %s "
|
|
"\"",
|
|
server_path, exit_code_not_found, server_path, args));
|
|
case Type::kLinux:
|
|
return absl::StrFormat("if [ ! -f %s ]; then exit %i; fi; %s %s",
|
|
server_path, exit_code_not_found, server_path,
|
|
args);
|
|
default:
|
|
assert(!kErrorArchTypeUnhandled);
|
|
return std::string();
|
|
}
|
|
}
|
|
|
|
std::string ServerArch::GetDeploySftpCommands() const {
|
|
std::string commands;
|
|
|
|
// Create the remote tools bin dir if it doesn't exist yet.
|
|
// This assumes that sftp's remote startup directory is the home directory.
|
|
const std::string server_dir = path::ToUnix(RemoteToolsBinDir());
|
|
std::vector<std::string> dir_parts =
|
|
absl::StrSplit(server_dir, '/', absl::SkipEmpty());
|
|
for (const std::string& dir : dir_parts) {
|
|
// Use -mkdir to ignore errors if the directory already exists.
|
|
commands += absl::StrFormat("-mkdir %s\ncd %s\n", dir, dir);
|
|
}
|
|
|
|
// Copy the server binary to a temp location. This assumes that sftp's local
|
|
// startup directory is cdc_rsync's exe dir.
|
|
const std::string server_file = CdcServerFilename();
|
|
const std::string server_temp_file = server_file + Util::GenerateUniqueId();
|
|
commands += absl::StrFormat("put %s %s\n", server_file, server_temp_file);
|
|
|
|
// Restore permissions in case they changed and propagate temp file.
|
|
commands += absl::StrFormat("-chmod 755 %s\n", server_file);
|
|
commands += absl::StrFormat("chmod 755 %s\n", server_temp_file);
|
|
commands += absl::StrFormat("rename %s %s\n", server_temp_file, server_file);
|
|
|
|
return commands;
|
|
}
|
|
|
|
} // namespace cdc_ft
|