mirror of
https://github.com/nestriness/cdc-file-transfer.git
synced 2026-01-30 10:25:37 +02:00
Adds a ServerArch class whose job it is to encapsulate differences between Windows and Linux cdc_rsync_servers. It detects the type based on a heuristic in the destination path. This is not fool proof and will probably require further work, like falling back to the other type if the detected one doesn't work. Uses the ServerArch class to determine the different commands to start the server and to deploy the server. Note that the functionality is not well tested on Windows yet, but copying plain files works.
159 lines
5.3 KiB
C++
159 lines
5.3 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 "common/path.h"
|
|
#include "common/remote_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;
|
|
}
|
|
|
|
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(UseCase use_case) const {
|
|
switch (type_) {
|
|
case Type::kWindows: {
|
|
// TODO(ljusten): Unfortunately, scp doesn't seem to support shell var
|
|
// expansion, so %AppData% can't be used. This relies on scp copying
|
|
// files relative to %UserProfile% and %AppData% mapping to
|
|
// "AppData\\Roaming" relative to that.
|
|
std::string app_data =
|
|
use_case == UseCase::kScp ? "AppData\\Roaming" : "$env:appdata";
|
|
return app_data + "\\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_dir = RemoteToolsBinDir(UseCase::kSsh);
|
|
std::string server_path =
|
|
RemoteUtil::QuoteForSsh(server_dir + CdcServerFilename());
|
|
path::EnsureDoesNotEndWithPathSeparator(&server_dir);
|
|
server_dir = RemoteUtil::QuoteForSsh(server_dir);
|
|
|
|
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("Set-StrictMode -Version 2; "
|
|
"$ErrorActionPreference = 'Stop'; "
|
|
"$server_dir = %s; "
|
|
"$server_path = %s; "
|
|
"$u=New-Item $server_dir -ItemType Directory -Force; "
|
|
"if (-not (Test-Path -Path $server_path)) { "
|
|
" exit %i; "
|
|
"} "
|
|
"& $server_path %s",
|
|
server_dir, server_path, exit_code_not_found, args));
|
|
case Type::kLinux:
|
|
return absl::StrFormat(
|
|
"mkdir -p %s; if [ ! -f %s ]; then exit %i; fi; %s %s", server_dir,
|
|
server_path, exit_code_not_found, server_path, args);
|
|
default:
|
|
assert(!kErrorArchTypeUnhandled);
|
|
return std::string();
|
|
}
|
|
}
|
|
|
|
std::string ServerArch::GetDeployReplaceCommand(
|
|
const std::string& old_server_path,
|
|
const std::string& new_server_path) const {
|
|
const std::string old_path = RemoteUtil::QuoteForSsh(old_server_path);
|
|
const std::string new_path = RemoteUtil::QuoteForSsh(new_server_path);
|
|
|
|
switch (type_) {
|
|
case Type::kWindows:
|
|
return RemoteUtil::QuoteForWindows(absl::StrFormat(
|
|
"Set-StrictMode -Version 2; "
|
|
"$ErrorActionPreference = 'Stop'; "
|
|
"$old_path = %s; "
|
|
"$new_path = %s; "
|
|
"if (Test-Path -Path $old_path) { "
|
|
" Get-Item -Path $old_path | "
|
|
" Set-ItemProperty -Name IsReadOnly -Value $false; "
|
|
"} "
|
|
"Move-Item -Path $new_path -Destination $old_path -Force",
|
|
old_path, new_path));
|
|
case Type::kLinux:
|
|
return absl::StrFormat(
|
|
"([ ! -f %s ] || chmod u+w %s) && chmod a+x %s && mv %s %s", old_path,
|
|
old_path, new_path, new_path, old_path);
|
|
default:
|
|
assert(!kErrorArchTypeUnhandled);
|
|
return std::string();
|
|
}
|
|
}
|
|
|
|
} // namespace cdc_ft
|