From d1a23fc4df1cc047da1e6ab67ab214e20ccdeff8 Mon Sep 17 00:00:00 2001 From: TapTap Date: Thu, 16 Jul 2026 12:28:16 +0200 Subject: [PATCH] quick-wins: ControlMaster, -z alias, --progress, fix write warning - SSH ControlMaster auto with ControlPath for connection reuse - -z as alias for -c (compression) - --progress flag showing transfer rate in send_files - Fixed unused-result warning on write() in transport_ssh.c --- src/client/client_cli.c | 6 +++++- src/client/client_send.c | 23 +++++++++++++++++++++++ src/shared/config.c | 1 + src/shared/config.h | 1 + src/shared/transport_ssh.c | 8 +++++--- 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/client/client_cli.c b/src/client/client_cli.c index d92e452..2965061 100644 --- a/src/client/client_cli.c +++ b/src/client/client_cli.c @@ -21,6 +21,8 @@ static void print_usage(void) { printf("\n"); printf("Options:\n"); printf(" -c [level] Enable compression (level 1-22, default 5)\n"); + printf(" -z [level] Alias for -c\n"); + printf(" --progress Show transfer progress\n"); printf(" -m Enable multithreading\n"); printf(" -s Enable chunk serialization\n"); printf(" -f Enable sendfile (TCP only, not with -c or -s)\n"); @@ -56,7 +58,7 @@ int main(int argc, char *argv[]) { if (strcmp(argv[i], "--help") == 0) { print_usage(); return 0; - } else if (strcmp(argv[i], "-c") == 0) { + } else if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "-z") == 0) { config->use_compression = true; log_message(LOG_LEVEL_INFO, "Enabled Compression"); if (i + 1 < argc) { @@ -94,6 +96,8 @@ int main(int argc, char *argv[]) { server_host = str_dup(argv[++i]); } else if (strcmp(argv[i], "--server-port") == 0 && i + 1 < argc) { server_port = atoi(argv[++i]); + } else if (strcmp(argv[i], "--progress") == 0) { + config->show_progress = true; } else if (strcmp(argv[i], "--chunk-size") == 0 && i + 1 < argc) { unsigned long long val = strtoull(argv[++i], NULL, 10); if (val > 0) diff --git a/src/client/client_send.c b/src/client/client_send.c index 81be93a..8e6a2d3 100644 --- a/src/client/client_send.c +++ b/src/client/client_send.c @@ -15,6 +15,7 @@ #include #include #include +#include int send_chunk(Client *client, Chunk *chunk, Config *config) { if (config->use_chunk_serialization) { @@ -140,16 +141,38 @@ int send_files(Config *config) { config_send(client->file_descriptor, config); DirectoryScanner *scanner = directory_scanner_create(config->send_directory, config->use_metadata, config->chunk_size); Chunk *current_chunk; + unsigned long long total_bytes = 0; + time_t last_progress = 0; + time_t start = time(NULL); while ((current_chunk = directory_scanner_next(scanner)) != NULL) { + unsigned long long chunk_bytes = 0; + for (int i = 0; i < current_chunk->element_count; i++) + chunk_bytes += current_chunk->items[i]->data->size; if (!config->use_sendfile) { for (int i = 0; i < current_chunk->element_count; i++) file_load_data(current_chunk->items[i]); } send_chunk(client, current_chunk, config); + if (config->show_progress) { + total_bytes += chunk_bytes; + time_t now = time(NULL); + if (now - last_progress >= 1) { + last_progress = now; + double elapsed = difftime(now, start); + double rate = elapsed > 0 ? total_bytes / (1048576.0 * elapsed) : 0; + fprintf(stderr, "\rSent %.1f MB (%.1f MB/s) ", total_bytes / 1048576.0, rate); + fflush(stderr); + } + } chunk_destroy(current_chunk); } send_status(client->file_descriptor, STATUS_FINISHED); int ok = receive_status(client->file_descriptor) == STATUS_OK; + if (config->show_progress) { + double elapsed = difftime(time(NULL), start); + double rate = elapsed > 0 ? total_bytes / (1048576.0 * elapsed) : 0; + fprintf(stderr, "\rSent %.1f MB (%.1f MB/s) Done.\n", total_bytes / 1048576.0, rate); + } directory_scanner_destroy(scanner); client_disconnect(client); client_delete(client); diff --git a/src/shared/config.c b/src/shared/config.c index 6880be9..43d40af 100644 --- a/src/shared/config.c +++ b/src/shared/config.c @@ -22,6 +22,7 @@ Config *config_create(char *version, char *send_directory, config->use_chunk_serialization = use_chunk_serialization; config->use_compression = use_compression; config->use_metadata = use_metadata; + config->show_progress = false; config->compression_level = compression_level; config->use_sendfile = use_sendfile; config->chunk_size = chunk_size > 0 ? chunk_size : DEFAULT_CHUNK_SIZE; diff --git a/src/shared/config.h b/src/shared/config.h index eb30002..b2a636a 100644 --- a/src/shared/config.h +++ b/src/shared/config.h @@ -18,6 +18,7 @@ typedef struct Config { bool use_compression; bool use_sendfile; bool use_metadata; + bool show_progress; int compression_level; unsigned long long chunk_size; TransportType transport; diff --git a/src/shared/transport_ssh.c b/src/shared/transport_ssh.c index 7d228b9..6b2b5d1 100644 --- a/src/shared/transport_ssh.c +++ b/src/shared/transport_ssh.c @@ -91,10 +91,12 @@ Client *client_connect_ssh(char *destination) { snprintf(ssh_user, sizeof(ssh_user), "%s", r.host); execlp("ssh", "ssh", "-o", "Compression=no", "-o", - "ControlMaster=no", ssh_user, "fastsync-server", "--stdio", - (char *)NULL); + "ControlMaster=auto", "-o", + "ControlPath=~/.cache/fastsync-%r@%h:%p", ssh_user, + "fastsync-server", "--stdio", (char *)NULL); perror("exec of ssh failed"); - (void)write(exec_pipe[1], "x", 1); + ssize_t wret = write(exec_pipe[1], "x", 1); + (void)wret; _exit(1); } -- 2.52.0