diff --git a/src/client/client_send.c b/src/client/client_send.c index e883cf7..900a150 100644 --- a/src/client/client_send.c +++ b/src/client/client_send.c @@ -537,6 +537,17 @@ static int load_files_multithreaded(void* pipeline_context) { } } +/* Print a one-line transfer progress report to stderr. `suffix` ends the + line (e.g. "Done.\n") or is "" for in-place refresh. Shared by the + single-threaded loop and the multithreaded progress thread. */ +static void print_transfer_progress(unsigned long long total_bytes, time_t start, + const char* suffix) { + double elapsed = difftime(time(NULL), start); + double rate = elapsed > 0.0 ? total_bytes / (1048576.0 * elapsed) : 0.0; + fprintf(stderr, "\rSent %.1f MB (%.1f MB/s) %s", total_bytes / 1048576.0, rate, suffix); + fflush(stderr); +} + /* Progress-reporting thread for multithreaded send. Runs in parallel with the scanner/loader/sender threads and prints periodic progress to stderr. */ static int progress_thread_fn(void* arg) { @@ -551,20 +562,14 @@ static int progress_thread_fn(void* arg) { mtx_unlock(&context->mutex_progress); if (done) { - time_t now = time(NULL); - double elapsed = difftime(now, start); - double rate = elapsed > 0.0 ? total / (1048576.0 * elapsed) : 0.0; - fprintf(stderr, "\rSent %.1f MB (%.1f MB/s) Done.\n", total / 1048576.0, rate); + print_transfer_progress(total, start, "Done.\n"); break; } time_t now = time(NULL); if (now - last_progress >= 1) { last_progress = now; - double elapsed = difftime(now, start); - double rate = elapsed > 0.0 ? total / (1048576.0 * elapsed) : 0.0; - fprintf(stderr, "\rSent %.1f MB (%.1f MB/s) ", total / 1048576.0, rate); - fflush(stderr); + print_transfer_progress(total, start, ""); } struct timespec ts = {0, 100 * 1000000L}; /* 100 ms */ @@ -587,29 +592,21 @@ int send_files(Config* config) { protocol_session_init(&session, client->file_descriptor, client->file_descriptor); protocol_session_set_ssl(&session, (SSL*)client->ssl); protocol_session_bind(&session); - if (!config_send(client->file_descriptor, config)) { - disconnect_transfer_client(client); - protocol_session_unbind(); - return 1; - } + int ret = 1; + DirectoryScanner* scanner = NULL; + ArrayList* manifest = NULL; + if (!config_send(client->file_descriptor, config)) + goto send_fail; ScannerOptions scanner_options = scanner_options_from_config(config, 0); - DirectoryScanner* scanner = - directory_scanner_create_with_options(config->send_directory, &scanner_options); + scanner = directory_scanner_create_with_options(config->send_directory, &scanner_options); + manifest = create_transfer_manifest(config); + if (!scanner || (config->use_delete && !manifest)) + goto send_fail; Chunk* current_chunk; unsigned long long total_bytes = 0; int total_files = 0; time_t last_progress = 0; time_t start = time(NULL); - ArrayList* manifest = create_transfer_manifest(config); - if (!scanner || (config->use_delete && !manifest)) { - if (scanner) - directory_scanner_destroy(scanner); - if (manifest) - array_list_delete(manifest); - disconnect_transfer_client(client); - protocol_session_unbind(); - return 1; - } while ((current_chunk = directory_scanner_next(scanner)) != NULL) { unsigned long long chunk_bytes = 0; for (int i = 0; i < current_chunk->element_count; i++) { @@ -621,16 +618,21 @@ int send_files(Config* config) { goto send_fail; } if (!config->use_sendfile) { + bool load_ok = true; for (int i = 0; i < current_chunk->element_count; i++) { File* f = current_chunk->items[i]; if (f->data->size > STREAM_THRESHOLD) continue; if (!file_load_data(f)) { log_message(LOG_LEVEL_ERROR, "Failed to load file data"); - chunk_destroy(current_chunk); - goto send_fail; + load_ok = false; + break; } } + if (!load_ok) { + chunk_destroy(current_chunk); + goto send_fail; + } } if (send_chunk(client, current_chunk, config) != 0) { log_message(LOG_LEVEL_ERROR, "Failed to send chunk"); @@ -645,10 +647,7 @@ int send_files(Config* config) { 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); + print_transfer_progress(total_bytes, start, ""); } } chunk_destroy(current_chunk); @@ -665,28 +664,26 @@ int send_files(Config* config) { manifest = NULL; } bool ok = finalize_transfer(client); - double elapsed_total = difftime(time(NULL), start); - if (config->show_progress) { - double rate = elapsed_total > 0 ? total_bytes / (1048576.0 * elapsed_total) : 0; - fprintf(stderr, "\rSent %.1f MB (%.1f MB/s) Done.\n", total_bytes / 1048576.0, rate); - } + if (config->show_progress) + print_transfer_progress(total_bytes, start, "Done.\n"); if (config->stats) { + double elapsed_total = difftime(time(NULL), start); double rate = elapsed_total > 0 ? total_bytes / (1048576.0 * elapsed_total) : 0; fprintf(stderr, "Stats: %d files, %.1f MB, %.1f MB/s\n", total_files, total_bytes / 1048576.0, rate); } - directory_scanner_destroy(scanner); - disconnect_transfer_client(client); - protocol_session_unbind(); - return ok ? 0 : 1; + ret = ok ? 0 : 1; send_fail: + /* Single cleanup path for all exits. The manifest is intentionally deleted + here even on success without --delete, fixing a pre-existing leak. */ if (manifest) array_list_delete(manifest); - directory_scanner_destroy(scanner); + if (scanner) + directory_scanner_destroy(scanner); disconnect_transfer_client(client); protocol_session_unbind(); - return 1; + return ret; } int send_files_multithreaded(Config* config) {