mirror of
https://github.com/upa/mscp.git
synced 2026-03-02 05:04:41 +08:00
Compare commits
2 Commits
main
...
16d3b5b772
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16d3b5b772 | ||
|
|
27646fc71d |
@@ -1 +0,0 @@
|
|||||||
build
|
|
||||||
28
.github/workflows/release.yml
vendored
28
.github/workflows/release.yml
vendored
@@ -10,6 +10,34 @@ env:
|
|||||||
BUILD_TYPE: Release
|
BUILD_TYPE: Release
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
build-and-release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
|
||||||
|
- name: apply the patch to libssh
|
||||||
|
run: |
|
||||||
|
git -C libssh fetch --all --tags --prune
|
||||||
|
patch -d libssh -p1 < patch/$(git -C libssh describe).patch
|
||||||
|
|
||||||
|
# TODO: just building docker does not require packages. fix CMakeLists
|
||||||
|
- name: install build dependency
|
||||||
|
run: sudo ./scripts/install-build-deps.sh
|
||||||
|
|
||||||
|
- name: Configure Cmake
|
||||||
|
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
|
- name: Build single binary mscp
|
||||||
|
run: make -C ${{github.workspace}}/build build-single-binary
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
${{github.workspace}}/build/mscp.linux.x86_64.static
|
||||||
|
|
||||||
source-release:
|
source-release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
- rocky-8.9
|
- rocky-8.9
|
||||||
- rocky-9.3
|
- rocky-9.3
|
||||||
- almalinux-9.3
|
- almalinux-9.3
|
||||||
- alpine-3.22
|
- alpine-3.19
|
||||||
- arch-base
|
- arch-base
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,5 @@ html
|
|||||||
compile_commands.json
|
compile_commands.json
|
||||||
CMakeUserPresets.json
|
CMakeUserPresets.json
|
||||||
.*.swp
|
.*.swp
|
||||||
.cache
|
|
||||||
|
|
||||||
include/mscp_version.h
|
include/mscp_version.h
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ enable_testing()
|
|||||||
#
|
#
|
||||||
# When edit DIST_IDS and DIST_VERS, also edit .github/workflows/test.yaml
|
# When edit DIST_IDS and DIST_VERS, also edit .github/workflows/test.yaml
|
||||||
list(APPEND DIST_IDS ubuntu ubuntu ubuntu rocky rocky almalinux alpine arch)
|
list(APPEND DIST_IDS ubuntu ubuntu ubuntu rocky rocky almalinux alpine arch)
|
||||||
list(APPEND DIST_VERS 20.04 22.04 24.04 8.9 9.3 9.3 3.22 base)
|
list(APPEND DIST_VERS 20.04 22.04 24.04 8.9 9.3 9.3 3.19 base)
|
||||||
|
|
||||||
list(LENGTH DIST_IDS _DIST_LISTLEN)
|
list(LENGTH DIST_IDS _DIST_LISTLEN)
|
||||||
math(EXPR DIST_LISTLEN "${_DIST_LISTLEN} - 1")
|
math(EXPR DIST_LISTLEN "${_DIST_LISTLEN} - 1")
|
||||||
@@ -208,16 +208,6 @@ foreach(x RANGE ${DIST_LISTLEN})
|
|||||||
--add-host=ip6-localhost:::1
|
--add-host=ip6-localhost:::1
|
||||||
${DOCKER_IMAGE} /mscp/scripts/test-in-container.sh)
|
${DOCKER_IMAGE} /mscp/scripts/test-in-container.sh)
|
||||||
|
|
||||||
add_custom_target(docker-run-${DOCKER_INDEX}
|
|
||||||
COMMENT "Start ${DOCKER_IMAGE} container"
|
|
||||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
|
||||||
COMMAND
|
|
||||||
${CE} run --init --rm --privileged
|
|
||||||
--sysctl net.ipv6.conf.all.disable_ipv6=0
|
|
||||||
--add-host=ip6-localhost:::1
|
|
||||||
-it
|
|
||||||
${DOCKER_IMAGE} /mscp/scripts/test-in-container.sh bash)
|
|
||||||
|
|
||||||
list(APPEND DOCKER_BUILDS docker-build-${DOCKER_INDEX})
|
list(APPEND DOCKER_BUILDS docker-build-${DOCKER_INDEX})
|
||||||
list(APPEND DOCKER_BUILDS_NO_CACHE docker-build-${DOCKER_INDEX}-no-cache)
|
list(APPEND DOCKER_BUILDS_NO_CACHE docker-build-${DOCKER_INDEX}-no-cache)
|
||||||
list(APPEND DOCKER_TESTS docker-test-${DOCKER_INDEX})
|
list(APPEND DOCKER_TESTS docker-test-${DOCKER_INDEX})
|
||||||
@@ -288,9 +278,9 @@ add_custom_target(build-single-binary
|
|||||||
COMMENT "Build mscp as a single binary in alpine conatiner"
|
COMMENT "Build mscp as a single binary in alpine conatiner"
|
||||||
WORKING_DIRECTORY ${mscp_SOURCE_DIR}
|
WORKING_DIRECTORY ${mscp_SOURCE_DIR}
|
||||||
BYPRODUCTS ${CMAKE_BINARY_DIR}/${SINGLEBINARYFILE}
|
BYPRODUCTS ${CMAKE_BINARY_DIR}/${SINGLEBINARYFILE}
|
||||||
DEPENDS docker-build-alpine-3.22
|
DEPENDS docker-build-alpine-3.19
|
||||||
COMMAND
|
COMMAND
|
||||||
${CE} run --rm -v ${CMAKE_BINARY_DIR}:/out mscp-alpine:3.22
|
${CE} run --rm -v ${CMAKE_BINARY_DIR}:/out mscp-alpine:3.19
|
||||||
cp /mscp/build/mscp /out/${SINGLEBINARYFILE})
|
cp /mscp/build/mscp /out/${SINGLEBINARYFILE})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.22
|
FROM alpine:3.19
|
||||||
|
|
||||||
# do not use REQUIREDPKGS build argument because
|
# do not use REQUIREDPKGS build argument because
|
||||||
# this Dockerfile compiles mscp with conan,so we do not need
|
# this Dockerfile compiles mscp with conan,so we do not need
|
||||||
@@ -19,10 +19,6 @@ RUN ssh-keygen -A \
|
|||||||
&& ssh-keygen -f /root/.ssh/id_rsa -N "" \
|
&& ssh-keygen -f /root/.ssh/id_rsa -N "" \
|
||||||
&& cat /root/.ssh/id_rsa.pub > /root/.ssh/authorized_keys
|
&& cat /root/.ssh/id_rsa.pub > /root/.ssh/authorized_keys
|
||||||
|
|
||||||
# disable PerSourcePenaltie, which would distrub test:
|
|
||||||
# https://undeadly.org/cgi?action=article;sid=20240607042157
|
|
||||||
RUN echo "PerSourcePenalties=no" > /etc/ssh/sshd_config.d/90-mscp-test.conf
|
|
||||||
|
|
||||||
# create test user
|
# create test user
|
||||||
RUN addgroup -S test \
|
RUN addgroup -S test \
|
||||||
&& adduser -S test -G test \
|
&& adduser -S test -G test \
|
||||||
@@ -61,6 +61,12 @@ sudo dnf copr enable upaaa/mscp
|
|||||||
sudo dnf install mscp
|
sudo dnf install mscp
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- Single binary `mscp` for x86_64 (not optimal performance)
|
||||||
|
```console
|
||||||
|
wget https://github.com/upa/mscp/releases/latest/download/mscp.linux.x86_64.static -O /usr/local/bin/mscp
|
||||||
|
chmod 755 /usr/local/bin/mscp
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
@@ -80,7 +86,7 @@ cd mscp
|
|||||||
|
|
||||||
# prepare patched libssh
|
# prepare patched libssh
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
patch -d libssh -p1 < patch/$(git -C libssh describe).patch
|
patch -d libssh -p1 < patch/$(git --git-dir=./libssh/.git describe).patch
|
||||||
|
|
||||||
# install build dependency
|
# install build dependency
|
||||||
bash ./scripts/install-build-deps.sh
|
bash ./scripts/install-build-deps.sh
|
||||||
|
|||||||
30
debian/changelog
vendored
30
debian/changelog
vendored
@@ -1,32 +1,4 @@
|
|||||||
mscp (0.2.4) UNRELEASED; urgency=medium
|
mscp (0.2.1) UNRELEASED; urgency=medium
|
||||||
|
|
||||||
* fix password auth does not work (issue #36)
|
|
||||||
* add Debian and Devuan to the install dep script (pr #38)
|
|
||||||
* fallback to default terminal size on no tty (pr #39)
|
|
||||||
|
|
||||||
-- Ryo Nakamura <upa@haeena.net> Sat, 08 Nov 2025 19:23:07 +0900
|
|
||||||
|
|
||||||
mscp (0.2.3) unstable; urgency=medium
|
|
||||||
|
|
||||||
* bump libssh version to 0.11.2 (#25)
|
|
||||||
* adopt new AIO read API of libssh
|
|
||||||
* fix path handling when remote dst path has suffix '/' (#24)
|
|
||||||
* fix remote path handling including '~' (partially)
|
|
||||||
* try pubkey auth first to avoid PerSourcePenalties
|
|
||||||
* remove the single-binary version of mscp from release
|
|
||||||
|
|
||||||
-- Ryo Nakamura <upa@haeena.net> Tue, 12 Aug 2025 18:11:47 +0900
|
|
||||||
|
|
||||||
mscp (0.2.2) unstable; urgency=medium
|
|
||||||
|
|
||||||
* bump cmake_minimum_version on libssh (#32)
|
|
||||||
* fix quiet mode (#30)
|
|
||||||
* use openssl@3 on macOS (#29)
|
|
||||||
* add archlinux support (#28)
|
|
||||||
|
|
||||||
-- Ryo Nakamura <upa@haeena.net> Wed, 16 Apr 2025 17:01:17 +0900
|
|
||||||
|
|
||||||
mscp (0.2.1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* fix broken checkpoint files when copying multiple files (#16)
|
* fix broken checkpoint files when copying multiple files (#16)
|
||||||
* fix broken password inputs for resume transfers (#17 and #18)
|
* fix broken password inputs for resume transfers (#17 and #18)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
MSCP
|
MSCP
|
||||||
====
|
====
|
||||||
|
|
||||||
:Date: v0.2.4
|
:Date: v0.2.1
|
||||||
|
|
||||||
NAME
|
NAME
|
||||||
====
|
====
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#define MSCP_DIRECTION_L2R 1 /** Indicates local to remote copy */
|
#define MSCP_DIRECTION_L2R 1 /** Indicates local to remote copy */
|
||||||
#define MSCP_DIRECTION_R2L 2 /** Indicates remote to local copy */
|
#define MSCP_DIRECTION_R2L 2 /** Indicates remote to local copy */
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ index d22178e7..2d6aa0a7 100644
|
|||||||
int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len);
|
int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len);
|
||||||
|
|
||||||
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h
|
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h
|
||||||
index 3bddb019..1d5d7761 100644
|
index 3bddb019..c6b01c1c 100644
|
||||||
--- a/include/libssh/libssh.h
|
--- a/include/libssh/libssh.h
|
||||||
+++ b/include/libssh/libssh.h
|
+++ b/include/libssh/libssh.h
|
||||||
@@ -373,6 +373,7 @@ enum ssh_options_e {
|
@@ -373,6 +373,7 @@ enum ssh_options_e {
|
||||||
@@ -64,7 +64,7 @@ index 3bddb019..1d5d7761 100644
|
|||||||
LIBSSH_API void ssh_buffer_free(ssh_buffer buffer);
|
LIBSSH_API void ssh_buffer_free(ssh_buffer buffer);
|
||||||
#define SSH_BUFFER_FREE(x) \
|
#define SSH_BUFFER_FREE(x) \
|
||||||
do { if ((x) != NULL) { ssh_buffer_free(x); x = NULL; } } while(0)
|
do { if ((x) != NULL) { ssh_buffer_free(x); x = NULL; } } while(0)
|
||||||
@@ -886,6 +889,12 @@ LIBSSH_API void *ssh_buffer_get(ssh_buffer buffer);
|
@@ -886,6 +889,11 @@ LIBSSH_API void *ssh_buffer_get(ssh_buffer buffer);
|
||||||
LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer);
|
LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer);
|
||||||
LIBSSH_API int ssh_session_set_disconnect_message(ssh_session session, const char *message);
|
LIBSSH_API int ssh_session_set_disconnect_message(ssh_session session, const char *message);
|
||||||
|
|
||||||
@@ -72,7 +72,6 @@ index 3bddb019..1d5d7761 100644
|
|||||||
+
|
+
|
||||||
+LIBSSH_API const char **ssh_ciphers(void);
|
+LIBSSH_API const char **ssh_ciphers(void);
|
||||||
+LIBSSH_API const char **ssh_hmacs(void);
|
+LIBSSH_API const char **ssh_hmacs(void);
|
||||||
+LIBSSH_API void ssh_use_openssh_proxy_jumps(int);
|
|
||||||
+
|
+
|
||||||
#ifndef LIBSSH_LEGACY_0_4
|
#ifndef LIBSSH_LEGACY_0_4
|
||||||
#include "libssh/legacy.h"
|
#include "libssh/legacy.h"
|
||||||
@@ -288,7 +287,7 @@ index 2cb64037..51f4c87e 100644
|
|||||||
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
diff --git a/src/misc.c b/src/misc.c
|
diff --git a/src/misc.c b/src/misc.c
|
||||||
index 774211fb..74e57959 100644
|
index 774211fb..ae62ddfe 100644
|
||||||
--- a/src/misc.c
|
--- a/src/misc.c
|
||||||
+++ b/src/misc.c
|
+++ b/src/misc.c
|
||||||
@@ -71,6 +71,8 @@
|
@@ -71,6 +71,8 @@
|
||||||
@@ -343,37 +342,6 @@ index 774211fb..74e57959 100644
|
|||||||
/**
|
/**
|
||||||
* @brief Write the requested number of bytes to a local file.
|
* @brief Write the requested number of bytes to a local file.
|
||||||
*
|
*
|
||||||
@@ -2227,6 +2265,17 @@ ssh_proxyjumps_free(struct ssh_list *proxy_jump_list)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+static bool force_openssh_proxy_jumps;
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ * @breif set use openssh proxy jumps without the OPENSSH_PROXYJUMP env var
|
|
||||||
+ */
|
|
||||||
+void
|
|
||||||
+ssh_use_openssh_proxy_jumps(int v)
|
|
||||||
+{
|
|
||||||
+ force_openssh_proxy_jumps = (v > 0);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
/**
|
|
||||||
* @brief Check if libssh proxy jumps is enabled
|
|
||||||
*
|
|
||||||
@@ -2241,7 +2290,12 @@ ssh_libssh_proxy_jumps(void)
|
|
||||||
{
|
|
||||||
const char *t = getenv("OPENSSH_PROXYJUMP");
|
|
||||||
|
|
||||||
+ if (force_openssh_proxy_jumps)
|
|
||||||
+ return false;
|
|
||||||
+
|
|
||||||
return !(t != NULL && t[0] == '1');
|
|
||||||
}
|
|
||||||
|
|
||||||
+
|
|
||||||
+
|
|
||||||
/** @} */
|
|
||||||
diff --git a/src/options.c b/src/options.c
|
diff --git a/src/options.c b/src/options.c
|
||||||
index 785296dd..a82d4d81 100644
|
index 785296dd..a82d4d81 100644
|
||||||
--- a/src/options.c
|
--- a/src/options.c
|
||||||
|
|||||||
@@ -38,15 +38,6 @@ make -C build install DESTDIR=%{buildroot}
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Sat Nov 08 2025 Ryo Nakamura <upa@haeena.net> - 0.2.4-1
|
|
||||||
- RPM release for v0.2.4
|
|
||||||
|
|
||||||
* Tue Aug 12 2025 Ryo Nakamura <upa@haeena.net> - 0.2.3-1
|
|
||||||
- RPM release for v0.2.3
|
|
||||||
|
|
||||||
* Wed Apr 16 2025 Ryo Nakamura <upa@haeena.net> - 0.2.2-1
|
|
||||||
- RPM release for v0.2.2
|
|
||||||
|
|
||||||
* Sat May 11 2024 Ryo Nakamura <upa@haeena.net> - 0.2.1-1
|
* Sat May 11 2024 Ryo Nakamura <upa@haeena.net> - 0.2.1-1
|
||||||
- RPM release for v0.2.1
|
- RPM release for v0.2.1
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ case $platform in
|
|||||||
cmd="brew install"
|
cmd="brew install"
|
||||||
pkgs="openssl@3"
|
pkgs="openssl@3"
|
||||||
;;
|
;;
|
||||||
Linux-ubuntu* | Linux-debian* | Linux-devuan*)
|
Linux-ubuntu*)
|
||||||
cmd="apt-get install --no-install-recommends -y"
|
cmd="apt-get install --no-install-recommends -y"
|
||||||
pkgs="gcc make cmake zlib1g-dev libssl-dev libkrb5-dev"
|
pkgs="gcc make cmake zlib1g-dev libssl-dev libkrb5-dev"
|
||||||
;;
|
;;
|
||||||
|
|||||||
@@ -28,11 +28,5 @@ for port in 22 8022; do
|
|||||||
ssh-keyscan -p $port ::1 >> ${HOME}/.ssh/known_hosts
|
ssh-keyscan -p $port ::1 >> ${HOME}/.ssh/known_hosts
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Run test
|
||||||
if [ $# -gt 0 ]; then
|
python3 -m pytest -v ../test
|
||||||
# command arguments are passed, exec them
|
|
||||||
"$@"
|
|
||||||
else
|
|
||||||
# no arguments passed, run the test
|
|
||||||
python3 -m pytest -v ../test
|
|
||||||
fi
|
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ int bwlimit_init(struct bwlimit *bw, uint64_t bps, uint64_t win)
|
|||||||
#define timespeccmp(a, b, expr) \
|
#define timespeccmp(a, b, expr) \
|
||||||
((a.tv_sec * 1000000000 + a.tv_nsec) expr(b.tv_sec * 1000000000 + b.tv_nsec))
|
((a.tv_sec * 1000000000 + a.tv_nsec) expr(b.tv_sec * 1000000000 + b.tv_nsec))
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
int bwlimit_wait(struct bwlimit *bw, size_t nr_bytes)
|
int bwlimit_wait(struct bwlimit *bw, size_t nr_bytes)
|
||||||
{
|
{
|
||||||
struct timespec now, end, rq, rm;
|
struct timespec now, end, rq, rm;
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
|
|
||||||
struct bwlimit {
|
struct bwlimit {
|
||||||
sem_t *sem; /* semaphore */
|
sem_t *sem; /* semaphore */
|
||||||
size_t bps; /* limit bit-rate (bps) */
|
uint64_t bps; /* limit bit-rate (bps) */
|
||||||
size_t win; /* window size (msec) */
|
uint64_t win; /* window size (msec) */
|
||||||
size_t amt; /* amount of bytes can be sent in a window */
|
size_t amt; /* amount of bytes can be sent in a window */
|
||||||
|
|
||||||
ssize_t credit; /* remaining bytes can be sent in a window */
|
ssize_t credit; /* remaining bytes can be sent in a window */
|
||||||
struct timespec wstart, wend; /* window start time and end time */
|
struct timespec wstart, wend; /* window start time and end time */
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ MDIR *mscp_opendir_wrapped(const char *path)
|
|||||||
|
|
||||||
void mscp_closedir(MDIR *md)
|
void mscp_closedir(MDIR *md)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
if (md->remote)
|
if (md->remote)
|
||||||
sftp_closedir(md->remote);
|
sftp_closedir(md->remote);
|
||||||
else
|
else
|
||||||
|
|||||||
52
src/main.c
52
src/main.c
@@ -117,6 +117,8 @@ char *split_user_host_path(const char *s, char **userp, char **hostp, char **pat
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user = NULL;
|
||||||
|
host = NULL;
|
||||||
path = tmp;
|
path = tmp;
|
||||||
for (cp = tmp; *cp; cp++) {
|
for (cp = tmp; *cp; cp++) {
|
||||||
if (*cp == '@' && (cp > tmp) && *(cp - 1) != '\\' && user == NULL) {
|
if (*cp == '@' && (cp > tmp) && *(cp - 1) != '\\' && user == NULL) {
|
||||||
@@ -203,12 +205,13 @@ struct target *validate_targets(char **arg, int len)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct target *t, *t0;
|
struct target *t, *t0;
|
||||||
int n, nslash;
|
int n;
|
||||||
|
|
||||||
if ((t = calloc(len, sizeof(struct target))) == NULL) {
|
if ((t = calloc(len, sizeof(struct target))) == NULL) {
|
||||||
pr_err("calloc: %s", strerrno());
|
pr_err("calloc: %s", strerrno());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
memset(t, 0, len * sizeof(struct target));
|
||||||
|
|
||||||
/* split remote:path into remote and path */
|
/* split remote:path into remote and path */
|
||||||
for (n = 0; n < len; n++) {
|
for (n = 0; n < len; n++) {
|
||||||
@@ -220,33 +223,9 @@ struct target *validate_targets(char **arg, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* expand remote path, e.g., empty dst path and '~' */
|
/* check all user@host are identical. t[len - 1] is destination,
|
||||||
for (n = 0; n < len; n++) {
|
* so we need to check t[0] to t[len - 2] having the identical
|
||||||
if (!t[n].host)
|
* remote notation */
|
||||||
continue;
|
|
||||||
|
|
||||||
/* this target is a remote path. check the path and
|
|
||||||
* expand it. this part is derived from
|
|
||||||
* openssh-portal prepare_remote_path() function.
|
|
||||||
*/
|
|
||||||
char *path = t[n].path;
|
|
||||||
if (*path == '\0' || strcmp(path, "~") == 0)
|
|
||||||
t[n].path = strdup(".");
|
|
||||||
else if (strncmp(path, "~/", 2) == 0) {
|
|
||||||
if ((nslash = strspn(path + 2, "/")) == strlen(path + 2))
|
|
||||||
t[n].path = strdup(".");
|
|
||||||
else
|
|
||||||
t[n].path = strdup(path + 2 + nslash);
|
|
||||||
}
|
|
||||||
if (!t[n].path) {
|
|
||||||
pr_err("strdup failed: %s", strerrno());
|
|
||||||
goto free_target_out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check all user@host are identical. t[len - 1] is the
|
|
||||||
* destination, so we need to check t[0] to t[len - 2] having
|
|
||||||
* the identical remote notation */
|
|
||||||
t0 = &t[0];
|
t0 = &t[0];
|
||||||
for (n = 1; n < len - 1; n++) {
|
for (n = 1; n < len - 1; n++) {
|
||||||
if (compare_remote(t0, &t[n]) != 0)
|
if (compare_remote(t0, &t[n]) != 0)
|
||||||
@@ -306,7 +285,7 @@ long atol_with_unit(char *value, bool i)
|
|||||||
{
|
{
|
||||||
/* value must be "\d+[kKmMgG]?" */
|
/* value must be "\d+[kKmMgG]?" */
|
||||||
|
|
||||||
char *u = value + (strlen(value) - 1);
|
char *u = value + (strlen(optarg) - 1);
|
||||||
long k = i ? 1024 : 1000;
|
long k = i ? 1024 : 1000;
|
||||||
long factor = 1;
|
long factor = 1;
|
||||||
long v;
|
long v;
|
||||||
@@ -356,6 +335,7 @@ int main(int argc, char **argv)
|
|||||||
struct mscp_ssh_opts s;
|
struct mscp_ssh_opts s;
|
||||||
struct mscp_opts o;
|
struct mscp_opts o;
|
||||||
struct target *t;
|
struct target *t;
|
||||||
|
int pipe_fd[2];
|
||||||
int ch, n, i, ret;
|
int ch, n, i, ret;
|
||||||
int direction = 0;
|
int direction = 0;
|
||||||
char *remote = NULL, *checkpoint_save = NULL, *checkpoint_load = NULL;
|
char *remote = NULL, *checkpoint_save = NULL, *checkpoint_load = NULL;
|
||||||
@@ -693,13 +673,8 @@ void print_progress_bar(double percent, char *suffix)
|
|||||||
|
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
|
|
||||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0 || ws.ws_col == 0) {
|
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0)
|
||||||
|
return; /* XXX */
|
||||||
// fallback to default
|
|
||||||
ws.ws_col = 80;
|
|
||||||
ws.ws_row = 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
bar_width = min(sizeof(buf), ws.ws_col) - strlen(suffix) - 7;
|
bar_width = min(sizeof(buf), ws.ws_col) - strlen(suffix) - 7;
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@@ -777,6 +752,8 @@ struct xfer_stat x;
|
|||||||
void print_stat(bool final)
|
void print_stat(bool final)
|
||||||
{
|
{
|
||||||
struct mscp_stats s;
|
struct mscp_stats s;
|
||||||
|
char buf[8192];
|
||||||
|
int timeout;
|
||||||
|
|
||||||
gettimeofday(&x.after, NULL);
|
gettimeofday(&x.after, NULL);
|
||||||
if (calculate_timedelta(&x.before, &x.after) > 1 || final) {
|
if (calculate_timedelta(&x.before, &x.after) > 1 || final) {
|
||||||
@@ -792,6 +769,9 @@ void print_stat(bool final)
|
|||||||
|
|
||||||
void *print_stat_thread(void *arg)
|
void *print_stat_thread(void *arg)
|
||||||
{
|
{
|
||||||
|
struct mscp_stats s;
|
||||||
|
char buf[8192];
|
||||||
|
|
||||||
memset(&x, 0, sizeof(x));
|
memset(&x, 0, sizeof(x));
|
||||||
gettimeofday(&x.start, NULL);
|
gettimeofday(&x.start, NULL);
|
||||||
x.before = x.start;
|
x.before = x.start;
|
||||||
|
|||||||
26
src/mscp.c
26
src/mscp.c
@@ -78,7 +78,7 @@ struct mscp {
|
|||||||
|
|
||||||
static int expand_coremask(const char *coremask, int **cores, int *nr_cores)
|
static int expand_coremask(const char *coremask, int **cores, int *nr_cores)
|
||||||
{
|
{
|
||||||
int n, *core_list, nr_usable, nr_all;
|
int n, *core_list, core_list_len = 0, nr_usable, nr_all;
|
||||||
char c[2] = { 'x', '\0' };
|
char c[2] = { 'x', '\0' };
|
||||||
const char *_coremask;
|
const char *_coremask;
|
||||||
long v, needle;
|
long v, needle;
|
||||||
@@ -273,13 +273,7 @@ struct mscp *mscp_init(struct mscp_opts *o, struct mscp_ssh_opts *s)
|
|||||||
priv_set_errv("bwlimit_init: %s", strerrno());
|
priv_set_errv("bwlimit_init: %s", strerrno());
|
||||||
goto free_out;
|
goto free_out;
|
||||||
}
|
}
|
||||||
|
pr_notice("bitrate limit: %lu bps", o->bitrate);
|
||||||
/* workaround: set libssh using openssh proxyjump
|
|
||||||
* https://gitlab.com/libssh/libssh-mirror/-/issues/319 */
|
|
||||||
ssh_use_openssh_proxy_jumps(1);
|
|
||||||
|
|
||||||
/* call ssh_init() because libssh is statically linked */
|
|
||||||
ssh_init();
|
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
|
|
||||||
@@ -328,12 +322,10 @@ int mscp_set_dst_path(struct mscp *m, const char *dst_path)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!non_null_string(dst_path)) {
|
if (!non_null_string(dst_path))
|
||||||
priv_set_errv("empty dst path");
|
strncpy(m->dst_path, ".", 1);
|
||||||
return -1;
|
else
|
||||||
}
|
strncpy(m->dst_path, dst_path, PATH_MAX);
|
||||||
|
|
||||||
strncpy(m->dst_path, dst_path, PATH_MAX);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -401,9 +393,6 @@ void *mscp_scan_thread(void *arg)
|
|||||||
if (pool_size(m->src_pool) > 1)
|
if (pool_size(m->src_pool) > 1)
|
||||||
a.dst_path_should_dir = true;
|
a.dst_path_should_dir = true;
|
||||||
|
|
||||||
if (m->dst_path[strlen(m->dst_path) - 1] == '/')
|
|
||||||
a.dst_path_should_dir = true;
|
|
||||||
|
|
||||||
if (mscp_stat(m->dst_path, &ds, dst_sftp) == 0) {
|
if (mscp_stat(m->dst_path, &ds, dst_sftp) == 0) {
|
||||||
if (S_ISDIR(ds.st_mode))
|
if (S_ISDIR(ds.st_mode))
|
||||||
a.dst_path_is_dir = true;
|
a.dst_path_is_dir = true;
|
||||||
@@ -562,9 +551,6 @@ int mscp_start(struct mscp *m)
|
|||||||
m->opts->nr_threads = n;
|
m->opts->nr_threads = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_notice("threads: %d",m->opts->nr_threads);
|
|
||||||
pr_notice("bwlimit: %ld bps", m->bw.bps);
|
|
||||||
|
|
||||||
for (n = 0; n < m->opts->nr_threads; n++) {
|
for (n = 0; n < m->opts->nr_threads; n++) {
|
||||||
t = mscp_copy_thread_spawn(m, n);
|
t = mscp_copy_thread_spawn(m, n);
|
||||||
if (!t)
|
if (!t)
|
||||||
|
|||||||
53
src/path.c
53
src/path.c
@@ -410,45 +410,46 @@ static int copy_chunk_l2r(struct chunk *c, int fd, sftp_file sf, int nr_ahead, i
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int copy_chunk_r2l(struct chunk *c, sftp_file sf, int fd,
|
static int copy_chunk_r2l(struct chunk *c, sftp_file sf, int fd, int nr_ahead, int buf_sz,
|
||||||
int nr_ahead, int buf_sz,
|
struct bwlimit *bw, size_t *counter)
|
||||||
struct bwlimit *bw, size_t *counter)
|
|
||||||
{
|
{
|
||||||
ssize_t read_bytes, write_bytes, remain, thrown, len, requested;
|
ssize_t read_bytes, write_bytes, remaind, thrown;
|
||||||
sftp_aio reqs[nr_ahead];
|
|
||||||
char buf[buf_sz];
|
char buf[buf_sz];
|
||||||
int i;
|
int idx;
|
||||||
|
struct {
|
||||||
|
int id;
|
||||||
|
ssize_t len;
|
||||||
|
} reqs[nr_ahead];
|
||||||
|
|
||||||
if (c->len == 0)
|
if (c->len == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
remain = thrown = c->len;
|
remaind = thrown = c->len;
|
||||||
|
|
||||||
for (i = 0; i < nr_ahead && thrown > 0; i++) {
|
for (idx = 0; idx < nr_ahead && thrown > 0; idx++) {
|
||||||
len = min(thrown, sizeof(buf));
|
reqs[idx].len = min(thrown, sizeof(buf));
|
||||||
requested = sftp_aio_begin_read(sf, len, &reqs[i]);
|
reqs[idx].id = sftp_async_read_begin(sf, reqs[idx].len);
|
||||||
if (requested == SSH_ERROR) {
|
if (reqs[idx].id < 0) {
|
||||||
priv_set_errv("sftp_aio_begin_read: %d",
|
priv_set_errv("sftp_async_read_begin: %d",
|
||||||
sftp_get_error(sf->sftp));
|
sftp_get_error(sf->sftp));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
thrown -= requested;
|
thrown -= reqs[idx].len;
|
||||||
bwlimit_wait(bw, requested);
|
bwlimit_wait(bw, reqs[idx].len);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; remain > 0; i = (i + 1) % nr_ahead) {
|
for (idx = 0; remaind > 0; idx = (idx + 1) % nr_ahead) {
|
||||||
read_bytes = sftp_aio_wait_read(&reqs[i], buf, sizeof(buf));
|
read_bytes = sftp_async_read(sf, buf, reqs[idx].len, reqs[idx].id);
|
||||||
if (read_bytes == SSH_ERROR) {
|
if (read_bytes == SSH_ERROR) {
|
||||||
priv_set_errv("sftp_aio_wait_read: %d",
|
priv_set_errv("sftp_async_read: %d", sftp_get_error(sf->sftp));
|
||||||
sftp_get_error(sf->sftp));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thrown > 0) {
|
if (thrown > 0) {
|
||||||
len = min(thrown, sizeof(buf));
|
reqs[idx].len = min(thrown, sizeof(buf));
|
||||||
requested = sftp_aio_begin_read(sf, len, &reqs[i]);
|
reqs[idx].id = sftp_async_read_begin(sf, reqs[idx].len);
|
||||||
thrown -= requested;
|
thrown -= reqs[idx].len;
|
||||||
bwlimit_wait(bw, requested);
|
bwlimit_wait(bw, reqs[idx].len);
|
||||||
}
|
}
|
||||||
|
|
||||||
write_bytes = write(fd, buf, read_bytes);
|
write_bytes = write(fd, buf, read_bytes);
|
||||||
@@ -463,13 +464,13 @@ static int copy_chunk_r2l(struct chunk *c, sftp_file sf, int fd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
*counter += write_bytes;
|
*counter += write_bytes;
|
||||||
remain -= write_bytes;
|
remaind -= read_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remain < 0) {
|
if (remaind < 0) {
|
||||||
priv_set_errv("invalid remain bytes %ld. last async_read bytes %ld. "
|
priv_set_errv("invalid remaind bytes %ld. last async_read bytes %ld. "
|
||||||
"last write bytes %ld",
|
"last write bytes %ld",
|
||||||
remain, read_bytes, write_bytes);
|
remaind, read_bytes, write_bytes);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ void set_print_severity(int serverity)
|
|||||||
{
|
{
|
||||||
if (serverity < 0)
|
if (serverity < 0)
|
||||||
__print_severity = -1; /* no print */
|
__print_severity = -1; /* no print */
|
||||||
else
|
__print_severity = serverity;
|
||||||
__print_severity = serverity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_print_severity()
|
int get_print_severity()
|
||||||
|
|||||||
28
src/ssh.c
28
src/ssh.c
@@ -114,25 +114,27 @@ static int ssh_set_opts(ssh_session ssh, struct mscp_ssh_opts *opts)
|
|||||||
|
|
||||||
static int ssh_authenticate(ssh_session ssh, struct mscp_ssh_opts *opts)
|
static int ssh_authenticate(ssh_session ssh, struct mscp_ssh_opts *opts)
|
||||||
{
|
{
|
||||||
static int auth_bit_mask;
|
int auth_bit_mask;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (auth_bit_mask == 0) {
|
/* none method */
|
||||||
/* the first authentication attempt. try none auth to
|
ret = ssh_userauth_none(ssh, NULL);
|
||||||
* get available auth methods. */
|
if (ret == SSH_AUTH_SUCCESS)
|
||||||
if (ssh_userauth_none(ssh, NULL) == SSH_AUTH_SUCCESS)
|
return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* save auth_bit_mask for further authentications */
|
auth_bit_mask = ssh_userauth_list(ssh, NULL);
|
||||||
auth_bit_mask = ssh_userauth_list(ssh, NULL);
|
if (auth_bit_mask & SSH_AUTH_METHOD_NONE &&
|
||||||
}
|
ssh_userauth_none(ssh, NULL) == SSH_AUTH_SUCCESS)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
auth_bit_mask = ssh_userauth_list(ssh, NULL);
|
||||||
if (auth_bit_mask & SSH_AUTH_METHOD_PUBLICKEY) {
|
if (auth_bit_mask & SSH_AUTH_METHOD_PUBLICKEY) {
|
||||||
char *p = opts->passphrase ? opts->passphrase : NULL;
|
char *p = opts->passphrase ? opts->passphrase : NULL;
|
||||||
if (ssh_userauth_publickey_auto(ssh, NULL, p) == SSH_AUTH_SUCCESS)
|
if (ssh_userauth_publickey_auto(ssh, NULL, p) == SSH_AUTH_SUCCESS)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auth_bit_mask = ssh_userauth_list(ssh, NULL);
|
||||||
if (auth_bit_mask & SSH_AUTH_METHOD_PASSWORD) {
|
if (auth_bit_mask & SSH_AUTH_METHOD_PASSWORD) {
|
||||||
if (!opts->password) {
|
if (!opts->password) {
|
||||||
char buf[128] = {};
|
char buf[128] = {};
|
||||||
|
|||||||
222
test/test_e2e.py
222
test/test_e2e.py
@@ -9,7 +9,6 @@ import getpass
|
|||||||
import datetime
|
import datetime
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from subprocess import check_call, CalledProcessError
|
from subprocess import check_call, CalledProcessError
|
||||||
@@ -32,45 +31,6 @@ def run2ng(args, env = None, timeout = None, quiet = False):
|
|||||||
check_call(cmd, env = env)
|
check_call(cmd, env = env)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
|
||||||
def cleanup_files():
|
|
||||||
"""
|
|
||||||
Cleanup files having the following `prefixes` or matching `paths`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
yield
|
|
||||||
|
|
||||||
prefixes = [
|
|
||||||
"src", "dst",
|
|
||||||
"non_existent_dstdir",
|
|
||||||
]
|
|
||||||
paths = [
|
|
||||||
"/mscp-test-src", "/tmp/mscp-test-src",
|
|
||||||
"{}/src".format(os.environ["HOME"]),
|
|
||||||
"{}/dst".format(os.environ["HOME"]),
|
|
||||||
"/tmp/mscp_test_ssh_config",
|
|
||||||
"/home/test/dst",
|
|
||||||
"/home/test/src",
|
|
||||||
"checkpoint",
|
|
||||||
]
|
|
||||||
|
|
||||||
def remove(path):
|
|
||||||
print(f"cleanup remove: {fname}")
|
|
||||||
if os.path.isdir(path):
|
|
||||||
shutil.rmtree(path)
|
|
||||||
else:
|
|
||||||
os.remove(path)
|
|
||||||
|
|
||||||
for fname in os.listdir(os.getcwd()):
|
|
||||||
for prefix in prefixes:
|
|
||||||
if fname.startswith(prefix):
|
|
||||||
remove(fname)
|
|
||||||
break
|
|
||||||
|
|
||||||
for path in paths:
|
|
||||||
if os.path.exists(path):
|
|
||||||
remove(path)
|
|
||||||
|
|
||||||
|
|
||||||
""" usage test """
|
""" usage test """
|
||||||
|
|
||||||
@@ -112,7 +72,8 @@ def test_single_copy(mscp, src_prefix, dst_prefix, src, dst):
|
|||||||
src.make()
|
src.make()
|
||||||
run2ok([mscp, "-vvv", src_prefix + src.path, dst_prefix + dst.path])
|
run2ok([mscp, "-vvv", src_prefix + src.path, dst_prefix + dst.path])
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
def test_failed_to_copy_nonexistent_file(mscp, src_prefix, dst_prefix):
|
def test_failed_to_copy_nonexistent_file(mscp, src_prefix, dst_prefix):
|
||||||
@@ -133,6 +94,10 @@ def test_double_copy(mscp, src_prefix, dst_prefix, s1, s2, d1, d2):
|
|||||||
run2ok([mscp, "-vvv", src_prefix + s1.path, src_prefix + s2.path, dst_prefix + "dst"])
|
run2ok([mscp, "-vvv", src_prefix + s1.path, src_prefix + s2.path, dst_prefix + "dst"])
|
||||||
assert check_same_md5sum(s1, d1)
|
assert check_same_md5sum(s1, d1)
|
||||||
assert check_same_md5sum(s2, d2)
|
assert check_same_md5sum(s2, d2)
|
||||||
|
s1.cleanup()
|
||||||
|
s2.cleanup()
|
||||||
|
d1.cleanup()
|
||||||
|
d2.cleanup()
|
||||||
|
|
||||||
|
|
||||||
remote_v6_prefix = "[::1]:{}/".format(os.getcwd())
|
remote_v6_prefix = "[::1]:{}/".format(os.getcwd())
|
||||||
@@ -148,6 +113,10 @@ def test_double_copy_with_ipv6_notation(mscp, src_prefix, dst_prefix, s1, s2, d1
|
|||||||
src_prefix + s1.path, src_prefix + s2.path, dst_prefix + "dst"])
|
src_prefix + s1.path, src_prefix + s2.path, dst_prefix + "dst"])
|
||||||
assert check_same_md5sum(s1, d1)
|
assert check_same_md5sum(s1, d1)
|
||||||
assert check_same_md5sum(s2, d2)
|
assert check_same_md5sum(s2, d2)
|
||||||
|
s1.cleanup()
|
||||||
|
s2.cleanup()
|
||||||
|
d1.cleanup()
|
||||||
|
d2.cleanup()
|
||||||
|
|
||||||
|
|
||||||
remote_user_v6_prefix = "{}@[::1]:{}/".format(getpass.getuser(), os.getcwd())
|
remote_user_v6_prefix = "{}@[::1]:{}/".format(getpass.getuser(), os.getcwd())
|
||||||
@@ -164,6 +133,11 @@ def test_double_copy_with_user_and_ipv6_notation(mscp, src_prefix, dst_prefix,
|
|||||||
src_prefix + s1.path, src_prefix + s2.path, dst_prefix + "dst"])
|
src_prefix + s1.path, src_prefix + s2.path, dst_prefix + "dst"])
|
||||||
assert check_same_md5sum(s1, d1)
|
assert check_same_md5sum(s1, d1)
|
||||||
assert check_same_md5sum(s2, d2)
|
assert check_same_md5sum(s2, d2)
|
||||||
|
s1.cleanup()
|
||||||
|
s2.cleanup()
|
||||||
|
d1.cleanup()
|
||||||
|
d2.cleanup()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
param_dir_copy = [
|
param_dir_copy = [
|
||||||
@@ -203,6 +177,10 @@ def test_dir_copy(mscp, src_prefix, dst_prefix, src_dir, dst_dir, src, dst, twic
|
|||||||
for sf, df in zip(src, twice):
|
for sf, df in zip(src, twice):
|
||||||
assert check_same_md5sum(sf, df)
|
assert check_same_md5sum(sf, df)
|
||||||
|
|
||||||
|
for sf, df, tf in zip(src, dst, twice):
|
||||||
|
sf.cleanup()
|
||||||
|
df.cleanup()
|
||||||
|
tf.cleanup()
|
||||||
|
|
||||||
|
|
||||||
param_dir_copy_single = [
|
param_dir_copy_single = [
|
||||||
@@ -218,7 +196,8 @@ def test_dir_copy_single(mscp, src_prefix, dst_prefix, src_dir, dst_dir, src, ds
|
|||||||
os.mkdir(dst_dir)
|
os.mkdir(dst_dir)
|
||||||
run2ok([mscp, "-vvv", src_prefix + src_dir, dst_prefix + dst_dir])
|
run2ok([mscp, "-vvv", src_prefix + src_dir, dst_prefix + dst_dir])
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
def test_override_single_file(mscp, src_prefix, dst_prefix):
|
def test_override_single_file(mscp, src_prefix, dst_prefix):
|
||||||
@@ -229,6 +208,8 @@ def test_override_single_file(mscp, src_prefix, dst_prefix):
|
|||||||
run2ok([mscp, "-vvv", src_prefix + src.path, dst_prefix + dst.path])
|
run2ok([mscp, "-vvv", src_prefix + src.path, dst_prefix + dst.path])
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
absolute_remote_prefix = "localhost:"
|
absolute_remote_prefix = "localhost:"
|
||||||
param_absolute_remote_prefix = [
|
param_absolute_remote_prefix = [
|
||||||
@@ -242,55 +223,8 @@ def test_copy_file_under_root_to_dir(mscp, src_prefix, dst_prefix):
|
|||||||
run2ok([mscp, "-vvv", src_prefix + src.path,
|
run2ok([mscp, "-vvv", src_prefix + src.path,
|
||||||
dst_prefix + os.path.dirname(dst.path)])
|
dst_prefix + os.path.dirname(dst.path)])
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup(preserve_dir = True)
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
|
||||||
def test_dst_has_suffix_slash(mscp, src_prefix, dst_prefix):
|
|
||||||
"""
|
|
||||||
if dst path has suffix '/' like "dir/" and does not exist,
|
|
||||||
mscp should create dir/ and put dir/src-file-name.
|
|
||||||
"""
|
|
||||||
dstdir = "non_existent_dstdir/"
|
|
||||||
|
|
||||||
src = File("src", size = 1024 * 1024).make()
|
|
||||||
dst = File(f"{dstdir}/src")
|
|
||||||
|
|
||||||
run2ok([mscp, "-vvv", src_prefix + src.path,
|
|
||||||
dst_prefix + dstdir])
|
|
||||||
|
|
||||||
assert check_same_md5sum(src, dst)
|
|
||||||
|
|
||||||
|
|
||||||
param_tilde_paths = [
|
|
||||||
("src", "localhost:~/dst"),
|
|
||||||
("localhost:~/src", "dst"),
|
|
||||||
]
|
|
||||||
@pytest.mark.parametrize("src_path, dst_path", param_tilde_paths)
|
|
||||||
def test_remote_path_contains_tilde(mscp, src_path, dst_path):
|
|
||||||
"""
|
|
||||||
if remote path contains '~' as prefix, it should be expanded as '.'.
|
|
||||||
Note that `~user` notation is not supported yet.
|
|
||||||
"""
|
|
||||||
def extract_and_expand(path):
|
|
||||||
path = path if not ':' in path else path[path.index(':')+1:]
|
|
||||||
return path.replace('~', os.environ["HOME"])
|
|
||||||
|
|
||||||
src_f_path = extract_and_expand(src_path)
|
|
||||||
dst_f_path = extract_and_expand(dst_path)
|
|
||||||
|
|
||||||
src = File(src_f_path, size = 1024 * 1024).make()
|
|
||||||
dst = File(dst_f_path)
|
|
||||||
|
|
||||||
run2ok([mscp, "-vvv", src_path, dst_path])
|
|
||||||
assert check_same_md5sum(src, dst)
|
|
||||||
|
|
||||||
|
|
||||||
def test_remote_path_contains_tilde2(mscp):
|
|
||||||
src = File("src", size = 1024 * 1024).make()
|
|
||||||
dst = File(f"{os.environ['HOME']}/src")
|
|
||||||
|
|
||||||
run2ok([mscp, "-vvv", src.path, f"localhost:~"])
|
|
||||||
assert check_same_md5sum(src, dst)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
@@ -301,6 +235,9 @@ def test_min_chunk(mscp, src_prefix, dst_prefix):
|
|||||||
run2ok([mscp, "-vvv", "-s", 32768, src_prefix + src.path, dst_prefix + dst.path])
|
run2ok([mscp, "-vvv", "-s", 32768, src_prefix + src.path, dst_prefix + dst.path])
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
|
|
||||||
def is_alpine():
|
def is_alpine():
|
||||||
if os.path.exists("/etc/os-release"):
|
if os.path.exists("/etc/os-release"):
|
||||||
@@ -335,7 +272,8 @@ def test_glob_src_path(mscp, src_prefix, dst_prefix,
|
|||||||
run2ok([mscp, "-vvv", src_prefix + src_glob_path, dst_prefix + dst_path])
|
run2ok([mscp, "-vvv", src_prefix + src_glob_path, dst_prefix + dst_path])
|
||||||
for src, dst in zip(srcs, dsts):
|
for src, dst in zip(srcs, dsts):
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
def test_thread_affinity(mscp, src_prefix, dst_prefix):
|
def test_thread_affinity(mscp, src_prefix, dst_prefix):
|
||||||
@@ -346,6 +284,8 @@ def test_thread_affinity(mscp, src_prefix, dst_prefix):
|
|||||||
src_prefix + src.path, dst_prefix + dst.path])
|
src_prefix + src.path, dst_prefix + dst.path])
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
def test_cannot_override_file_with_dir(mscp, src_prefix, dst_prefix):
|
def test_cannot_override_file_with_dir(mscp, src_prefix, dst_prefix):
|
||||||
@@ -354,6 +294,8 @@ def test_cannot_override_file_with_dir(mscp, src_prefix, dst_prefix):
|
|||||||
|
|
||||||
run2ng([mscp, "-vvv", src_prefix + src.path, dst_prefix + "dst/src"])
|
run2ng([mscp, "-vvv", src_prefix + src.path, dst_prefix + "dst/src"])
|
||||||
|
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
def test_transfer_zero_bytes(mscp, src_prefix, dst_prefix):
|
def test_transfer_zero_bytes(mscp, src_prefix, dst_prefix):
|
||||||
@@ -361,6 +303,8 @@ def test_transfer_zero_bytes(mscp, src_prefix, dst_prefix):
|
|||||||
dst = File("dst")
|
dst = File("dst")
|
||||||
run2ok([mscp, "-vvv", src_prefix + src.path, dst_prefix + "dst"])
|
run2ok([mscp, "-vvv", src_prefix + src.path, dst_prefix + "dst"])
|
||||||
assert os.path.exists("dst")
|
assert os.path.exists("dst")
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
def test_override_dst_having_larger_size(mscp, src_prefix, dst_prefix):
|
def test_override_dst_having_larger_size(mscp, src_prefix, dst_prefix):
|
||||||
@@ -368,6 +312,8 @@ def test_override_dst_having_larger_size(mscp, src_prefix, dst_prefix):
|
|||||||
dst = File("dst", size = 1024 * 1024 * 2).make()
|
dst = File("dst", size = 1024 * 1024 * 2).make()
|
||||||
run2ok([mscp, "-vvv", src_prefix + src.path, dst_prefix + "dst"])
|
run2ok([mscp, "-vvv", src_prefix + src.path, dst_prefix + "dst"])
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
def test_dont_truncate_dst(mscp, src_prefix, dst_prefix):
|
def test_dont_truncate_dst(mscp, src_prefix, dst_prefix):
|
||||||
@@ -376,7 +322,7 @@ def test_dont_truncate_dst(mscp, src_prefix, dst_prefix):
|
|||||||
run2ok([mscp, "-vvv", src_prefix + f.path, dst_prefix + f.path])
|
run2ok([mscp, "-vvv", src_prefix + f.path, dst_prefix + f.path])
|
||||||
md5_after = f.md5sum()
|
md5_after = f.md5sum()
|
||||||
assert md5_before == md5_after
|
assert md5_before == md5_after
|
||||||
|
f.cleanup()
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
def test_copy_readonly_file(mscp, src_prefix, dst_prefix):
|
def test_copy_readonly_file(mscp, src_prefix, dst_prefix):
|
||||||
@@ -390,6 +336,8 @@ def test_copy_readonly_file(mscp, src_prefix, dst_prefix):
|
|||||||
dst = File("dst")
|
dst = File("dst")
|
||||||
run2ok([mscp, "-vvv", src_prefix + src.path, dst_prefix + dst.path])
|
run2ok([mscp, "-vvv", src_prefix + src.path, dst_prefix + dst.path])
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
def test_dont_make_conns_more_than_chunks(mscp, src_prefix, dst_prefix):
|
def test_dont_make_conns_more_than_chunks(mscp, src_prefix, dst_prefix):
|
||||||
@@ -406,7 +354,8 @@ def test_dont_make_conns_more_than_chunks(mscp, src_prefix, dst_prefix):
|
|||||||
end = time.time()
|
end = time.time()
|
||||||
for s, d in zip(srcs, dsts):
|
for s, d in zip(srcs, dsts):
|
||||||
assert check_same_md5sum(s, d)
|
assert check_same_md5sum(s, d)
|
||||||
|
shutil.rmtree("src")
|
||||||
|
shutil.rmtree("dst")
|
||||||
assert((end - start) < 10)
|
assert((end - start) < 10)
|
||||||
|
|
||||||
|
|
||||||
@@ -420,6 +369,8 @@ def test_bwlimit(mscp, src_prefix, dst_prefix):
|
|||||||
run2ok([mscp, "-vvv", "-L", "100m", src_prefix + "src", dst_prefix + "dst"])
|
run2ok([mscp, "-vvv", "-L", "100m", src_prefix + "src", dst_prefix + "dst"])
|
||||||
end = datetime.datetime.now().timestamp()
|
end = datetime.datetime.now().timestamp()
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
assert end - start > 7
|
assert end - start > 7
|
||||||
|
|
||||||
|
|
||||||
@@ -428,13 +379,14 @@ def test_bwlimit(mscp, src_prefix, dst_prefix):
|
|||||||
def test_set_port_ng(mscp, src_prefix, dst_prefix, src, dst):
|
def test_set_port_ng(mscp, src_prefix, dst_prefix, src, dst):
|
||||||
src.make()
|
src.make()
|
||||||
run2ng([mscp, "-vvv", "-P", 21, src_prefix + src.path, dst_prefix + dst.path])
|
run2ng([mscp, "-vvv", "-P", 21, src_prefix + src.path, dst_prefix + dst.path])
|
||||||
|
src.cleanup()
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
@pytest.mark.parametrize("src, dst", param_single_copy)
|
@pytest.mark.parametrize("src, dst", param_single_copy)
|
||||||
def test_set_port_ok(mscp, src_prefix, dst_prefix, src, dst):
|
def test_set_port_ok(mscp, src_prefix, dst_prefix, src, dst):
|
||||||
src.make()
|
src.make()
|
||||||
run2ok([mscp, "-vvv", "-P", 8022, src_prefix + src.path, dst_prefix + dst.path])
|
run2ok([mscp, "-vvv", "-P", 8022, src_prefix + src.path, dst_prefix + dst.path])
|
||||||
|
src.cleanup()
|
||||||
|
|
||||||
def test_v4only(mscp):
|
def test_v4only(mscp):
|
||||||
src = File("src", size = 1024).make()
|
src = File("src", size = 1024).make()
|
||||||
@@ -442,6 +394,8 @@ def test_v4only(mscp):
|
|||||||
dst_prefix = "localhost:{}/".format(os.getcwd())
|
dst_prefix = "localhost:{}/".format(os.getcwd())
|
||||||
run2ok([mscp, "-vvv", "-4", src.path, dst_prefix + dst.path])
|
run2ok([mscp, "-vvv", "-4", src.path, dst_prefix + dst.path])
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
def test_v6only(mscp):
|
def test_v6only(mscp):
|
||||||
src = File("src", size = 1024).make()
|
src = File("src", size = 1024).make()
|
||||||
@@ -449,18 +403,22 @@ def test_v6only(mscp):
|
|||||||
dst_prefix = "ip6-localhost:{}/".format(os.getcwd())
|
dst_prefix = "ip6-localhost:{}/".format(os.getcwd())
|
||||||
run2ok([mscp, "-vvv", "-6", src.path, dst_prefix + dst.path])
|
run2ok([mscp, "-vvv", "-6", src.path, dst_prefix + dst.path])
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
def test_v4_to_v6_should_fail(mscp):
|
def test_v4_to_v6_should_fail(mscp):
|
||||||
src = File("src", size = 1024).make()
|
src = File("src", size = 1024).make()
|
||||||
dst = File("dst")
|
dst = File("dst")
|
||||||
dst_prefix = "[::1]:{}/".format(os.getcwd())
|
dst_prefix = "[::1]:{}/".format(os.getcwd())
|
||||||
run2ng([mscp, "-vvv", "-4", src.path, dst_prefix + dst.path])
|
run2ng([mscp, "-vvv", "-4", src.path, dst_prefix + dst.path])
|
||||||
|
src.cleanup()
|
||||||
|
|
||||||
def test_v6_to_v4_should_fail(mscp):
|
def test_v6_to_v4_should_fail(mscp):
|
||||||
src = File("src", size = 1024).make()
|
src = File("src", size = 1024).make()
|
||||||
dst = File("dst")
|
dst = File("dst")
|
||||||
dst_prefix = "127.0.0.1:{}/".format(os.getcwd())
|
dst_prefix = "127.0.0.1:{}/".format(os.getcwd())
|
||||||
run2ng([mscp, "-vvv", "-6", src.path, dst_prefix + dst.path])
|
run2ng([mscp, "-vvv", "-6", src.path, dst_prefix + dst.path])
|
||||||
|
src.cleanup()
|
||||||
|
|
||||||
def test_quiet_mode(capsys, mscp):
|
def test_quiet_mode(capsys, mscp):
|
||||||
src = File("src", size = 1024).make()
|
src = File("src", size = 1024).make()
|
||||||
@@ -468,7 +426,8 @@ def test_quiet_mode(capsys, mscp):
|
|||||||
dst_prefix = "127.0.0.1:{}/".format(os.getcwd())
|
dst_prefix = "127.0.0.1:{}/".format(os.getcwd())
|
||||||
run2ok([mscp, "-vvv", "-q", src.path, dst_prefix + dst.path], quiet=True)
|
run2ok([mscp, "-vvv", "-q", src.path, dst_prefix + dst.path], quiet=True)
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
assert not captured.out
|
assert not captured.out
|
||||||
assert not captured.err
|
assert not captured.err
|
||||||
@@ -484,6 +443,8 @@ def test_set_conn_interval(mscp, src_prefix, dst_prefix):
|
|||||||
|
|
||||||
for src, dst in zip(srcs, dsts):
|
for src, dst in zip(srcs, dsts):
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
compressions = ["yes", "no", "none"]
|
compressions = ["yes", "no", "none"]
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
@@ -493,6 +454,8 @@ def test_compression(mscp, src_prefix, dst_prefix, compress):
|
|||||||
dst = File("dst", size = 1024 * 1024 * 2).make()
|
dst = File("dst", size = 1024 * 1024 * 2).make()
|
||||||
run2ok([mscp, "-vvv", "-C", compress, src_prefix + src.path, dst_prefix + "dst"])
|
run2ok([mscp, "-vvv", "-C", compress, src_prefix + src.path, dst_prefix + "dst"])
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
def test_ccalgo(mscp, src_prefix, dst_prefix):
|
def test_ccalgo(mscp, src_prefix, dst_prefix):
|
||||||
@@ -529,7 +492,8 @@ def test_config_ok(mscp, src_prefix, dst_prefix):
|
|||||||
|
|
||||||
os.remove(config)
|
os.remove(config)
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_testhost_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_testhost_prefix)
|
||||||
def test_config_ng(mscp, src_prefix, dst_prefix):
|
def test_config_ng(mscp, src_prefix, dst_prefix):
|
||||||
@@ -543,6 +507,8 @@ def test_config_ng(mscp, src_prefix, dst_prefix):
|
|||||||
src_prefix + src.path, dst_prefix + "dst"])
|
src_prefix + src.path, dst_prefix + "dst"])
|
||||||
|
|
||||||
os.remove(config)
|
os.remove(config)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
|
|
||||||
param_valid_option_ok = [
|
param_valid_option_ok = [
|
||||||
@@ -559,6 +525,8 @@ def test_inline_option_ok(mscp, src_prefix, dst_prefix, option):
|
|||||||
run2ok([mscp, "-vvv"] + option +
|
run2ok([mscp, "-vvv"] + option +
|
||||||
[src_prefix + src.path, dst_prefix + dst.path])
|
[src_prefix + src.path, dst_prefix + dst.path])
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
|
|
||||||
param_valid_option_ng = [
|
param_valid_option_ng = [
|
||||||
@@ -573,6 +541,7 @@ def test_inline_option_ng(mscp, src_prefix, dst_prefix, option):
|
|||||||
dst = File("dst")
|
dst = File("dst")
|
||||||
run2ng([mscp, "-vvv"] + option +
|
run2ng([mscp, "-vvv"] + option +
|
||||||
[src_prefix + src.path, dst_prefix + dst.path])
|
[src_prefix + src.path, dst_prefix + dst.path])
|
||||||
|
src.cleanup()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
@@ -585,6 +554,8 @@ def test_porxyjump_ok(mscp, src_prefix, dst_prefix):
|
|||||||
"-J", "localhost:8022",
|
"-J", "localhost:8022",
|
||||||
src_prefix + src.path, dst_prefix + dst.path])
|
src_prefix + src.path, dst_prefix + dst.path])
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
@@ -596,6 +567,7 @@ def test_porxyjump_ng(mscp, src_prefix, dst_prefix):
|
|||||||
run2ng([mscp, "-n", 4, "-s", 1024 * 1024, "-vvv",
|
run2ng([mscp, "-n", 4, "-s", 1024 * 1024, "-vvv",
|
||||||
"-J", "invaliduser@localhost:8022",
|
"-J", "invaliduser@localhost:8022",
|
||||||
src_prefix + src.path, dst_prefix + dst.path])
|
src_prefix + src.path, dst_prefix + dst.path])
|
||||||
|
src.cleanup()
|
||||||
|
|
||||||
# username test assumes that this test runs inside a container, see Dockerfiles
|
# username test assumes that this test runs inside a container, see Dockerfiles
|
||||||
def test_specify_passphrase_via_env(mscp):
|
def test_specify_passphrase_via_env(mscp):
|
||||||
@@ -606,6 +578,8 @@ def test_specify_passphrase_via_env(mscp):
|
|||||||
run2ok([mscp, "-vvv", "-l", "test", "-i", "/home/test/.ssh/id_rsa_test",
|
run2ok([mscp, "-vvv", "-l", "test", "-i", "/home/test/.ssh/id_rsa_test",
|
||||||
src.path, "localhost:" + dst.path], env = env)
|
src.path, "localhost:" + dst.path], env = env)
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
def test_specify_invalid_passphrase_via_env(mscp):
|
def test_specify_invalid_passphrase_via_env(mscp):
|
||||||
src = File(os.getcwd() + "/src", size = 1024).make()
|
src = File(os.getcwd() + "/src", size = 1024).make()
|
||||||
@@ -614,6 +588,7 @@ def test_specify_invalid_passphrase_via_env(mscp):
|
|||||||
env["MSCP_SSH_AUTH_PASSPHRASE"] = "invalid-keypassphrase"
|
env["MSCP_SSH_AUTH_PASSPHRASE"] = "invalid-keypassphrase"
|
||||||
run2ng([mscp, "-vvv", "-l", "test", "-i", "/home/test/.ssh/id_rsa_test",
|
run2ng([mscp, "-vvv", "-l", "test", "-i", "/home/test/.ssh/id_rsa_test",
|
||||||
src.path, "localhost:" + dst.path], env = env)
|
src.path, "localhost:" + dst.path], env = env)
|
||||||
|
src.cleanup()
|
||||||
|
|
||||||
def test_specify_password_via_env(mscp):
|
def test_specify_password_via_env(mscp):
|
||||||
src = File(os.getcwd() + "/src", size = 1024).make()
|
src = File(os.getcwd() + "/src", size = 1024).make()
|
||||||
@@ -623,6 +598,8 @@ def test_specify_password_via_env(mscp):
|
|||||||
run2ok([mscp, "-vvv", "-l", "test",
|
run2ok([mscp, "-vvv", "-l", "test",
|
||||||
src.path, "localhost:" + dst.path], env = env)
|
src.path, "localhost:" + dst.path], env = env)
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
def test_specify_invalid_password_via_env(mscp):
|
def test_specify_invalid_password_via_env(mscp):
|
||||||
src = File(os.getcwd() + "/src", size = 1024).make()
|
src = File(os.getcwd() + "/src", size = 1024).make()
|
||||||
@@ -631,44 +608,7 @@ def test_specify_invalid_password_via_env(mscp):
|
|||||||
env["MSCP_SSH_AUTH_PASSWORD"] = "invalid-userpassword"
|
env["MSCP_SSH_AUTH_PASSWORD"] = "invalid-userpassword"
|
||||||
run2ng([mscp, "-vvv", "-l", "test",
|
run2ng([mscp, "-vvv", "-l", "test",
|
||||||
src.path, "localhost:" + dst.path], env = env)
|
src.path, "localhost:" + dst.path], env = env)
|
||||||
|
src.cleanup()
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def move_pubkey_temporally():
|
|
||||||
"""
|
|
||||||
mv ~/.ssh/id_* to id_rsa.bak before test, and move it back after test.
|
|
||||||
"""
|
|
||||||
|
|
||||||
sshdir = os.path.join(os.environ["HOME"], ".ssh")
|
|
||||||
|
|
||||||
# move pubkeys to /tmp
|
|
||||||
moved = []
|
|
||||||
for fname in os.listdir(sshdir):
|
|
||||||
if re.match(r"^id_[a-z0-9]+$", fname):
|
|
||||||
moved.append(fname)
|
|
||||||
shutil.move(f"{sshdir}/{fname}", f"/tmp/{fname}")
|
|
||||||
|
|
||||||
yield
|
|
||||||
|
|
||||||
# move back the keys
|
|
||||||
for fname in moved:
|
|
||||||
shutil.move(f"/tmp/{fname}", f"{sshdir}/{fname}")
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
|
||||||
def test_passwordauth_without_pubkey(move_pubkey_temporally,
|
|
||||||
mscp, src_prefix, dst_prefix):
|
|
||||||
"""
|
|
||||||
make sure password auth works (by removing public keys)
|
|
||||||
"""
|
|
||||||
src = File(os.getcwd() + "/src", size = 1024).make()
|
|
||||||
dst = File("/home/test/dst")
|
|
||||||
env = os.environ
|
|
||||||
env["MSCP_SSH_AUTH_PASSWORD"] = "userpassword"
|
|
||||||
run2ok([mscp, "-vvv", "-l", "test",
|
|
||||||
src.path, "localhost:" + dst.path], env = env)
|
|
||||||
assert check_same_md5sum(src, dst)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
def test_10k_files(mscp, src_prefix, dst_prefix):
|
def test_10k_files(mscp, src_prefix, dst_prefix):
|
||||||
@@ -680,6 +620,8 @@ def test_10k_files(mscp, src_prefix, dst_prefix):
|
|||||||
run2ok([mscp, "-v", src_prefix + "src", dst_prefix + "dst"])
|
run2ok([mscp, "-v", src_prefix + "src", dst_prefix + "dst"])
|
||||||
for s, d in zip(srcs, dsts):
|
for s, d in zip(srcs, dsts):
|
||||||
assert check_same_md5sum(s, d)
|
assert check_same_md5sum(s, d)
|
||||||
|
shutil.rmtree("src")
|
||||||
|
shutil.rmtree("dst")
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||||
def test_checkpoint_dump_and_resume(mscp, src_prefix, dst_prefix):
|
def test_checkpoint_dump_and_resume(mscp, src_prefix, dst_prefix):
|
||||||
@@ -694,6 +636,10 @@ def test_checkpoint_dump_and_resume(mscp, src_prefix, dst_prefix):
|
|||||||
run2ok([mscp, "-vvv", "-R", "checkpoint"])
|
run2ok([mscp, "-vvv", "-R", "checkpoint"])
|
||||||
assert check_same_md5sum(src1, dst1)
|
assert check_same_md5sum(src1, dst1)
|
||||||
assert check_same_md5sum(src2, dst2)
|
assert check_same_md5sum(src2, dst2)
|
||||||
|
src1.cleanup()
|
||||||
|
src2.cleanup()
|
||||||
|
dst1.cleanup()
|
||||||
|
dst2.cleanup()
|
||||||
os.remove("checkpoint")
|
os.remove("checkpoint")
|
||||||
|
|
||||||
@pytest.mark.parametrize("timeout", [ 1, 2, 3, 4, 5 ])
|
@pytest.mark.parametrize("timeout", [ 1, 2, 3, 4, 5 ])
|
||||||
@@ -712,6 +658,10 @@ def test_checkpoint_interrupt_large_file(mscp, timeout, src_prefix, dst_prefix):
|
|||||||
run2ok([mscp, "-vv", "-R", "checkpoint"])
|
run2ok([mscp, "-vv", "-R", "checkpoint"])
|
||||||
assert check_same_md5sum(src1, dst1)
|
assert check_same_md5sum(src1, dst1)
|
||||||
assert check_same_md5sum(src2, dst2)
|
assert check_same_md5sum(src2, dst2)
|
||||||
|
src1.cleanup()
|
||||||
|
src2.cleanup()
|
||||||
|
dst1.cleanup()
|
||||||
|
dst2.cleanup()
|
||||||
os.remove("checkpoint")
|
os.remove("checkpoint")
|
||||||
|
|
||||||
@pytest.mark.parametrize("timeout", [ 1, 2, 3, 4, 5 ])
|
@pytest.mark.parametrize("timeout", [ 1, 2, 3, 4, 5 ])
|
||||||
@@ -737,6 +687,8 @@ def test_checkpoint_interrupt_many_files(mscp, timeout, src_prefix, dst_prefix):
|
|||||||
|
|
||||||
for src, dst in files:
|
for src, dst in files:
|
||||||
assert check_same_md5sum(src, dst)
|
assert check_same_md5sum(src, dst)
|
||||||
|
src.cleanup()
|
||||||
|
dst.cleanup()
|
||||||
|
|
||||||
os.remove("checkpoint")
|
os.remove("checkpoint")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user